json-rest-api 1.0.22 → 1.0.23
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/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
- package/docs/API.md +51 -14
- package/docs/COMPARISON.md +2 -2
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +28 -1
- 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 +250 -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/package.json +2 -2
- package/plugins/core/connectors/express-plugin.js +97 -184
- package/plugins/core/connectors/fastify-plugin.js +206 -0
- 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/dbIntrospection.js +1078 -0
- package/plugins/core/lib/dbTablesOperations.js +1104 -160
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -2
- package/plugins/core/lib/querying/knex-process-includes.js +3 -4
- package/plugins/core/lib/querying/knex-query-helpers.js +17 -71
- package/plugins/core/lib/querying/knex-relationship-includes.js +466 -206
- 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 +12 -1
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -13
- 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/storage/canonical-storage-mapping.js +113 -0
- package/plugins/core/lib/storage/storage-adapter.js +79 -2
- package/plugins/core/lib/storage/storage-mapping.js +204 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +355 -228
- package/plugins/core/rest-api-autofilter-plugin.js +414 -0
- package/plugins/core/rest-api-knex-plugin.js +249 -211
- 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-methods/apply-query-filters.js +41 -0
- package/plugins/core/rest-api-plugin-methods/common.js +121 -83
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
- package/plugins/core/rest-api-plugin-methods/get.js +23 -14
- package/plugins/core/rest-api-plugin-methods/patch.js +28 -12
- package/plugins/core/rest-api-plugin-methods/post.js +13 -8
- package/plugins/core/rest-api-plugin-methods/put.js +45 -21
- package/plugins/core/rest-api-plugin-methods/query.js +15 -53
- package/plugins/core/rest-api-plugin.js +2 -0
- package/plugins/core/rest-api-positioning-plugin.js +1 -1
- package/plugins/core/rest-api-query-projections-plugin.js +130 -0
- package/plugins/core/socketio-plugin.js +1 -3
- package/tests/autofilter.test.js +463 -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 +518 -0
- package/tests/db-table-operations.test.js +781 -0
- package/tests/fastify-plugin.test.js +141 -0
- package/tests/field-getters.test.js +1 -2
- package/tests/field-setters.test.js +0 -4
- package/tests/fixtures/api-configs.js +188 -219
- package/tests/helpers/fake-fastify.js +99 -0
- package/tests/http-connectors-parity.test.js +235 -0
- 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 +210 -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
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Knex Schema and Migrations
|
|
2
|
+
|
|
3
|
+
`RestApiKnexPlugin` exposes a small schema-management surface for table-backed resources.
|
|
4
|
+
|
|
5
|
+
Use it when you want to:
|
|
6
|
+
|
|
7
|
+
- create tables directly from resource definitions
|
|
8
|
+
- add or alter plain columns on existing tables
|
|
9
|
+
- inspect a live table snapshot
|
|
10
|
+
- generate a create migration from a resource
|
|
11
|
+
- generate an additive diff migration from a live table
|
|
12
|
+
|
|
13
|
+
This is a Knex/table feature surface. It does not exist for non-table resources.
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Once a resource is backed by `RestApiKnexPlugin`, these scope methods are available:
|
|
18
|
+
|
|
19
|
+
- `createKnexTable()`
|
|
20
|
+
- `addKnexFields({ fields })`
|
|
21
|
+
- `alterKnexFields({ fields })`
|
|
22
|
+
- `introspectKnexTableSnapshot()`
|
|
23
|
+
- `generateKnexMigration()`
|
|
24
|
+
- `generateKnexMigrationDiff()`
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
await api.addResource('memberships', {
|
|
30
|
+
schema: {
|
|
31
|
+
id: { type: 'id' },
|
|
32
|
+
workspaceId: { type: 'id', required: true, storage: { column: 'workspace_id' } },
|
|
33
|
+
userId: { type: 'id', required: true, storage: { column: 'user_id' } },
|
|
34
|
+
role: { type: 'string', enum: ['owner', 'member'], required: true, defaultTo: 'member' }
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
indexes: [
|
|
38
|
+
{
|
|
39
|
+
name: 'uq_memberships_workspace_user',
|
|
40
|
+
unique: true,
|
|
41
|
+
columns: ['workspaceId', 'userId']
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
|
|
45
|
+
foreignKeys: [
|
|
46
|
+
{
|
|
47
|
+
name: 'fk_memberships_workspace_user',
|
|
48
|
+
columns: ['workspaceId', 'userId'],
|
|
49
|
+
referencedTableName: 'workspace_users',
|
|
50
|
+
referencedColumns: ['workspace_id', 'user_id'],
|
|
51
|
+
deleteRule: 'CASCADE',
|
|
52
|
+
updateRule: 'RESTRICT'
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
checkConstraints: [
|
|
57
|
+
{
|
|
58
|
+
name: 'chk_memberships_workspace_positive',
|
|
59
|
+
clause: 'workspace_id > 0'
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
|
|
63
|
+
tableName: 'memberships'
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Create Tables
|
|
68
|
+
|
|
69
|
+
Create the table directly from the resource definition:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
await api.resources.memberships.createKnexTable()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`createKnexTable()` understands:
|
|
76
|
+
|
|
77
|
+
- storage-mapped column names
|
|
78
|
+
- mapped logical id columns
|
|
79
|
+
- top-level `indexes`
|
|
80
|
+
- top-level `foreignKeys`
|
|
81
|
+
- top-level `checkConstraints`
|
|
82
|
+
- enum columns
|
|
83
|
+
- MySQL-style `setValues`
|
|
84
|
+
|
|
85
|
+
This is the same table metadata used by migration generation and diffing.
|
|
86
|
+
|
|
87
|
+
## Field-Only Helpers
|
|
88
|
+
|
|
89
|
+
Two helpers only operate on columns:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
await api.resources.memberships.addKnexFields({
|
|
93
|
+
fields: {
|
|
94
|
+
noteCount: { type: 'number', defaultTo: 0, storage: { column: 'note_count' } }
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
await api.resources.memberships.alterKnexFields({
|
|
99
|
+
fields: {
|
|
100
|
+
role: { type: 'string', enum: ['owner', 'member', 'viewer'] }
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Important:
|
|
106
|
+
|
|
107
|
+
- these helpers are field-only
|
|
108
|
+
- they reject top-level `indexes`, `foreignKeys`, and `checkConstraints`
|
|
109
|
+
- use `createKnexTable()`, `generateKnexMigration()`, or `generateKnexMigrationDiff()` for table metadata
|
|
110
|
+
|
|
111
|
+
## Live Table Snapshots
|
|
112
|
+
|
|
113
|
+
Use `introspectKnexTableSnapshot()` to inspect the physical table shape:
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
const snapshot = await api.resources.memberships.introspectKnexTableSnapshot()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Returned shape:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
{
|
|
123
|
+
dialect: 'sqlite',
|
|
124
|
+
schemaName: 'main',
|
|
125
|
+
tableName: 'memberships',
|
|
126
|
+
tableCollation: '',
|
|
127
|
+
idColumn: 'id',
|
|
128
|
+
primaryKeyColumns: ['id'],
|
|
129
|
+
hasWorkspaceIdColumn: true,
|
|
130
|
+
hasUserIdColumn: true,
|
|
131
|
+
columns: [...],
|
|
132
|
+
indexes: [...],
|
|
133
|
+
foreignKeys: [...],
|
|
134
|
+
checkConstraints: [...]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Column entries are normalized and include information such as:
|
|
139
|
+
|
|
140
|
+
- physical column name
|
|
141
|
+
- logical key
|
|
142
|
+
- type kind
|
|
143
|
+
- nullability
|
|
144
|
+
- default value
|
|
145
|
+
- precision / scale / datetime precision
|
|
146
|
+
- enum values
|
|
147
|
+
- set values
|
|
148
|
+
|
|
149
|
+
Current live introspection support:
|
|
150
|
+
|
|
151
|
+
- SQLite
|
|
152
|
+
- MySQL / MariaDB via `mysql2`
|
|
153
|
+
|
|
154
|
+
## Create Migrations
|
|
155
|
+
|
|
156
|
+
Use `generateKnexMigration()` to emit a Knex migration string from the resource definition:
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
const migration = await api.resources.memberships.generateKnexMigration()
|
|
160
|
+
console.log(migration)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This generates `exports.up` and `exports.down` for full table creation/drop.
|
|
164
|
+
|
|
165
|
+
It includes the same table metadata as `createKnexTable()`:
|
|
166
|
+
|
|
167
|
+
- mapped columns
|
|
168
|
+
- mapped id column
|
|
169
|
+
- indexes
|
|
170
|
+
- foreign keys
|
|
171
|
+
- check constraints
|
|
172
|
+
- enum columns
|
|
173
|
+
- supported MySQL-specific set columns
|
|
174
|
+
|
|
175
|
+
## Diff Migrations
|
|
176
|
+
|
|
177
|
+
Use `generateKnexMigrationDiff()` to compare the desired schema against the live table snapshot:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
const diff = await api.resources.memberships.generateKnexMigrationDiff()
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Returned shape:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
{
|
|
187
|
+
migration,
|
|
188
|
+
warnings,
|
|
189
|
+
plan
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`plan` is normalized into:
|
|
194
|
+
|
|
195
|
+
- `addColumns`
|
|
196
|
+
- `alterColumns`
|
|
197
|
+
- `dropColumns`
|
|
198
|
+
- `addIndexes`
|
|
199
|
+
- `dropIndexes`
|
|
200
|
+
- `addForeignKeys`
|
|
201
|
+
- `dropForeignKeys`
|
|
202
|
+
- `addCheckConstraints`
|
|
203
|
+
|
|
204
|
+
The generated migration is intentionally additive-first:
|
|
205
|
+
|
|
206
|
+
- create missing columns
|
|
207
|
+
- alter columns when supported
|
|
208
|
+
- recreate changed indexes when needed
|
|
209
|
+
- add missing foreign keys
|
|
210
|
+
- add supported check constraints
|
|
211
|
+
|
|
212
|
+
## Important Limits
|
|
213
|
+
|
|
214
|
+
This is a schema-vs-live-table diff, not a migration-history engine.
|
|
215
|
+
|
|
216
|
+
It answers:
|
|
217
|
+
|
|
218
|
+
- what the table looks like now
|
|
219
|
+
- what the resource says it should look like
|
|
220
|
+
- what Knex migration can safely move the table toward that shape
|
|
221
|
+
|
|
222
|
+
It does not answer:
|
|
223
|
+
|
|
224
|
+
- what changed since a previous migration file
|
|
225
|
+
- how to reconstruct migration history
|
|
226
|
+
|
|
227
|
+
Other important limits:
|
|
228
|
+
|
|
229
|
+
- destructive changes are surfaced as warnings
|
|
230
|
+
- dropped columns are skipped unless explicitly allowed by diff options
|
|
231
|
+
- SQLite check-constraint add/drop/alter support is warning-only
|
|
232
|
+
- `setValues` diffing is only emitted for MySQL-compatible targets
|
|
233
|
+
- diff migrations do not auto-generate a destructive `down`
|
|
234
|
+
|
|
235
|
+
## When to Use Which Helper
|
|
236
|
+
|
|
237
|
+
- `createKnexTable()`
|
|
238
|
+
- bootstrap a table directly from the resource
|
|
239
|
+
|
|
240
|
+
- `addKnexFields()` / `alterKnexFields()`
|
|
241
|
+
- small column-only local changes
|
|
242
|
+
|
|
243
|
+
- `introspectKnexTableSnapshot()`
|
|
244
|
+
- inspect the real physical table
|
|
245
|
+
|
|
246
|
+
- `generateKnexMigration()`
|
|
247
|
+
- emit a full create migration from the current resource definition
|
|
248
|
+
|
|
249
|
+
- `generateKnexMigrationDiff()`
|
|
250
|
+
- emit an additive migration against the live table
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Query Projections
|
|
2
|
+
|
|
3
|
+
Query projections are SQL-backed, output-only query fields provided by the optional `QueryProjectionsPlugin`. They are different from normal computed fields.
|
|
4
|
+
|
|
5
|
+
If you want to build your own plugin on the same query-field seam, see [Writing Plugins](GUIDE_X_Writing_Plugins.md).
|
|
6
|
+
|
|
7
|
+
- **Computed fields** run after the row is fetched, in JavaScript.
|
|
8
|
+
- **Projected fields** are selected inside the query, so they can participate in `SELECT`, `ORDER BY`, and cursor pagination.
|
|
9
|
+
|
|
10
|
+
Use query projection fields when a derived value must behave like a real list field.
|
|
11
|
+
|
|
12
|
+
Typical cases:
|
|
13
|
+
- sorting by a derived label such as `full_name`
|
|
14
|
+
- cursor pagination over a derived value
|
|
15
|
+
- returning a derived SQL value without storing it
|
|
16
|
+
|
|
17
|
+
Do **not** use query projection fields for normal response decoration. Regular computed fields are simpler and remain the right default for that.
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { RestApiPlugin, QueryProjectionsPlugin } from 'json-rest-api'
|
|
23
|
+
|
|
24
|
+
await api.use(RestApiPlugin, { simplifiedApi: false, simplifiedTransport: false })
|
|
25
|
+
await api.use(QueryProjectionsPlugin)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Defining a query field
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
await api.addResource('authors', {
|
|
32
|
+
schema: {
|
|
33
|
+
id: { type: 'id' },
|
|
34
|
+
first_name: { type: 'string', required: true },
|
|
35
|
+
last_name: { type: 'string', required: true }
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
queryFields: {
|
|
39
|
+
full_name: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
sortable: true,
|
|
42
|
+
select: ({ knex, column }) => knex.raw(
|
|
43
|
+
"trim(coalesce(??, '') || ' ' || coalesce(??, ''))",
|
|
44
|
+
[column('first_name'), column('last_name')]
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
sortableFields: ['id', 'first_name', 'last_name'],
|
|
50
|
+
defaultSort: ['full_name']
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`select()` is called at query time. It can return:
|
|
55
|
+
|
|
56
|
+
- a `knex.raw(...)` expression
|
|
57
|
+
- a Knex reference
|
|
58
|
+
- a Knex query/subquery expression
|
|
59
|
+
|
|
60
|
+
The callback receives:
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
{
|
|
64
|
+
knex, // current knex/db handle
|
|
65
|
+
db, // same as knex
|
|
66
|
+
context, // request context
|
|
67
|
+
scopeName,
|
|
68
|
+
tableName,
|
|
69
|
+
fieldName,
|
|
70
|
+
schemaInfo,
|
|
71
|
+
adapter, // storage adapter
|
|
72
|
+
column, // helper: logical field -> qualified storage column
|
|
73
|
+
ref // helper: logical field -> knex ref
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Behavior
|
|
78
|
+
|
|
79
|
+
Query projection fields are:
|
|
80
|
+
|
|
81
|
+
- returned by default in `get()` and `query()`
|
|
82
|
+
- available in sparse fieldsets
|
|
83
|
+
- usable in sorting and cursor pagination
|
|
84
|
+
- available on included resources
|
|
85
|
+
- ignored on writes
|
|
86
|
+
|
|
87
|
+
They are **not** stored columns, and they are **not** part of write validation.
|
|
88
|
+
|
|
89
|
+
## Sparse fieldsets
|
|
90
|
+
|
|
91
|
+
Query projection fields can be requested explicitly:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
const result = await api.resources.authors.get({
|
|
95
|
+
id: '1',
|
|
96
|
+
queryParams: {
|
|
97
|
+
fields: {
|
|
98
|
+
authors: 'first_name,full_name'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If a query field is needed only for sorting, it is still selected internally, but it is removed from the response unless the sparse fieldset asked for it.
|
|
105
|
+
|
|
106
|
+
## Sorting and cursor pagination
|
|
107
|
+
|
|
108
|
+
Query projection fields are useful when a derived value must drive list behavior:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const result = await api.resources.authors.query({
|
|
112
|
+
queryParams: {
|
|
113
|
+
sort: ['full_name'],
|
|
114
|
+
page: { size: 20 }
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`json-rest-api` automatically appends `id` as a stable tie-breaker for cursor ordering. That prevents duplicate or skipped rows when multiple records share the same projected value.
|
|
120
|
+
|
|
121
|
+
## Included resources
|
|
122
|
+
|
|
123
|
+
Query projection fields can be selected for included resources too:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
const result = await api.resources.books.get({
|
|
127
|
+
id: '1',
|
|
128
|
+
queryParams: {
|
|
129
|
+
include: ['author'],
|
|
130
|
+
fields: {
|
|
131
|
+
books: 'title',
|
|
132
|
+
authors: 'full_name'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Write behavior
|
|
139
|
+
|
|
140
|
+
Query projection fields are output-only. If a client sends them in `POST`, `PUT`, or `PATCH`, they are ignored.
|
|
141
|
+
|
|
142
|
+
That keeps the boundary clean:
|
|
143
|
+
|
|
144
|
+
- persisted fields own storage
|
|
145
|
+
- computed fields own response-layer enrichment
|
|
146
|
+
- query projection fields own query-layer derivation
|
|
147
|
+
|
|
148
|
+
## Limits
|
|
149
|
+
|
|
150
|
+
Projected fields are an advanced query feature. They are intentionally **backend-sensitive**.
|
|
151
|
+
|
|
152
|
+
Important limits:
|
|
153
|
+
|
|
154
|
+
- projection SQL can be dialect-specific
|
|
155
|
+
- this is not a portability layer across every SQL engine
|
|
156
|
+
- query projection fields are not auto-searchable
|
|
157
|
+
- if you want to sort by one, mark it `sortable: true`
|
|
158
|
+
|
|
159
|
+
For display-only derived values, prefer normal computed fields from [Field Transformations](GUIDE_3_Field_Transformations.md).
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Writing Plugins
|
|
2
|
+
|
|
3
|
+
`json-rest-api` is built as a set of plugins on top of `hooked-api`. This guide covers the public extension surface for plugin authors.
|
|
4
|
+
|
|
5
|
+
Use this guide when you want to:
|
|
6
|
+
|
|
7
|
+
- add resource-level behavior across many resources
|
|
8
|
+
- add new scope methods
|
|
9
|
+
- compile resource metadata into reusable runtime state
|
|
10
|
+
- hook into query or write processing
|
|
11
|
+
|
|
12
|
+
For internal architecture notes and maintainer-oriented details, see [docs/ONBOARDING.md](../ONBOARDING.md).
|
|
13
|
+
|
|
14
|
+
## Minimal plugin shape
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
export const MyPlugin = {
|
|
18
|
+
name: 'my-plugin',
|
|
19
|
+
dependencies: ['rest-api'],
|
|
20
|
+
|
|
21
|
+
install ({ addHook, addScopeMethod, helpers, log, pluginOptions = {} }) {
|
|
22
|
+
addHook('scope:added', 'compile-my-plugin', {}, ({ context, scopes }) => {
|
|
23
|
+
const scope = scopes[context.scopeName]
|
|
24
|
+
scope.vars.myPlugin = { enabled: true }
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
addScopeMethod('doSomething', async ({ scopeName, scope, params, context }) => {
|
|
28
|
+
return { scopeName, enabled: scope.vars.myPlugin?.enabled === true }
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The usual pattern is:
|
|
35
|
+
|
|
36
|
+
1. compile resource metadata during `scope:added`
|
|
37
|
+
2. store normalized state in `scope.vars`
|
|
38
|
+
3. use hooks or scope methods to apply behavior at runtime
|
|
39
|
+
|
|
40
|
+
## The stable extension points
|
|
41
|
+
|
|
42
|
+
### `scope:added`
|
|
43
|
+
|
|
44
|
+
Use this to inspect `scopeOptions`, validate configuration, and compile resource-specific runtime state into `scope.vars`.
|
|
45
|
+
|
|
46
|
+
Typical uses:
|
|
47
|
+
|
|
48
|
+
- compile autofilter presets
|
|
49
|
+
- compile query-field definitions
|
|
50
|
+
- validate resource-specific options
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
addHook('scope:added', 'compile-example', {}, ({ context, scopes }) => {
|
|
56
|
+
const scope = scopes[context.scopeName]
|
|
57
|
+
const options = scope.scopeOptions || {}
|
|
58
|
+
|
|
59
|
+
scope.vars.example = {
|
|
60
|
+
flag: options.exampleFlag === true
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `beforeSchemaValidate`
|
|
66
|
+
|
|
67
|
+
Use this to normalize or strip write input before schema validation runs.
|
|
68
|
+
|
|
69
|
+
Typical uses:
|
|
70
|
+
|
|
71
|
+
- inject derived input values
|
|
72
|
+
- remove output-only fields from `POST`/`PUT`/`PATCH`
|
|
73
|
+
- translate alternate request forms into canonical attributes/relationships
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
addHook('beforeSchemaValidate', 'strip-output-only-input', {}, ({ context }) => {
|
|
79
|
+
const attributes = context.inputRecord?.data?.attributes
|
|
80
|
+
if (!attributes) return
|
|
81
|
+
|
|
82
|
+
delete attributes.output_only_field
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `knexQueryFiltering`
|
|
87
|
+
|
|
88
|
+
Use this to add query constraints to the generated Knex query.
|
|
89
|
+
|
|
90
|
+
Typical uses:
|
|
91
|
+
|
|
92
|
+
- automatic scoping
|
|
93
|
+
- cross-table filters
|
|
94
|
+
- custom public filter semantics
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
addHook('knexQueryFiltering', 'scope-by-workspace', {}, async ({ context }) => {
|
|
100
|
+
const query = context.knexQuery?.query
|
|
101
|
+
if (!query) return
|
|
102
|
+
|
|
103
|
+
query.where('workspace_id', context.session.workspaceId)
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`knexQueryFiltering` is the right seam for filtering. It is **not** the right seam for turning ad hoc SQL aliases into first-class fields.
|
|
108
|
+
|
|
109
|
+
### `addScopeMethod`
|
|
110
|
+
|
|
111
|
+
Use this when a plugin needs a reusable method on every resource or selected resources.
|
|
112
|
+
|
|
113
|
+
Example:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
addScopeMethod('introspect', async ({ vars }) => {
|
|
117
|
+
return {
|
|
118
|
+
tableName: vars.schemaInfo?.tableName,
|
|
119
|
+
fields: Object.keys(vars.schemaInfo?.schemaStructure || {})
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## The query-field seam
|
|
125
|
+
|
|
126
|
+
`json-rest-api` now supports a small, explicit seam for **query-only read fields**.
|
|
127
|
+
|
|
128
|
+
This is the seam used by `QueryProjectionsPlugin`, and it is the recommended pattern for plugins that need derived SQL-backed fields.
|
|
129
|
+
|
|
130
|
+
### What a plugin should provide
|
|
131
|
+
|
|
132
|
+
Compile resource-level definitions into:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
scope.vars.queryFields = {
|
|
136
|
+
full_name: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
sortable: true,
|
|
139
|
+
hidden: false,
|
|
140
|
+
normallyHidden: false,
|
|
141
|
+
select: ({ knex, db, context, scopeName, tableName, fieldName, schemaInfo, adapter, column, ref }) => {
|
|
142
|
+
return knex.raw(
|
|
143
|
+
"trim(coalesce(??, '') || ' ' || coalesce(??, ''))",
|
|
144
|
+
[column('first_name'), column('last_name')]
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### What core will do with `scope.vars.queryFields`
|
|
152
|
+
|
|
153
|
+
Once a plugin sets `scope.vars.queryFields`, core will:
|
|
154
|
+
|
|
155
|
+
- include visible query fields by default in `get()` and `query()`
|
|
156
|
+
- allow them in sparse fieldsets
|
|
157
|
+
- allow them in sorting when the plugin marks them sortable
|
|
158
|
+
- use them in cursor pagination with a stable `id` tie-breaker
|
|
159
|
+
- carry them through included-resource selection
|
|
160
|
+
- only expose declared query-field aliases on the AnyAPI path
|
|
161
|
+
|
|
162
|
+
### What this seam is for
|
|
163
|
+
|
|
164
|
+
Use it for:
|
|
165
|
+
|
|
166
|
+
- SQL-backed projections
|
|
167
|
+
- aggregate list fields
|
|
168
|
+
- joined display labels
|
|
169
|
+
- derived fields that must participate in `ORDER BY`
|
|
170
|
+
|
|
171
|
+
Do **not** use it for:
|
|
172
|
+
|
|
173
|
+
- writable fields
|
|
174
|
+
- storage/schema ownership
|
|
175
|
+
- migrations or introspection
|
|
176
|
+
- normal response-only computed fields
|
|
177
|
+
|
|
178
|
+
For the concrete projection example, see [Query Projections](GUIDE_X_Query_Projections.md).
|
|
179
|
+
|
|
180
|
+
## Recommended plugin pattern
|
|
181
|
+
|
|
182
|
+
When you add a new plugin feature, prefer this flow:
|
|
183
|
+
|
|
184
|
+
1. read plugin options at install time
|
|
185
|
+
2. validate and compile per-resource config in `scope:added`
|
|
186
|
+
3. store only normalized runtime state in `scope.vars`
|
|
187
|
+
4. use hooks or scope methods to apply behavior
|
|
188
|
+
|
|
189
|
+
That keeps the plugin declarative and avoids re-parsing configuration during requests.
|
|
190
|
+
|
|
191
|
+
## Boundaries to keep clean
|
|
192
|
+
|
|
193
|
+
- Keep **query-layer** extensions out of `schema`.
|
|
194
|
+
- Keep **write/input** reshaping in `beforeSchemaValidate`.
|
|
195
|
+
- Keep **filtering** in `knexQueryFiltering`.
|
|
196
|
+
- Keep **response-only** enrichment in `enrichAttributes`.
|
|
197
|
+
- Do not rely on arbitrary internal helper filenames as public API.
|
|
198
|
+
|
|
199
|
+
If a feature requires deeper integration than the public seams provide, treat that as a core extension discussion rather than a plugin hack.
|
package/docs/GUIDE/index.md
CHANGED
|
@@ -15,16 +15,13 @@ Welcome to the comprehensive guide for JSON REST API. This guide will walk you t
|
|
|
15
15
|
3. **[Field Transformations](GUIDE_3_Field_Transformations.md)**
|
|
16
16
|
Transform data with virtual fields, getters, setters, computed fields, and visibility control.
|
|
17
17
|
|
|
18
|
-
4. **[
|
|
19
|
-
Implement security with authentication strategies and fine-grained permissions.
|
|
20
|
-
|
|
21
|
-
5. **[Non-Database Resources](GUIDE_5_Non-Db_Resources.md)**
|
|
18
|
+
4. **[Non-Database Resources](GUIDE_5_Non-Db_Resources.md)**
|
|
22
19
|
Connect your API to alternative data sources beyond traditional databases.
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
5. **[Positioning](GUIDE_6_Positioning.md)**
|
|
25
22
|
Implement drag-and-drop functionality with automatic position management.
|
|
26
23
|
|
|
27
|
-
|
|
24
|
+
6. **[Hooks, Data Management, and Plugins](GUIDE_7_Hooks_Data_Management_And_Plugins.md)**
|
|
28
25
|
Master the hook system for data validation, transformation, and business logic.
|
|
29
26
|
|
|
30
27
|
|
|
@@ -39,8 +36,20 @@ Welcome to the comprehensive guide for JSON REST API. This guide will walk you t
|
|
|
39
36
|
- **[CORS Configuration](GUIDE_X_Cors.md)**
|
|
40
37
|
Set up Cross-Origin Resource Sharing for browser-based applications.
|
|
41
38
|
|
|
42
|
-
- **[
|
|
43
|
-
|
|
39
|
+
- **[Autofiltering](GUIDE_X_Autofiltering.md)**
|
|
40
|
+
Scope datasets automatically using configured context values, without baking in auth semantics.
|
|
41
|
+
|
|
42
|
+
- **[Knex Schema and Migrations](GUIDE_X_Knex_Schema_And_Migrations.md)**
|
|
43
|
+
Create tables, inspect live table snapshots, and generate create or additive diff migrations from table-backed resource scopes.
|
|
44
|
+
|
|
45
|
+
- **[Query Projections](GUIDE_X_Query_Projections.md)**
|
|
46
|
+
Use the optional query-projections plugin to add SQL-backed, output-only derived fields that can participate in sorting and cursor pagination.
|
|
47
|
+
|
|
48
|
+
- **[Writing Plugins](GUIDE_X_Writing_Plugins.md)**
|
|
49
|
+
Build plugins against the supported extension surface, including hooks, scope methods, and query-only read fields.
|
|
50
|
+
|
|
51
|
+
- **[Fastify Integration](GUIDE_X_Fastify.md)**
|
|
52
|
+
Register REST routes on Fastify and reject malformed write payloads at the transport layer using exported resource schemas.
|
|
44
53
|
|
|
45
54
|
- **[Socket.IO Integration](GUIDE_X_SocketIO.md)**
|
|
46
55
|
Add real-time capabilities to your API with WebSocket support.
|
|
@@ -61,4 +70,4 @@ Before starting this guide, you should have:
|
|
|
61
70
|
|
|
62
71
|
---
|
|
63
72
|
|
|
64
|
-
Ready to get started? Head to [Chapter 1: Initial Setup](GUIDE_1_Initial_Setup.md) →
|
|
73
|
+
Ready to get started? Head to [Chapter 1: Initial Setup](GUIDE_1_Initial_Setup.md) →
|
package/docs/QUICKSTART.md
CHANGED
|
@@ -103,6 +103,10 @@ await api.addResource('authors', {
|
|
|
103
103
|
await api.resources.authors.createKnexTable();
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
`searchSchema` defines the public filter names your API accepts. Those keys do not need to match database columns or even resource field names. Keep the quickstart mental model simple: `searchSchema` is the resource's public filter contract. For advanced mapping, multi-field search, and custom backend filtering, see [Manipulating and Searching Tables](GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md).
|
|
107
|
+
|
|
108
|
+
If you want to inspect the physical table shape or generate Knex migrations directly from your resource definitions, see [Knex Schema and Migrations](GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md).
|
|
109
|
+
|
|
106
110
|
## Run the program
|
|
107
111
|
|
|
108
112
|
```bash
|
|
@@ -332,7 +336,7 @@ You've successfully set up a basic JSON REST API! This quickstart covered the es
|
|
|
332
336
|
|
|
333
337
|
Check out the [full guide](./GUIDE) to learn about:
|
|
334
338
|
- Advanced relationships (many-to-many, polymorphic)
|
|
335
|
-
-
|
|
339
|
+
- Permission hooks, request auth context, and autofiltering
|
|
336
340
|
- Hooks and middleware
|
|
337
341
|
- Custom validation
|
|
338
342
|
- Pagination strategies
|
package/docs/index.md
CHANGED
|
@@ -27,7 +27,7 @@ JSON REST API is a lightweight, plugin-based framework that makes building REST
|
|
|
27
27
|
|
|
28
28
|
<div class="feature-card">
|
|
29
29
|
<h3>🔌 Plugin Architecture</h3>
|
|
30
|
-
<p>Extend your API with
|
|
30
|
+
<p>Extend your API with focused plugins for transports, dataset scoping, query fields, CORS, and more.</p>
|
|
31
31
|
</div>
|
|
32
32
|
|
|
33
33
|
<div class="feature-card">
|
package/index.js
CHANGED
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
// Core plugins
|
|
12
12
|
export { RestApiPlugin } from './plugins/core/rest-api-plugin.js'
|
|
13
|
+
export { AutoFilterPlugin } from './plugins/core/rest-api-autofilter-plugin.js'
|
|
14
|
+
export { QueryProjectionsPlugin } from './plugins/core/rest-api-query-projections-plugin.js'
|
|
13
15
|
export { FileHandlingPlugin } from './plugins/core/file-handling-plugin.js'
|
|
14
16
|
export { CorsPlugin } from './plugins/core/rest-api-cors-plugin.js'
|
|
15
|
-
export { AccessPlugin } from './plugins/core/rest-api-access.js'
|
|
16
17
|
export { LabelPlugin } from './plugins/core/rest-api-label-plugin.js'
|
|
17
18
|
|
|
18
19
|
// Database plugins
|
|
@@ -21,7 +22,7 @@ export { RestApiAnyapiKnexPlugin } from './plugins/core/rest-api-anyapi-knex-plu
|
|
|
21
22
|
|
|
22
23
|
// Connector plugins
|
|
23
24
|
export { ExpressPlugin } from './plugins/core/connectors/express-plugin.js'
|
|
24
|
-
|
|
25
|
+
export { FastifyPlugin } from './plugins/core/connectors/fastify-plugin.js'
|
|
25
26
|
// Future: export { KoaPlugin } from './plugins/core/connectors/koa-plugin.js';
|
|
26
27
|
|
|
27
28
|
// Storage plugins for file handling
|