json-rest-api 1.0.22 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -2
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
- package/README.md +22 -1
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
- package/docs/API.md +196 -38
- package/docs/COMPARISON.md +2 -2
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
- package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
- package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +370 -0
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
- package/docs/GUIDE/index.md +18 -9
- package/docs/QUICKSTART.md +5 -1
- package/docs/index.md +1 -1
- package/index.js +3 -2
- package/lib/enhanced-logger.js +1 -1
- package/package.json +6 -2
- package/plugins/core/bulk-operations-plugin.js +26 -34
- package/plugins/core/connectors/express-plugin.js +97 -190
- package/plugins/core/connectors/fastify-plugin.js +206 -0
- package/plugins/core/connectors/lib/busboy-detector.js +4 -4
- package/plugins/core/connectors/lib/connector-core.js +195 -0
- package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
- package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
- package/plugins/core/lib/anyapi/schema-utils.js +43 -4
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
- package/plugins/core/lib/dbIntrospection.js +1078 -0
- package/plugins/core/lib/dbTablesOperations.js +1111 -160
- package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
- package/plugins/core/lib/querying/knex-process-includes.js +3 -4
- package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
- package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
- package/plugins/core/lib/querying/query-builder-utils.js +19 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
- package/plugins/core/lib/querying/sort-helpers.js +33 -0
- package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
- package/plugins/core/lib/querying/url-helpers.js +8 -2
- package/plugins/core/lib/querying-writing/compile-schemas.js +20 -5
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
- package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
- package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +131 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
- package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
- package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
- package/plugins/core/lib/storage/storage-adapter.js +82 -4
- package/plugins/core/lib/storage/storage-mapping.js +274 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
- package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
- package/plugins/core/rest-api-autofilter-plugin.js +414 -0
- package/plugins/core/rest-api-knex-plugin.js +271 -226
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +1 -0
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
- package/plugins/core/rest-api-plugin-methods/common.js +148 -92
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
- package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get.js +29 -14
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
- package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/post.js +21 -8
- package/plugins/core/rest-api-plugin-methods/put.js +73 -21
- package/plugins/core/rest-api-plugin-methods/query.js +15 -53
- package/plugins/core/rest-api-plugin-methods/release.js +0 -2
- package/plugins/core/rest-api-plugin.js +6 -0
- package/plugins/core/rest-api-positioning-plugin.js +2 -5
- package/plugins/core/rest-api-query-projections-plugin.js +130 -0
- package/plugins/core/socketio-plugin.js +1 -4
- package/plugins/storage/local-storage.js +1 -1
- package/plugins/storage/s3-storage.js +5 -2
- package/quickTest.js +1 -0
- package/scripts/run-docs.js +80 -84
- package/test-debug.js +1 -1
- package/tests/README.md +7 -0
- package/tests/anyapi-basic.test.js +3 -0
- package/tests/autofilter.test.js +463 -0
- package/tests/custom-id-mysql-returning-fallback.test.js +128 -0
- package/tests/custom-id-simplified-post.test.js +75 -0
- package/tests/custom-idproperty-relationships.test.js +33 -0
- package/tests/db-introspection.test.js +521 -0
- package/tests/db-table-operations.test.js +786 -0
- package/tests/fastify-plugin.test.js +156 -0
- package/tests/field-getters.test.js +1 -2
- package/tests/field-setters.test.js +0 -4
- package/tests/fixtures/api-configs.js +278 -176
- package/tests/helpers/fake-fastify.js +99 -0
- package/tests/http-connectors-parity.test.js +235 -0
- package/tests/id-normalization.test.js +444 -0
- package/tests/logical-id-write-validation.test.js +151 -0
- package/tests/pagination-cursor-multifield.test.js +11 -11
- package/tests/projected-fields.test.js +319 -0
- package/tests/relationships.test.js +3 -3
- package/tests/searchschema-knex-behavior.test.js +187 -0
- package/tests/searchschema-merge.test.js +21 -69
- package/tests/storage-mapping.test.js +259 -0
- package/audit/00-charter.md +0 -103
- package/audit/01-scope-map.md +0 -84
- package/audit/02-coverage-matrix.csv +0 -174
- package/audit/03-invariants.md +0 -123
- package/audit/04-standards-rubric.md +0 -56
- package/audit/05-competitor-rubric.md +0 -77
- package/audit/06-findings.md +0 -160
- package/audit/07-risk-register.csv +0 -10
- package/audit/08-remediation-roadmap.md +0 -177
- package/audit/09-signoff-check.md +0 -23
- package/audit/10-final-synthesis.md +0 -29
- package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
- package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
- package/audit/evidence/code/boundary-leak-checks.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
- package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
- package/audit/evidence/code/critical-pass1-summary.csv +0 -67
- package/audit/evidence/code/critical-pass2-summary.csv +0 -67
- package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
- package/audit/evidence/code/error-model-signals.txt +0 -98
- package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
- package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
- package/audit/evidence/code/hook-flow-signals.txt +0 -282
- package/audit/evidence/code/idproperty-signals.txt +0 -157
- package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
- package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
- package/audit/evidence/code/imports-json-rest-api.txt +0 -354
- package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
- package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
- package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
- package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
- package/audit/evidence/code/permission-signals.txt +0 -193
- package/audit/evidence/code/query-include-signals.txt +0 -687
- package/audit/evidence/code/transaction-signals.txt +0 -28
- package/audit/evidence/code/validation-signals.txt +0 -650
- package/audit/evidence/code/write-path-signals.txt +0 -61
- package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
- package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
- package/audit/evidence/external/corpus-freeze.md +0 -21
- package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
- package/audit/evidence/external/npm-download-signals.txt +0 -23
- package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
- package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
- package/audit/evidence/external/readme-fortune-signals.txt +0 -26
- package/audit/evidence/external/readme-fortune.md +0 -165
- package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
- package/audit/evidence/external/readme-json-api-serializer.md +0 -690
- package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
- package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
- package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
- package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
- package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
- package/audit/evidence/external/readme-jsonapi-server.md +0 -104
- package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
- package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
- package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
- package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
- package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
- package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
- package/audit/evidence/external/standards-sources.txt +0 -6
- package/audit/evidence/runtime/baseline-commits.txt +0 -2
- package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
- package/audit/evidence/runtime/environment.txt +0 -4
- package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
- package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
- package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
- package/audit/evidence/runtime/test-exitcodes.txt +0 -4
- package/audit/evidence/runtime/test-summary.md +0 -107
- package/audit/evidence/runtime/trace-anchors.txt +0 -61
- package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
- package/audit/evidence/tests/failing-tests-summary.txt +0 -25
- package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
- package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
- package/audit/evidence/tests/query-include-test-signals.txt +0 -948
- package/audit/evidence/tests/relationship-test-signals.txt +0 -223
- package/audit/evidence/tests/skipped-tests.txt +0 -10
- package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
- package/audit/evidence/tests/test-suite-list.txt +0 -32
- package/audit/subsystems/docs-drift.md +0 -49
- package/audit/subsystems/pass2-cross-review.md +0 -131
- package/audit/subsystems/plugins-access.md +0 -51
- package/audit/subsystems/plugins-bulk.md +0 -50
- package/audit/subsystems/plugins-cors.md +0 -48
- package/audit/subsystems/plugins-file.md +0 -53
- package/audit/subsystems/plugins-multihome.md +0 -50
- package/audit/subsystems/plugins-positioning.md +0 -54
- package/audit/subsystems/plugins-socketio.md +0 -50
- package/audit/subsystems/query-engine.md +0 -61
- package/audit/subsystems/relationships.md +0 -55
- package/audit/subsystems/rest-orchestration.md +0 -66
- package/audit/subsystems/schema-core.md +0 -64
- package/audit/subsystems/storage-knex.md +0 -57
- package/audit/subsystems/tests.md +0 -48
- package/audit/subsystems/transport-express.md +0 -55
- package/audit/traces/trace-read-get.md +0 -22
- package/audit/traces/trace-read-query.md +0 -25
- package/audit/traces/trace-relationship-endpoints.md +0 -31
- package/audit/traces/trace-write-delete.md +0 -17
- package/audit/traces/trace-write-patch.md +0 -26
- package/audit/traces/trace-write-post.md +0 -22
- package/audit/traces/trace-write-put.md +0 -23
- package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
- package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
- package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
- package/plugins/core/rest-api-access.js +0 -459
- package/plugins/core/rest-api-multihome-plugin.js +0 -314
- package/tests/multihome.test.js +0 -553
- package/tests/multihome.test.js.bak +0 -550
- package/tests/ownership-optout.test.js +0 -76
- package/tests/rest-api-access.test.js +0 -206
package/docs/API.md
CHANGED
|
@@ -4,13 +4,17 @@ This reference provides comprehensive documentation for all methods, parameters,
|
|
|
4
4
|
|
|
5
5
|
## Important Notes
|
|
6
6
|
|
|
7
|
-
1. **Context Parameter**: The `context` parameter shown in method signatures is typically managed internally by the framework. When using the API programmatically, you usually don't need to provide it unless you're implementing custom
|
|
7
|
+
1. **Context Parameter**: The `context` parameter shown in method signatures is typically managed internally by the framework. When using the API programmatically, you usually don't need to provide it unless you're implementing custom request identity/auth context or other request-specific data.
|
|
8
8
|
|
|
9
|
-
2. **
|
|
9
|
+
2. **App-Owned Auth Context**: `json-rest-api` does not define authentication semantics. If you use `context.auth` in hooks, treat it as application-owned data supplied by your transport or surrounding stack.
|
|
10
|
+
|
|
11
|
+
3. **Simplified Mode Defaults**:
|
|
10
12
|
- `simplifiedApi`: `true` (default for programmatic API calls)
|
|
11
13
|
- `simplifiedTransport`: `false` (default for HTTP transport)
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
4. **All parameters must be passed within a single params object** as the first argument to each method.
|
|
16
|
+
|
|
17
|
+
5. **Simplified shorthand is payload-only**: when you pass attributes directly (for example, `post({ title: 'Hello' })`), that plain object is treated as the resource payload. If you also need per-call options such as `transaction`, `queryParams`, `simplified`, or `returnFullRecord`, put the record under `inputRecord` and keep those options at the top level of `params`.
|
|
14
18
|
|
|
15
19
|
## Table of Contents
|
|
16
20
|
|
|
@@ -289,6 +293,8 @@ const result = await api.resources.[resourceType].get(params, context)
|
|
|
289
293
|
| `simplified` | Boolean | No | Override simplified mode setting (default: true) |
|
|
290
294
|
| `transaction` | Object | No | Database transaction object |
|
|
291
295
|
|
|
296
|
+
`id` is normalized with the effective `normalizeId` function before validation and lookup. If it normalizes to an empty value, the operation fails as `REST_API_RESOURCE` with subtype `not_found`.
|
|
297
|
+
|
|
292
298
|
#### Return Value
|
|
293
299
|
|
|
294
300
|
**JSON:API Mode (simplified: false):**
|
|
@@ -428,7 +434,9 @@ const result = await api.resources.[resourceType].post(params, context)
|
|
|
428
434
|
| Parameter | Type | Required | Description |
|
|
429
435
|
|-----------|------|----------|-------------|
|
|
430
436
|
| `inputRecord` | Object | Yes | Resource data to create |
|
|
437
|
+
| `inputRecord.id` | String | No (simplified) | Optional explicit logical resource ID |
|
|
431
438
|
| `inputRecord.data` | Object | Yes (JSON:API) | Resource data container |
|
|
439
|
+
| `inputRecord.data.id` | String | No (JSON:API) | Optional explicit logical resource ID |
|
|
432
440
|
| `inputRecord.data.type` | String | Yes (JSON:API) | Resource type |
|
|
433
441
|
| `inputRecord.data.attributes` | Object | Yes (JSON:API) | Resource attributes |
|
|
434
442
|
| `inputRecord.data.relationships` | Object | No | Related resources |
|
|
@@ -437,6 +445,8 @@ const result = await api.resources.[resourceType].post(params, context)
|
|
|
437
445
|
| `transaction` | Object | No | Database transaction object |
|
|
438
446
|
| `returnFullRecord` | String | No | Override return setting ('no', 'minimal', 'full') |
|
|
439
447
|
|
|
448
|
+
When an explicit resource id is provided, `normalizeId` runs before persistence and before any follow-up record fetch used for the return payload. If the normalized id is empty, the request fails as `REST_API_VALIDATION` on `data.id`.
|
|
449
|
+
|
|
440
450
|
#### Return Value Behavior
|
|
441
451
|
|
|
442
452
|
The return value depends on `returnFullRecord` setting and whether it's an API or transport call:
|
|
@@ -513,6 +523,25 @@ const result = await api.resources.articles.post({
|
|
|
513
523
|
});
|
|
514
524
|
```
|
|
515
525
|
|
|
526
|
+
**Create with Explicit ID and Normalization:**
|
|
527
|
+
```javascript
|
|
528
|
+
// With normalizeId configured to trim and uppercase ids,
|
|
529
|
+
// this record is stored as ARTICLE-42
|
|
530
|
+
const result = await api.resources.articles.post({
|
|
531
|
+
inputRecord: {
|
|
532
|
+
data: {
|
|
533
|
+
type: 'articles',
|
|
534
|
+
id: ' article-42 ',
|
|
535
|
+
attributes: {
|
|
536
|
+
title: 'Canonical ID Example',
|
|
537
|
+
content: 'Stored under the normalized id'
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
simplified: false
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
516
545
|
**Create with Multiple Relationships:**
|
|
517
546
|
```javascript
|
|
518
547
|
// Create article with author and tags (simplified)
|
|
@@ -589,8 +618,8 @@ const result = await api.resources.[resourceType].put(params, context)
|
|
|
589
618
|
| Parameter | Type | Required | Description |
|
|
590
619
|
|-----------|------|----------|-------------|
|
|
591
620
|
| `inputRecord` | Object | Yes | Complete resource data |
|
|
592
|
-
| `inputRecord.id` | String | Yes (simplified) |
|
|
593
|
-
| `inputRecord.data.id` | String | Yes (JSON:API) |
|
|
621
|
+
| `inputRecord.id` | String | Yes (simplified) | Logical resource ID |
|
|
622
|
+
| `inputRecord.data.id` | String | Yes (JSON:API) | Logical resource ID |
|
|
594
623
|
| `inputRecord.data.type` | String | Yes (JSON:API) | Resource type |
|
|
595
624
|
| `inputRecord.data.attributes` | Object | Yes (JSON:API) | All resource attributes |
|
|
596
625
|
| `inputRecord.data.relationships` | Object | No | All relationships (missing ones are nulled) |
|
|
@@ -599,6 +628,10 @@ const result = await api.resources.[resourceType].put(params, context)
|
|
|
599
628
|
| `transaction` | Object | No | Database transaction object |
|
|
600
629
|
| `returnFullRecord` | String | No | Override return setting |
|
|
601
630
|
|
|
631
|
+
`inputRecord.id` and `inputRecord.data.id` always refer to the logical resource id. `idProperty` and storage mapping affect the backing column name, not the API field name, and the resource id is not part of `attributes`.
|
|
632
|
+
|
|
633
|
+
If both the URL id and body id are present, both are normalized before the equality check. If either id normalizes to an empty value, the operation fails before storage is touched.
|
|
634
|
+
|
|
602
635
|
#### Return Value
|
|
603
636
|
|
|
604
637
|
Updated resource based on `returnFullRecord` setting (defaults: API='full', transport='no').
|
|
@@ -716,8 +749,8 @@ const result = await api.resources.[resourceType].patch(params, context)
|
|
|
716
749
|
| Parameter | Type | Required | Description |
|
|
717
750
|
|-----------|------|----------|-------------|
|
|
718
751
|
| `inputRecord` | Object | Yes | Partial resource data |
|
|
719
|
-
| `inputRecord.id` | String | Yes (simplified) |
|
|
720
|
-
| `inputRecord.data.id` | String | Yes (JSON:API) |
|
|
752
|
+
| `inputRecord.id` | String | Yes (simplified) | Logical resource ID |
|
|
753
|
+
| `inputRecord.data.id` | String | Yes (JSON:API) | Logical resource ID |
|
|
721
754
|
| `inputRecord.data.type` | String | Yes (JSON:API) | Resource type |
|
|
722
755
|
| `inputRecord.data.attributes` | Object | No | Attributes to update |
|
|
723
756
|
| `inputRecord.data.relationships` | Object | No | Relationships to update |
|
|
@@ -726,6 +759,8 @@ const result = await api.resources.[resourceType].patch(params, context)
|
|
|
726
759
|
| `transaction` | Object | No | Database transaction object |
|
|
727
760
|
| `returnFullRecord` | String | No | Override return setting |
|
|
728
761
|
|
|
762
|
+
If both the URL id and body id are present, both are normalized before the equality check. If either id normalizes to an empty value, the operation fails before storage is touched.
|
|
763
|
+
|
|
729
764
|
#### Return Value
|
|
730
765
|
|
|
731
766
|
Updated resource based on `returnFullRecord` setting (defaults: API='full', transport='no').
|
|
@@ -847,6 +882,8 @@ const result = await api.resources.[resourceType].delete(params, context)
|
|
|
847
882
|
| `id` | String\|Number | Yes | ID of resource to delete |
|
|
848
883
|
| `transaction` | Object | No | Database transaction object |
|
|
849
884
|
|
|
885
|
+
`id` is normalized with the effective `normalizeId` function before validation and lookup. If it normalizes to an empty value, the operation fails as `REST_API_RESOURCE` with subtype `not_found`.
|
|
886
|
+
|
|
850
887
|
#### Return Value
|
|
851
888
|
|
|
852
889
|
Returns `undefined` (204 No Content)
|
|
@@ -933,6 +970,8 @@ const result = await api.resources.[resourceType].getRelated(params, context)
|
|
|
933
970
|
| `queryParams` | Object | No | Standard query parameters for related resources |
|
|
934
971
|
| `transaction` | Object | No | Database transaction object |
|
|
935
972
|
|
|
973
|
+
`id` is normalized with the effective `normalizeId` function before validation and lookup. If it normalizes to an empty value, the operation fails as `REST_API_RESOURCE` with subtype `not_found`.
|
|
974
|
+
|
|
936
975
|
#### Return Value
|
|
937
976
|
|
|
938
977
|
JSON:API response with related resources (supports all query features like filtering, pagination, etc.)
|
|
@@ -1005,6 +1044,8 @@ const result = await api.resources.[resourceType].getRelationship(params, contex
|
|
|
1005
1044
|
}
|
|
1006
1045
|
```
|
|
1007
1046
|
|
|
1047
|
+
`id` is normalized with the effective `normalizeId` function before validation and lookup. If it normalizes to an empty value, the operation fails as `REST_API_RESOURCE` with subtype `not_found`.
|
|
1048
|
+
|
|
1008
1049
|
#### Return Value
|
|
1009
1050
|
|
|
1010
1051
|
JSON:API relationship document with resource identifiers only
|
|
@@ -1079,6 +1120,8 @@ const result = await api.resources.[resourceType].postRelationship(params, conte
|
|
|
1079
1120
|
}
|
|
1080
1121
|
```
|
|
1081
1122
|
|
|
1123
|
+
The parent `id` is normalized with the parent resource's normalizer. Each `relationshipData[*].id` is normalized with the related target resource's normalizer before validation and persistence.
|
|
1124
|
+
|
|
1082
1125
|
#### Return Value
|
|
1083
1126
|
|
|
1084
1127
|
Returns `undefined` (204 No Content)
|
|
@@ -1114,6 +1157,8 @@ await api.resources.articles.postRelationship({
|
|
|
1114
1157
|
// Existing tags remain, new tags are added
|
|
1115
1158
|
```
|
|
1116
1159
|
|
|
1160
|
+
If `normalizeId` is configured, both the parent id and each relationship identifier are normalized before the relationship is written.
|
|
1161
|
+
|
|
1117
1162
|
---
|
|
1118
1163
|
|
|
1119
1164
|
### patchRelationship - Replace Relationship
|
|
@@ -1136,6 +1181,8 @@ const result = await api.resources.[resourceType].patchRelationship(params, cont
|
|
|
1136
1181
|
}
|
|
1137
1182
|
```
|
|
1138
1183
|
|
|
1184
|
+
The parent `id` is normalized with the parent resource's normalizer. Each relationship identifier inside `relationshipData` is normalized with the related target resource's normalizer before validation and persistence.
|
|
1185
|
+
|
|
1139
1186
|
#### Return Value
|
|
1140
1187
|
|
|
1141
1188
|
Returns `undefined` (204 No Content)
|
|
@@ -1217,6 +1264,8 @@ const result = await api.resources.[resourceType].deleteRelationship(params, con
|
|
|
1217
1264
|
}
|
|
1218
1265
|
```
|
|
1219
1266
|
|
|
1267
|
+
The parent `id` is normalized with the parent resource's normalizer. Each `relationshipData[*].id` is normalized with the related target resource's normalizer before validation and persistence.
|
|
1268
|
+
|
|
1220
1269
|
#### Return Value
|
|
1221
1270
|
|
|
1222
1271
|
Returns `undefined` (204 No Content)
|
|
@@ -1400,7 +1449,7 @@ Each API method has its own specific hook execution order. Here's the exact sequ
|
|
|
1400
1449
|
|
|
1401
1450
|
1. **Processing Hooks**: Only POST, PUT, and PATCH have `beforeProcessing` hooks
|
|
1402
1451
|
2. **Schema Validation**: Only POST, PUT, and PATCH have schema validation hooks
|
|
1403
|
-
3. **Permission
|
|
1452
|
+
3. **Permission Hooks**: GET uses `checkDataPermissions`, while relationship methods use `checkPermissions`
|
|
1404
1453
|
4. **Query Filtering**: Only QUERY method triggers `knexQueryFiltering` hooks
|
|
1405
1454
|
5. **Enrichment**: Only GET and QUERY have `enrichRecord` hooks
|
|
1406
1455
|
6. **Relationships**: Only GET has `enrichRecordWithRelationships`
|
|
@@ -1421,7 +1470,7 @@ Each hook receives a context object with different properties based on the hook
|
|
|
1421
1470
|
queryParams: {...},
|
|
1422
1471
|
simplified: true
|
|
1423
1472
|
},
|
|
1424
|
-
auth: {...}, //
|
|
1473
|
+
auth: {...}, // App-provided auth/identity context if present
|
|
1425
1474
|
transaction: {...}, // Database transaction
|
|
1426
1475
|
schemaInfo: {...}, // Resource schema
|
|
1427
1476
|
db: {...} // Database connection
|
|
@@ -1490,7 +1539,7 @@ api.resource('articles').hook('afterSchemaValidate', async (context) => {
|
|
|
1490
1539
|
}
|
|
1491
1540
|
```
|
|
1492
1541
|
|
|
1493
|
-
**Purpose:**
|
|
1542
|
+
**Purpose:** Permission or visibility checks implemented by your app hooks. Throw an error to deny the operation.
|
|
1494
1543
|
|
|
1495
1544
|
**Example:**
|
|
1496
1545
|
```javascript
|
|
@@ -2073,24 +2122,30 @@ api.resource('articles').hook('afterDataQuery', async (context) => {
|
|
|
2073
2122
|
### Plugin Configuration
|
|
2074
2123
|
|
|
2075
2124
|
```javascript
|
|
2076
|
-
|
|
2125
|
+
await api.use(RestApiPlugin, {
|
|
2077
2126
|
// API behavior
|
|
2078
2127
|
simplifiedApi: true, // Use simplified mode for programmatic calls (default: true)
|
|
2079
2128
|
simplifiedTransport: false, // Use JSON:API for HTTP transport (default: false)
|
|
2129
|
+
normalizeId: (value) => {
|
|
2130
|
+
if (value === null || value === undefined) {
|
|
2131
|
+
return null
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
const normalized = String(value).trim()
|
|
2135
|
+
return normalized ? normalized.toUpperCase() : null
|
|
2136
|
+
},
|
|
2080
2137
|
|
|
2081
2138
|
// Return record configuration
|
|
2082
2139
|
returnRecordApi: {
|
|
2083
2140
|
post: 'full', // Return full record after create (default)
|
|
2084
2141
|
put: 'full', // Return full record after replace (default)
|
|
2085
|
-
patch: 'full'
|
|
2086
|
-
delete: 'no' // Return nothing after delete (default)
|
|
2142
|
+
patch: 'full' // Return full record after update (default)
|
|
2087
2143
|
},
|
|
2088
2144
|
|
|
2089
2145
|
returnRecordTransport: {
|
|
2090
2146
|
post: 'no', // Return 204 for HTTP POST (default)
|
|
2091
2147
|
put: 'no', // Return 204 for HTTP PUT (default)
|
|
2092
|
-
patch: 'no'
|
|
2093
|
-
delete: 'no' // Return 204 for HTTP DELETE (default)
|
|
2148
|
+
patch: 'no' // Return 204 for HTTP PATCH (default)
|
|
2094
2149
|
},
|
|
2095
2150
|
|
|
2096
2151
|
// Query limits
|
|
@@ -2101,15 +2156,7 @@ const restApiPlugin = new RestApiPlugin({
|
|
|
2101
2156
|
includeDepthLimit: 3, // Maximum relationship nesting depth
|
|
2102
2157
|
|
|
2103
2158
|
// Performance
|
|
2104
|
-
enablePaginationCounts: true
|
|
2105
|
-
|
|
2106
|
-
// Error handling
|
|
2107
|
-
exposeErrors: false, // Include error details in responses
|
|
2108
|
-
|
|
2109
|
-
// Custom serializers
|
|
2110
|
-
serializers: {
|
|
2111
|
-
articles: customArticleSerializer
|
|
2112
|
-
}
|
|
2159
|
+
enablePaginationCounts: true // Execute count queries for total pages
|
|
2113
2160
|
});
|
|
2114
2161
|
```
|
|
2115
2162
|
|
|
@@ -2124,7 +2171,7 @@ api.addResource({
|
|
|
2124
2171
|
name: 'articles',
|
|
2125
2172
|
|
|
2126
2173
|
// Primary key configuration
|
|
2127
|
-
idProperty: 'id', //
|
|
2174
|
+
idProperty: 'id', // Physical primary-key column name for table-backed resources
|
|
2128
2175
|
|
|
2129
2176
|
schema: {
|
|
2130
2177
|
// Attributes
|
|
@@ -2243,13 +2290,9 @@ api.addResource({
|
|
|
2243
2290
|
}
|
|
2244
2291
|
},
|
|
2245
2292
|
|
|
2246
|
-
//
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
read: ['*'],
|
|
2250
|
-
update: ['author', 'editor', 'admin'],
|
|
2251
|
-
delete: ['admin']
|
|
2252
|
-
},
|
|
2293
|
+
// No built-in permissions option exists here.
|
|
2294
|
+
// Use permission hooks for access decisions, and optional plugins
|
|
2295
|
+
// such as AutoFilterPlugin for dataset scoping.
|
|
2253
2296
|
|
|
2254
2297
|
// Soft delete configuration
|
|
2255
2298
|
softDelete: {
|
|
@@ -2275,19 +2318,95 @@ api.addResource({
|
|
|
2275
2318
|
|
|
2276
2319
|
#### ID Property Configuration
|
|
2277
2320
|
```javascript
|
|
2278
|
-
//
|
|
2321
|
+
// Physical primary key column: user_id
|
|
2279
2322
|
api.addResource({
|
|
2280
2323
|
name: 'users',
|
|
2281
|
-
idProperty: 'user_id',
|
|
2324
|
+
idProperty: 'user_id',
|
|
2282
2325
|
schema: {
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2326
|
+
id: { type: 'id', required: true, storage: { column: 'user_id' } },
|
|
2327
|
+
email: { type: 'string', required: true },
|
|
2328
|
+
displayName: { type: 'string' }
|
|
2329
|
+
}
|
|
2330
|
+
});
|
|
2331
|
+
```
|
|
2332
|
+
|
|
2333
|
+
`idProperty` names the physical primary-key column for table-backed resources. At the API layer, the resource id remains `id`, so writes use `inputRecord.id` or `inputRecord.data.id`, reads return `id` or `data.id`, and the resource id is not part of `attributes`.
|
|
2334
|
+
|
|
2335
|
+
#### Resource ID Normalization
|
|
2336
|
+
|
|
2337
|
+
`normalizeId` canonicalizes resource identifiers before the library reads, writes, validates, or links records.
|
|
2338
|
+
|
|
2339
|
+
The default normalizer:
|
|
2340
|
+
|
|
2341
|
+
- trims surrounding whitespace from strings
|
|
2342
|
+
- converts finite numbers and bigints to strings
|
|
2343
|
+
- rejects values that normalize to an empty identifier
|
|
2344
|
+
|
|
2345
|
+
Provide a custom normalizer when your ids need additional canonicalization:
|
|
2346
|
+
|
|
2347
|
+
```javascript
|
|
2348
|
+
await api.use(RestApiPlugin, {
|
|
2349
|
+
normalizeId: (value) => {
|
|
2350
|
+
if (value === null || value === undefined) {
|
|
2351
|
+
return null
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
const normalized = String(value).trim()
|
|
2355
|
+
return normalized ? normalized.toUpperCase() : null
|
|
2356
|
+
}
|
|
2357
|
+
});
|
|
2358
|
+
```
|
|
2359
|
+
|
|
2360
|
+
Resource-level overrides take precedence over the plugin-level default:
|
|
2361
|
+
|
|
2362
|
+
```javascript
|
|
2363
|
+
await api.addResource('countries', {
|
|
2364
|
+
normalizeId: (value) => {
|
|
2365
|
+
if (value === null || value === undefined) {
|
|
2366
|
+
return null
|
|
2286
2367
|
}
|
|
2368
|
+
|
|
2369
|
+
const normalized = String(value).trim()
|
|
2370
|
+
return normalized ? normalized.toLowerCase() : null
|
|
2371
|
+
},
|
|
2372
|
+
schema: {
|
|
2373
|
+
name: { type: 'string', required: true }
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
```
|
|
2377
|
+
|
|
2378
|
+
Normalization is applied to:
|
|
2379
|
+
|
|
2380
|
+
- parent ids used by `get`, `put`, `patch`, `delete`, `getRelated`, and `getRelationship`
|
|
2381
|
+
- explicit `POST`, `PUT`, and `PATCH` document ids
|
|
2382
|
+
- relationship identifiers used by `postRelationship`, `patchRelationship`, and `deleteRelationship`
|
|
2383
|
+
|
|
2384
|
+
Relationship identifiers use the normalizer of the related target resource, not the parent resource.
|
|
2385
|
+
|
|
2386
|
+
If an id normalizes to an empty value:
|
|
2387
|
+
|
|
2388
|
+
- existing-resource operations fail as `REST_API_RESOURCE` with subtype `not_found`
|
|
2389
|
+
- explicit `POST` document ids fail as `REST_API_VALIDATION` on `data.id`
|
|
2390
|
+
|
|
2391
|
+
#### Storage Column Naming
|
|
2392
|
+
|
|
2393
|
+
Table-backed resources use snake_case physical columns by default. For example, `displayName` maps to `display_name`.
|
|
2394
|
+
|
|
2395
|
+
Use `storage.column` when a field needs a specific column name:
|
|
2396
|
+
|
|
2397
|
+
```javascript
|
|
2398
|
+
api.addResource({
|
|
2399
|
+
name: 'profiles',
|
|
2400
|
+
schema: {
|
|
2401
|
+
id: { type: 'id' },
|
|
2402
|
+
displayName: { type: 'string', required: true },
|
|
2403
|
+
legacyRef: { type: 'string', storage: { column: 'legacy_profile_ref' } }
|
|
2287
2404
|
}
|
|
2288
2405
|
});
|
|
2289
2406
|
```
|
|
2290
2407
|
|
|
2408
|
+
If physical columns should match logical field names exactly for an entire resource, use `storage: { naming: 'exact' }`.
|
|
2409
|
+
|
|
2291
2410
|
#### Virtual Fields
|
|
2292
2411
|
Virtual fields are excluded from database operations but can be used for temporary UI state:
|
|
2293
2412
|
|
|
@@ -2499,6 +2618,45 @@ try {
|
|
|
2499
2618
|
|
|
2500
2619
|
**Important:** When you provide a transaction, you're responsible for committing/rolling back. When you don't provide one, the library auto-commits.
|
|
2501
2620
|
|
|
2621
|
+
### Knex Schema Helpers
|
|
2622
|
+
|
|
2623
|
+
When a resource is backed by `RestApiKnexPlugin`, its scope also exposes table-management helpers:
|
|
2624
|
+
|
|
2625
|
+
```javascript
|
|
2626
|
+
await api.resources.articles.createKnexTable()
|
|
2627
|
+
|
|
2628
|
+
const snapshot = await api.resources.articles.introspectKnexTableSnapshot()
|
|
2629
|
+
const createMigration = await api.resources.articles.generateKnexMigration()
|
|
2630
|
+
const diff = await api.resources.articles.generateKnexMigrationDiff()
|
|
2631
|
+
```
|
|
2632
|
+
|
|
2633
|
+
Available helpers:
|
|
2634
|
+
|
|
2635
|
+
- `createKnexTable()`
|
|
2636
|
+
- `addKnexFields({ fields })`
|
|
2637
|
+
- `alterKnexFields({ fields })`
|
|
2638
|
+
- `introspectKnexTableSnapshot()`
|
|
2639
|
+
- `generateKnexMigration()`
|
|
2640
|
+
- `generateKnexMigrationDiff()`
|
|
2641
|
+
|
|
2642
|
+
`generateKnexMigrationDiff()` returns:
|
|
2643
|
+
|
|
2644
|
+
```javascript
|
|
2645
|
+
{
|
|
2646
|
+
migration,
|
|
2647
|
+
warnings,
|
|
2648
|
+
plan
|
|
2649
|
+
}
|
|
2650
|
+
```
|
|
2651
|
+
|
|
2652
|
+
Important boundaries:
|
|
2653
|
+
|
|
2654
|
+
- this is a live-table snapshot diff, not migration-history reconstruction
|
|
2655
|
+
- `addKnexFields()` and `alterKnexFields()` are field-only helpers
|
|
2656
|
+
- indexes, foreign keys, and check constraints belong on the full table schema surface
|
|
2657
|
+
|
|
2658
|
+
For full examples and dialect notes, see [Knex Schema and Migrations](GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md).
|
|
2659
|
+
|
|
2502
2660
|
### Batch Operations
|
|
2503
2661
|
|
|
2504
2662
|
Process multiple operations efficiently:
|
|
@@ -2746,4 +2904,4 @@ api.resource('articles').hook('knexQueryFiltering', async (context) => {
|
|
|
2746
2904
|
query.whereRaw("metadata->>'key' = ?", [filters.metadata_key]);
|
|
2747
2905
|
}
|
|
2748
2906
|
});
|
|
2749
|
-
```
|
|
2907
|
+
```
|
package/docs/COMPARISON.md
CHANGED
|
@@ -30,7 +30,7 @@ json-rest-api is a full-featured, plugin-based JSON:API implementation built on
|
|
|
30
30
|
| WebSocket support | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
31
31
|
| Bulk operations | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
32
32
|
| Positioning/sorting | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
33
|
-
|
|
|
33
|
+
| Permission hooks / app-owned auth integration | ✅ | ❌ | ⚠️ | ❌ | ❌ |
|
|
34
34
|
| **Developer Experience** |
|
|
35
35
|
| TypeScript support | ✅ | ✅ | ✅ | ❌ | ❌ |
|
|
36
36
|
| Active maintenance | ✅ (2025) | ✅ (2024) | ✅ (2024) | 🟡 (2022) | ❌ (2022) |
|
|
@@ -430,4 +430,4 @@ json-rest-api stands out as the most comprehensive JSON:API solution for Node.js
|
|
|
430
430
|
4. **Active Development**: Regular updates and community support
|
|
431
431
|
5. **Production Ready**: Battle-tested with extensive test coverage
|
|
432
432
|
|
|
433
|
-
For teams building JSON:API services in 2025, json-rest-api offers the best combination of compliance, features, and developer experience.
|
|
433
|
+
For teams building JSON:API services in 2025, json-rest-api offers the best combination of compliance, features, and developer experience.
|
|
@@ -325,6 +325,8 @@ const result = await api.resources.countries.post({
|
|
|
325
325
|
});
|
|
326
326
|
```
|
|
327
327
|
|
|
328
|
+
If you need per-call options such as `transaction`, `returnFullRecord`, or `queryParams`, move the record under `inputRecord` and keep those options at the top level of the params object.
|
|
329
|
+
|
|
328
330
|
By default, `simplifiedApi` is `true` for programmatic usage, making it easier to work with the API in your code while still maintaining full JSON:API compliance internally.
|
|
329
331
|
|
|
330
332
|
#### API usage and returning records
|
|
@@ -778,6 +780,7 @@ Here is a full list of parameters and their respective variables:
|
|
|
778
780
|
| `simplifiedApi` | `vars.simplifiedApi` | `true` | Use simplified format for programmatic API calls | ✓ |
|
|
779
781
|
| `simplifiedTransport` | `vars.simplifiedTransport` | `false` | Use simplified format for HTTP/REST endpoints | ✓ |
|
|
780
782
|
| `idProperty` | `vars.idProperty` | `'id'` | Name of the ID field in resources | ✓ |
|
|
783
|
+
| `normalizeId` | `vars.normalizeId` | trim strings, stringify finite numbers | Normalize resource identifiers before lookups and writes | ✓ |
|
|
781
784
|
| `returnRecordApi` | `vars.returnRecordApi` | `{ post: 'full', put: 'full', patch: 'full' }` | What to return for programmatic API write operations | ✓ |
|
|
782
785
|
| `returnRecordTransport` | `vars.returnRecordTransport` | `{ post: 'no', put: 'no', patch: 'no' }` | What to return for HTTP/REST write operations | ✓ |
|
|
783
786
|
|
|
@@ -795,9 +798,79 @@ Here is a full list of parameters and their respective variables:
|
|
|
795
798
|
- An object: `{ post: 'full', put: 'minimal', patch: 'no' }` (per-method configuration)
|
|
796
799
|
- All parameters support the cascade: per-call → resource-level → plugin-level default
|
|
797
800
|
|
|
798
|
-
#
|
|
801
|
+
# Logical IDs and Physical Columns
|
|
802
|
+
|
|
803
|
+
For table-backed resources, `idProperty` defines the physical primary-key column. The API surface still uses the logical resource id.
|
|
804
|
+
|
|
805
|
+
- simplified writes use `inputRecord.id`
|
|
806
|
+
- JSON:API writes use `inputRecord.data.id`
|
|
807
|
+
- responses expose `id` or `data.id`
|
|
808
|
+
- the resource id is not part of `attributes`
|
|
809
|
+
|
|
810
|
+
```javascript
|
|
811
|
+
await api.addResource('profiles', {
|
|
812
|
+
idProperty: 'user_id',
|
|
813
|
+
schema: {
|
|
814
|
+
id: { type: 'id', required: true, storage: { column: 'user_id' } },
|
|
815
|
+
displayName: { type: 'string', required: true },
|
|
816
|
+
loginCount: { type: 'number', defaultTo: 0 }
|
|
817
|
+
},
|
|
818
|
+
tableName: 'profiles'
|
|
819
|
+
});
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
For table-backed resources, storage columns default to snake_case, so `displayName` maps to `display_name` and `loginCount` maps to `login_count`. Use `storage.column` for a per-field override, or `storage: { naming: 'exact' }` when physical column names should match logical field names exactly.
|
|
823
|
+
|
|
824
|
+
## ID normalization
|
|
825
|
+
|
|
826
|
+
`normalizeId` lets you canonicalize resource identifiers before the library reads, writes, validates, or links records.
|
|
799
827
|
|
|
800
|
-
|
|
828
|
+
The default normalizer already handles the common cases:
|
|
829
|
+
|
|
830
|
+
- trims surrounding whitespace from strings
|
|
831
|
+
- converts finite numbers and bigints to strings
|
|
832
|
+
- rejects values that normalize to an empty identifier
|
|
833
|
+
|
|
834
|
+
You only need to provide `normalizeId` when your resource ids need additional canonicalization, such as uppercasing, lowercasing, or removing formatting characters.
|
|
835
|
+
|
|
836
|
+
```javascript
|
|
837
|
+
await api.use(RestApiPlugin, {
|
|
838
|
+
normalizeId: (value) => {
|
|
839
|
+
if (value === null || value === undefined) return null
|
|
840
|
+
|
|
841
|
+
const normalized = String(value).trim()
|
|
842
|
+
return normalized ? normalized.toUpperCase() : null
|
|
843
|
+
}
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
await api.addResource('countries', {
|
|
847
|
+
// Override the plugin-wide normalizer for this one resource
|
|
848
|
+
normalizeId: (value) => {
|
|
849
|
+
if (value === null || value === undefined) return null
|
|
850
|
+
|
|
851
|
+
const normalized = String(value).trim()
|
|
852
|
+
return normalized ? normalized.toLowerCase() : null
|
|
853
|
+
},
|
|
854
|
+
schema: {
|
|
855
|
+
name: { type: 'string', required: true }
|
|
856
|
+
}
|
|
857
|
+
})
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
Normalization is applied consistently to:
|
|
861
|
+
|
|
862
|
+
- `get`, `put`, `patch`, `delete`, `getRelated`, and `getRelationship` parent ids
|
|
863
|
+
- explicit resource ids in `POST`, `PUT`, and `PATCH` documents
|
|
864
|
+
- relationship identifiers supplied to `postRelationship`, `patchRelationship`, and `deleteRelationship`
|
|
865
|
+
|
|
866
|
+
The resource-level `normalizeId` override also applies to relationship identifiers when that resource appears as the related target.
|
|
867
|
+
|
|
868
|
+
If an id normalizes to an empty value:
|
|
869
|
+
|
|
870
|
+
- existing-resource operations behave as `not_found`
|
|
871
|
+
- explicit `POST` document ids are rejected as validation errors on `data.id`
|
|
872
|
+
|
|
873
|
+
For full examples of table creation, physical column naming, and migration generation, see [Knex Schema and Migrations](GUIDE_X_Knex_Schema_And_Migrations.md).
|
|
801
874
|
|
|
802
875
|
# Helpers and Methods Provided by REST API Plugins
|
|
803
876
|
|
|
@@ -828,8 +901,14 @@ When you install the REST API plugins, the following helpers are added to `api.h
|
|
|
828
901
|
const trx = await api.helpers.newTransaction();
|
|
829
902
|
try {
|
|
830
903
|
// Use transaction in multiple operations
|
|
831
|
-
await api.resources.countries.post({
|
|
832
|
-
|
|
904
|
+
await api.resources.countries.post({
|
|
905
|
+
inputRecord: { name: 'France', code: 'FR' },
|
|
906
|
+
transaction: trx
|
|
907
|
+
});
|
|
908
|
+
await api.resources.publishers.post({
|
|
909
|
+
inputRecord: { name: 'French Press', country: 1 },
|
|
910
|
+
transaction: trx
|
|
911
|
+
});
|
|
833
912
|
await trx.commit();
|
|
834
913
|
} catch (error) {
|
|
835
914
|
await trx.rollback();
|
|
@@ -928,6 +1007,32 @@ Each resource (added via `api.addResource()`) gets these methods automatically:
|
|
|
928
1007
|
await api.resources.countries.createKnexTable();
|
|
929
1008
|
```
|
|
930
1009
|
|
|
1010
|
+
- **`api.resources.{resourceName}.introspectKnexTableSnapshot()`** - Returns a normalized snapshot of the live physical table
|
|
1011
|
+
```javascript
|
|
1012
|
+
const snapshot = await api.resources.countries.introspectKnexTableSnapshot();
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
- **`api.resources.{resourceName}.generateKnexMigration()`** - Generates a Knex create migration string for the resource
|
|
1016
|
+
```javascript
|
|
1017
|
+
const migration = await api.resources.countries.generateKnexMigration();
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
- **`api.resources.{resourceName}.generateKnexMigrationDiff()`** - Generates an additive diff migration from the live table snapshot
|
|
1021
|
+
```javascript
|
|
1022
|
+
const diff = await api.resources.countries.generateKnexMigrationDiff();
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
- **`api.resources.{resourceName}.addKnexFields({ fields })`** / **`alterKnexFields({ fields })`** - Column-only helpers for existing tables
|
|
1026
|
+
```javascript
|
|
1027
|
+
await api.resources.countries.addKnexFields({
|
|
1028
|
+
fields: {
|
|
1029
|
+
iso3: { type: 'string', maxLength: 3 }
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
For full examples of snapshots, migration generation, diffing, and table metadata such as indexes / foreign keys / checks, see [Knex Schema and Migrations](GUIDE_X_Knex_Schema_And_Migrations.md).
|
|
1035
|
+
|
|
931
1036
|
|
|
932
1037
|
## API Namespaces (internal, for plugin developers)
|
|
933
1038
|
|
|
@@ -943,6 +1048,7 @@ These helpers and methods provide a complete toolkit for:
|
|
|
943
1048
|
- Managing database transactions
|
|
944
1049
|
- Generating proper URLs and links
|
|
945
1050
|
- Accessing the underlying database when needed
|
|
1051
|
+
- Inspecting live tables and generating Knex migrations when using table-backed resources
|
|
946
1052
|
- Integrating with web frameworks like Express
|
|
947
1053
|
|
|
948
|
-
The architecture ensures clean separation between HTTP transport, business logic, and data persistence layers.
|
|
1054
|
+
The architecture ensures clean separation between HTTP transport, business logic, and data persistence layers.
|
|
@@ -306,6 +306,10 @@ The `searchSchema` gives you:
|
|
|
306
306
|
* Flexibility to extend: Add virtual fields or complex filters via searchSchema while basic fields use `search: true`
|
|
307
307
|
* Best of both worlds: Explicit control for complex cases, automatic setup for simple ones
|
|
308
308
|
|
|
309
|
+
`searchSchema` also defines the public filter names your API accepts. Those keys do not need to match database columns or even resource field names. Treat `searchSchema` as an allowlist plus normalization layer for filter input: the actual meaning of each key is still implemented by the backend through mappings such as `actualField`, multi-field rules such as `oneOf`, standard operators, or custom `applyFilter` logic. It is not a portable filter DSL.
|
|
310
|
+
|
|
311
|
+
The merge rules and validation surface are shared across storage backends. Advanced execution semantics are still backend-owned. In practice, that means alias filters such as `oneOf` and custom `applyFilter` functions should be validated against the backend you actually run, and the SQL-heavy examples in this chapter assume the Knex-backed query layer.
|
|
312
|
+
|
|
309
313
|
`searchSchema` also gives you the ability to define a search field that will search in multiple fields. For example:
|
|
310
314
|
|
|
311
315
|
```javascript
|
|
@@ -801,4 +805,4 @@ GET /api/countries?filter[search]=united+states&fields[countries]=code
|
|
|
801
805
|
|
|
802
806
|
---
|
|
803
807
|
|
|
804
|
-
[Previous: 2.1 The starting point](./GUIDE_2_1_The_Starting_Point.md) | [Back to Guide](./README.md) | [Next: 2.3 `belongsTo` Relationships](./GUIDE_2_3_BelongsTo_Relationships.md)
|
|
808
|
+
[Previous: 2.1 The starting point](./GUIDE_2_1_The_Starting_Point.md) | [Back to Guide](./README.md) | [Next: 2.3 `belongsTo` Relationships](./GUIDE_2_3_BelongsTo_Relationships.md)
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Pagination and ordering are essential features for working with large datasets. The json-rest-api library provides powerful pagination that applies not just to main resources, but also to included relationships. This means you can limit and order both parent records AND their children independently.
|
|
4
4
|
|
|
5
|
+
For derived fields that must participate in `ORDER BY` and cursor pagination, see [Query Projections](GUIDE_X_Query_Projections.md). Regular computed fields are response-layer only and are not the right tool for stable SQL ordering.
|
|
6
|
+
|
|
5
7
|
Let's create a comprehensive example with posts, comments, and tags to demonstrate all pagination and ordering features:
|
|
6
8
|
|
|
7
9
|
```javascript
|
|
@@ -1233,4 +1235,4 @@ The pagination and ordering system is designed to be efficient and predictable:
|
|
|
1233
1235
|
|
|
1234
1236
|
---
|
|
1235
1237
|
|
|
1236
|
-
[Previous: 2.6 Many to Many Relationships](./GUIDE_2_6_Many_To_Many.md) | [Back to Guide](./README.md)
|
|
1238
|
+
[Previous: 2.6 Many to Many Relationships](./GUIDE_2_6_Many_To_Many.md) | [Back to Guide](./README.md)
|