json-rest-api 1.0.28 → 2.0.0
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/LICENSE +10 -670
- package/LICENSE-GPL-3.0 +674 -0
- package/LICENSE-MIT +21 -0
- package/README.md +39 -30
- package/docs/API.md +746 -1273
- package/docs/GUIDE/01-getting-started.md +338 -0
- package/docs/GUIDE/02-resources-and-relationships.md +33 -0
- package/docs/GUIDE/03-running-example.md +87 -0
- package/docs/GUIDE/04-creating-and-querying.md +181 -0
- package/docs/GUIDE/05-belongs-to.md +177 -0
- package/docs/GUIDE/06-has-many.md +184 -0
- package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
- package/docs/GUIDE/08-many-to-many.md +184 -0
- package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
- package/docs/GUIDE/10-put-and-patch.md +174 -0
- package/docs/GUIDE/11-relationship-endpoints.md +174 -0
- package/docs/GUIDE/12-field-transformations.md +287 -0
- package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
- package/docs/GUIDE/14-custom-resource-methods.md +125 -0
- package/docs/GUIDE/15-query-projections.md +266 -0
- package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
- package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
- package/docs/GUIDE/18-labels.md +86 -0
- package/docs/GUIDE/19-managed-transactions.md +179 -0
- package/docs/GUIDE/20-transaction-outcomes.md +207 -0
- package/docs/GUIDE/21-schema-and-migrations.md +634 -0
- package/docs/GUIDE/22-version-field-migrations.md +208 -0
- package/docs/GUIDE/23-fastify.md +179 -0
- package/docs/GUIDE/24-cors.md +172 -0
- package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
- package/docs/GUIDE/26-file-uploads.md +278 -0
- package/docs/GUIDE/27-bulk-operations.md +277 -0
- package/docs/GUIDE/28-socketio.md +325 -0
- package/docs/GUIDE/29-writing-plugins.md +278 -0
- package/docs/GUIDE/30-backend-capabilities.md +100 -0
- package/docs/GUIDE/31-positioning.md +181 -0
- package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +90 -31
- package/docs/GUIDE/33-migrating-to-v2.md +3827 -0
- package/docs/GUIDE/index.md +51 -59
- package/docs/QUICKSTART.md +120 -287
- package/docs/architecture.md +75 -0
- package/docs/contributing.md +178 -0
- package/index.d.ts +36 -0
- package/index.js +1 -22
- package/lib/enhanced-logger.js +91 -85
- package/lib/error-context.js +445 -5
- package/lib/error-formatter.js +219 -59
- package/lib/knex-transaction.js +64 -0
- package/lib/logger-types.d.ts +22 -0
- package/lib/missing-package.js +4 -0
- package/lib/rest-api-errors.js +103 -8
- package/lib/runtime/json-rest-api.js +172 -0
- package/lib/transaction-types.d.ts +59 -0
- package/package.json +97 -27
- package/plugins/core/bulk-operations-plugin.js +191 -184
- package/plugins/core/connectors/express-plugin.js +148 -219
- package/plugins/core/connectors/fastify-plugin.js +125 -82
- package/plugins/core/connectors/lib/busboy-detector.js +74 -156
- package/plugins/core/connectors/lib/connector-core.js +144 -20
- package/plugins/core/connectors/lib/formidable-detector.js +63 -120
- package/plugins/core/connectors/lib/http-validators.js +77 -0
- package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
- package/plugins/core/connectors/lib/request-helpers.js +10 -1
- package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
- package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
- package/plugins/core/file-handling-plugin.js +87 -174
- package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
- package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
- package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
- package/plugins/core/lib/anyapi/schema-utils.js +25 -16
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
- package/plugins/core/lib/dbIntrospection.js +228 -21
- package/plugins/core/lib/dbTablesOperations.js +409 -92
- package/plugins/core/lib/fractional-positioning.js +12 -48
- package/plugins/core/lib/querying/identifier-query.js +19 -0
- package/plugins/core/lib/querying/include-query-helpers.js +364 -0
- package/plugins/core/lib/querying/include-to-many.js +428 -0
- package/plugins/core/lib/querying/include-to-one.js +579 -0
- package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
- package/plugins/core/lib/querying/knex-pagination-helpers.js +67 -330
- package/plugins/core/lib/querying/knex-process-includes.js +5 -110
- package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
- package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
- package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
- package/plugins/core/lib/querying/knex-window-queries.js +62 -253
- package/plugins/core/lib/querying/query-builder-utils.js +44 -4
- package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
- package/plugins/core/lib/querying/query-constraint.js +27 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +205 -30
- package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
- package/plugins/core/lib/querying/sort-helpers.js +20 -1
- package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
- package/plugins/core/lib/querying/url-helpers.js +11 -4
- package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
- package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +238 -187
- package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
- package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
- package/plugins/core/lib/querying-writing/field-utils.js +113 -92
- package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
- package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +111 -287
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
- package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
- package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
- package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
- package/plugins/core/lib/querying-writing/request-contracts.js +109 -44
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
- package/plugins/core/lib/querying-writing/response-options.js +35 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
- package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
- package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
- package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
- package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
- package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
- package/plugins/core/lib/storage/storage-adapter.js +142 -62
- package/plugins/core/lib/storage/storage-mapping.js +78 -28
- package/plugins/core/lib/storage/storage-types.d.ts +502 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
- package/plugins/core/lib/writing/relationship-processor.js +94 -158
- package/plugins/core/lib/writing/resource-version.js +172 -0
- package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2509
- package/plugins/core/rest-api-autofilter-plugin.js +17 -19
- package/plugins/core/rest-api-cors-plugin.js +52 -205
- package/plugins/core/rest-api-knex-plugin.js +45 -1069
- package/plugins/core/rest-api-label-plugin.js +25 -38
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
- package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
- package/plugins/core/rest-api-plugin-methods/common.js +291 -385
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
- package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -145
- package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
- package/plugins/core/rest-api-plugin-methods/get.js +38 -69
- package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
- package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
- package/plugins/core/rest-api-plugin-methods/post.js +51 -51
- package/plugins/core/rest-api-plugin-methods/put.js +69 -148
- package/plugins/core/rest-api-plugin-methods/query.js +39 -82
- package/plugins/core/rest-api-plugin-methods/release.js +2 -1
- package/plugins/core/rest-api-plugin.js +32 -46
- package/plugins/core/rest-api-positioning-plugin.js +183 -628
- package/plugins/core/rest-api-query-projections-plugin.js +19 -102
- package/plugins/core/rest-api-row-policy-plugin.js +3 -3
- package/plugins/core/socketio-plugin.js +364 -344
- package/plugins/storage/local-storage.js +40 -36
- package/types/autofilter.d.ts +57 -0
- package/types/bulk-methods.d.ts +63 -0
- package/types/errors.d.ts +118 -0
- package/types/fastify-options.d.ts +19 -0
- package/types/file-detectors.d.ts +33 -0
- package/types/file-storage.d.ts +48 -0
- package/types/hook-context.d.ts +180 -0
- package/types/plugin-options.d.ts +53 -0
- package/types/relationship-methods.d.ts +74 -0
- package/types/representations.d.ts +50 -0
- package/types/resource-methods.d.ts +95 -0
- package/types/resource-schema.d.ts +157 -0
- package/types/row-policy.d.ts +31 -0
- package/types/runtime.d.ts +132 -0
- package/types/transactions.d.ts +21 -0
- package/.claude/agents/library-guide-expert.md +0 -30
- package/.claude/agents/rest-api-internals-expert.md +0 -54
- package/.claude/settings.local.json +0 -70
- package/AGENTS.md +0 -34
- package/CLAUDE.md +0 -160
- package/CRUSH.md +0 -55
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
- package/TODO.todo +0 -13
- package/connectors_ideas/fastify.js +0 -217
- package/connectors_ideas/koa-plugin.js +0 -112
- package/docs/.bundle/config +0 -2
- package/docs/COMPARISON.md +0 -433
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
- package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
- package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
- package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
- package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
- package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1238
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
- package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
- package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
- package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
- package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
- package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
- package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
- package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
- package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
- package/docs/Gemfile +0 -6
- package/docs/Gemfile.lock +0 -308
- package/docs/ONBOARDING.md +0 -315
- package/docs/_config.yml +0 -36
- package/docs/_layouts/default.html +0 -123
- package/docs/apple-touch-icon.svg +0 -4
- package/docs/assets/css/style.scss +0 -392
- package/docs/favicon.svg +0 -4
- package/docs/index.md +0 -164
- package/docs/mini-guides/file-uploads-complete.md +0 -161
- package/eslint.config.js +0 -13
- package/examples/url-override-example.js +0 -137
- package/fixing_plan.md +0 -112
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
- package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
- package/plugins/storage/s3-storage.js +0 -93
- package/quickTest.js +0 -136
- package/scripts/debug-anyapi-review-filter.mjs +0 -63
- package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
- package/scripts/inspect-anyapi-descriptor.mjs +0 -19
- package/scripts/run-docs.js +0 -133
- package/test-debug.js +0 -59
- package/tests/README.md +0 -202
- package/tests/TEST_TEMPLATE.test.js +0 -178
- package/tests/anyapi-basic.test.js +0 -105
- package/tests/anyapi-cursor-pagination.test.js +0 -150
- package/tests/anyapi-custom-idproperty.test.js +0 -163
- package/tests/autofilter.test.js +0 -463
- package/tests/bulk-operations.test.js +0 -657
- package/tests/computed-fields.test.js +0 -586
- package/tests/cors.test.js +0 -834
- package/tests/curl.test.js +0 -467
- package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
- package/tests/custom-id-simplified-post.test.js +0 -75
- package/tests/custom-idproperty-relationships.test.js +0 -932
- package/tests/db-introspection.test.js +0 -521
- package/tests/db-table-operations.test.js +0 -798
- package/tests/fastify-plugin.test.js +0 -184
- package/tests/field-getters.test.js +0 -370
- package/tests/field-setters.test.js +0 -306
- package/tests/file-handling.test.js +0 -118
- package/tests/fixtures/api-configs.js +0 -2509
- package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
- package/tests/helpers/fake-fastify.js +0 -99
- package/tests/helpers/storage-mode.js +0 -65
- package/tests/helpers/test-utils.js +0 -203
- package/tests/http-connectors-parity.test.js +0 -395
- package/tests/id-normalization.test.js +0 -444
- package/tests/include-depth-validation.test.js +0 -331
- package/tests/includes.test.js +0 -427
- package/tests/local-storage.test.js +0 -96
- package/tests/logical-id-write-validation.test.js +0 -151
- package/tests/nested-includes.test.js +0 -617
- package/tests/pagination-cursor-multifield.test.js +0 -643
- package/tests/pagination-enhanced.test.js +0 -563
- package/tests/polymorphic-relationships.test.js +0 -347
- package/tests/polymorphic-simple.test.js +0 -148
- package/tests/positioning-advanced.test.js +0 -692
- package/tests/positioning-extended.test.js +0 -915
- package/tests/positioning-multifilter.test.js +0 -699
- package/tests/positioning.test.js +0 -560
- package/tests/post-commit-hooks.test.js +0 -120
- package/tests/projected-fields.test.js +0 -319
- package/tests/public-exports.test.js +0 -15
- package/tests/put-create-parity.test.js +0 -216
- package/tests/queries.test.js +0 -521
- package/tests/query-limits.test.js +0 -584
- package/tests/relationship-endpoints.test.js +0 -620
- package/tests/relationship-include-storage-adapter.test.js +0 -56
- package/tests/relationships.test.js +0 -681
- package/tests/rest-api.test.js +0 -337
- package/tests/return-record-settings.test.js +0 -184
- package/tests/row-policy.test.js +0 -489
- package/tests/s3-storage.test.js +0 -38
- package/tests/searchschema-knex-behavior.test.js +0 -187
- package/tests/searchschema-merge.test.js +0 -151
- package/tests/socketio.test.js +0 -860
- package/tests/storage-mapping.test.js +0 -362
- package/tests/test-development-guide.md +0 -370
- package/tests/virtual-fields.test.js +0 -404
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
Single Validation Contract TODO
|
|
2
|
-
|
|
3
|
-
Goal
|
|
4
|
-
- Make `json-rest-schema` the single authored validation contract in `json-rest-api`.
|
|
5
|
-
- Keep plain JSON Schema only as a derived transport artifact for connectors.
|
|
6
|
-
- Remove the split between:
|
|
7
|
-
- resource/search validation via `json-rest-schema`
|
|
8
|
-
- hand-written JSON:API/query validators in `plugins/core/lib/querying-writing/payload-validators.js`
|
|
9
|
-
|
|
10
|
-
Current audit status
|
|
11
|
-
- [done] Audit the live validation paths and identify the actual indirection.
|
|
12
|
-
|
|
13
|
-
Root cause
|
|
14
|
-
- Validation is split across three places:
|
|
15
|
-
1. `plugins/core/lib/querying-writing/compile-schemas.js`
|
|
16
|
-
- compiles resource and search schemas with `createSchema(...)`
|
|
17
|
-
2. `plugins/core/lib/querying-writing/payload-validators.js`
|
|
18
|
-
- manually validates JSON:API request envelopes and query parameter objects
|
|
19
|
-
3. `plugins/core/connectors/lib/transport-route-schemas.js`
|
|
20
|
-
- separately builds connector-facing JSON Schemas from `schemaInfo`
|
|
21
|
-
- This duplicates contract meaning across runtime and transport.
|
|
22
|
-
- Route methods still call imperative payload validators before calling
|
|
23
|
-
`schemaInstance.create()`, `schemaInstance.replace()`, or `schemaInstance.patch()`.
|
|
24
|
-
- `setupCommonRequest()` in `plugins/core/rest-api-plugin-methods/common.js`
|
|
25
|
-
also repeats some checks that are already transport-contract concerns.
|
|
26
|
-
|
|
27
|
-
What the neat end state looks like
|
|
28
|
-
- Authored contract:
|
|
29
|
-
- `json-rest-schema` only
|
|
30
|
-
- Derived transport schema:
|
|
31
|
-
- plain JSON Schema, generated from the same compiled contract
|
|
32
|
-
- Runtime write validation:
|
|
33
|
-
- uses the same compiled contract as Fastify pre-validation
|
|
34
|
-
- Remaining imperative checks:
|
|
35
|
-
- only stateful/business checks that are not schema concerns
|
|
36
|
-
- examples: permission checks, record existence, relationship access, complete-replace semantics
|
|
37
|
-
|
|
38
|
-
What should stay imperative
|
|
39
|
-
- `validateRelationshipAccess()` in `plugins/core/rest-api-plugin-methods/common.js`
|
|
40
|
-
- `validateCompleteReplacePayload()` in `plugins/core/rest-api-plugin-methods/common.js`
|
|
41
|
-
- path/body cross-source checks such as URL id vs body id consistency
|
|
42
|
-
- permission and data existence checks
|
|
43
|
-
|
|
44
|
-
What should stop existing
|
|
45
|
-
- `validateGetPayload()`
|
|
46
|
-
- `validateQueryPayload()`
|
|
47
|
-
- `validatePostPayload()`
|
|
48
|
-
- `validatePutPayload()`
|
|
49
|
-
- `validatePatchPayload()`
|
|
50
|
-
- duplicate route/body/query syntax checks spread across route methods and `setupCommonRequest()`
|
|
51
|
-
|
|
52
|
-
Work list
|
|
53
|
-
|
|
54
|
-
1. [done] Define one compiled request-contract surface for resource `get/query/post/put/patch`.
|
|
55
|
-
Target files:
|
|
56
|
-
- `plugins/core/lib/querying-writing/compile-schemas.js`
|
|
57
|
-
- `plugins/core/connectors/lib/transport-route-schemas.js`
|
|
58
|
-
Deliverables:
|
|
59
|
-
- compile request contracts once per scope
|
|
60
|
-
- store them on `scope.vars.schemaInfo` or an adjacent compiled-contract object
|
|
61
|
-
- separate:
|
|
62
|
-
- write document contracts (`post`, `put`, `patch`)
|
|
63
|
-
- query/get contracts (`get`, `query`)
|
|
64
|
-
- relationship route contracts
|
|
65
|
-
Status:
|
|
66
|
-
- resource route contracts now compile once in `request-contracts.js`
|
|
67
|
-
- relationship route contracts are still separate and remain pending work
|
|
68
|
-
|
|
69
|
-
2. [done] Replace manual write-document validation with compiled schema contracts.
|
|
70
|
-
Target files:
|
|
71
|
-
- `plugins/core/lib/querying-writing/payload-validators.js`
|
|
72
|
-
- `plugins/core/rest-api-plugin-methods/post.js`
|
|
73
|
-
- `plugins/core/rest-api-plugin-methods/put.js`
|
|
74
|
-
- `plugins/core/rest-api-plugin-methods/patch.js`
|
|
75
|
-
Deliverables:
|
|
76
|
-
- one compiled JSON:API document contract per write mode
|
|
77
|
-
- `data.type` constrained to the scope name inside the contract
|
|
78
|
-
- `data.id` required/optional according to mode
|
|
79
|
-
- `attributes` contract derived from `schemaInstance.toJsonSchema({ mode })`
|
|
80
|
-
- relationship identifier contracts derived from `schemaRelationships` and `belongsTo` metadata
|
|
81
|
-
- `included` rules expressed once in the contract rather than repeated manually
|
|
82
|
-
|
|
83
|
-
3. [done] Replace manual GET/query parameter validation with compiled schema contracts.
|
|
84
|
-
Target files:
|
|
85
|
-
- `plugins/core/lib/querying-writing/payload-validators.js`
|
|
86
|
-
- `plugins/core/rest-api-plugin-methods/get.js`
|
|
87
|
-
- `plugins/core/rest-api-plugin-methods/query.js`
|
|
88
|
-
Deliverables:
|
|
89
|
-
- a compiled `get` contract for:
|
|
90
|
-
- `id`
|
|
91
|
-
- `queryParams.include`
|
|
92
|
-
- `queryParams.fields`
|
|
93
|
-
- a compiled `query` contract for:
|
|
94
|
-
- `include`
|
|
95
|
-
- `fields`
|
|
96
|
-
- `filters`
|
|
97
|
-
- `sort`
|
|
98
|
-
- `page`
|
|
99
|
-
- include-depth validation and sortable-field restrictions represented in the compiled contract, not duplicated in ad hoc code
|
|
100
|
-
Notes:
|
|
101
|
-
- `searchSchemaInstance` should remain the value contract for `filters`
|
|
102
|
-
- the query contract should validate the envelope/shape, not duplicate filter semantics
|
|
103
|
-
|
|
104
|
-
4. [done] Collapse Fastify pre-validation and in-process validation onto the same source for resource write routes.
|
|
105
|
-
Target files:
|
|
106
|
-
- `plugins/core/connectors/lib/transport-route-schemas.js`
|
|
107
|
-
- `plugins/core/connectors/fastify-plugin.js`
|
|
108
|
-
- route methods in `plugins/core/rest-api-plugin-methods/`
|
|
109
|
-
Deliverables:
|
|
110
|
-
- Fastify consumes transport JSON Schema exported from the compiled request contract
|
|
111
|
-
- route methods consume the same compiled contract directly for runtime validation
|
|
112
|
-
- no second hand-written envelope contract path
|
|
113
|
-
|
|
114
|
-
5. [done] Shrink `setupCommonRequest()` to non-schema responsibilities.
|
|
115
|
-
Target file:
|
|
116
|
-
- `plugins/core/rest-api-plugin-methods/common.js`
|
|
117
|
-
Deliverables:
|
|
118
|
-
- keep simplified-mode conversion, transaction setup, context wiring
|
|
119
|
-
- keep stateful/business checks only
|
|
120
|
-
- remove syntax/envelope checks that belong in the compiled contract
|
|
121
|
-
- keep only cross-input checks that a single schema cannot express cleanly
|
|
122
|
-
|
|
123
|
-
6. [done] Delete `payload-validators.js`.
|
|
124
|
-
Target file:
|
|
125
|
-
- `plugins/core/lib/querying-writing/payload-validators.js`
|
|
126
|
-
Deliverables:
|
|
127
|
-
- no route method imports it anymore
|
|
128
|
-
- helper logic worth keeping is either:
|
|
129
|
-
- absorbed into compiled contracts
|
|
130
|
-
- or moved into narrowly named stateful helpers
|
|
131
|
-
|
|
132
|
-
7. [done] Tighten tests around the single-contract flow.
|
|
133
|
-
Target areas:
|
|
134
|
-
- `tests/fastify-plugin.test.js`
|
|
135
|
-
- route method coverage exercised by the existing REST suites
|
|
136
|
-
- add one focused contract test suite if needed
|
|
137
|
-
Deliverables:
|
|
138
|
-
- prove Fastify pre-validation and runtime validation reject the same bad inputs
|
|
139
|
-
- cover:
|
|
140
|
-
- wrong `data.type`
|
|
141
|
-
- missing/invalid `data.id`
|
|
142
|
-
- invalid relationships
|
|
143
|
-
- invalid query/include/page/sort shapes
|
|
144
|
-
- verify there is no drift between transport schema and runtime schema behavior
|
|
145
|
-
|
|
146
|
-
8. [done] Proof cleanup.
|
|
147
|
-
Deliverables:
|
|
148
|
-
- `rg` proof that route methods no longer import `payload-validators.js`
|
|
149
|
-
- `rg` proof that `validateGetPayload`, `validateQueryPayload`, `validatePostPayload`,
|
|
150
|
-
`validatePutPayload`, and `validatePatchPayload` are gone
|
|
151
|
-
- `npm test`
|
|
152
|
-
|
|
153
|
-
Current state
|
|
154
|
-
- Resource `get/query/post/put/patch` now use one compiled contract source.
|
|
155
|
-
- Fastify transport schemas for those resource routes are derived from the same compiled contract.
|
|
156
|
-
- `payload-validators.js` is deleted.
|
|
157
|
-
- `npm test` passes.
|
|
158
|
-
- The main remaining simplification is the separate relationship-route contract path.
|
|
159
|
-
|
|
160
|
-
File map for the next implementation pass
|
|
161
|
-
- Remaining relationship-route cleanup:
|
|
162
|
-
- `plugins/core/rest-api-plugin-methods/post-relationship.js`
|
|
163
|
-
- `plugins/core/rest-api-plugin-methods/patch-relationship.js`
|
|
164
|
-
- `plugins/core/rest-api-plugin-methods/delete-relationship.js`
|
|
165
|
-
- Transport schema generator to reuse, not duplicate:
|
|
166
|
-
- `plugins/core/connectors/lib/transport-route-schemas.js`
|
|
167
|
-
|
|
168
|
-
Explicit non-goals
|
|
169
|
-
- Do not move permission checks into schemas.
|
|
170
|
-
- Do not move DB existence checks into schemas.
|
|
171
|
-
- Do not turn `searchSchema` into a generic filter DSL.
|
|
172
|
-
- Do not add a compatibility layer that preserves both manual validators and compiled contracts.
|
package/TODO.todo
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
Potential Enhancements
|
|
2
|
-
|
|
3
|
-
1. Provider Priority: Consider adding a "primary_provider" field to handle users who authenticate through multiple providers.
|
|
4
|
-
2. Field Cleanup: Maybe add a helper to remove provider fields when a user unlinks that provider.
|
|
5
|
-
3. Migration Safety: The automatic column creation via RestApiKnexPlugin is convenient, but you might want provider plugins to check if their
|
|
6
|
-
fields already exist before extending.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
☐ Delete "Creating Custom Storage Plugins for JSON REST API", make an op plugin instead.
|
|
10
|
-
☐ Improve the look of the CSS, especially black and long code fragments, title fonts
|
|
11
|
-
☐ Check manually that the API is OK
|
|
12
|
-
☐ Check that the guide has full coverage of features, map the missing parts
|
|
13
|
-
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* http-plugin-fastify.js
|
|
3
|
-
* This plugin for Hooked API provides a high-performance HTTP layer using the Fastify framework.
|
|
4
|
-
* It automatically generates JSON:API compliant RESTful routes and schemas for each scope.
|
|
5
|
-
*
|
|
6
|
-
* You'll need to install dependencies: npm install fastify
|
|
7
|
-
*/
|
|
8
|
-
import { HookedApiError } from './hooked-api.js'
|
|
9
|
-
import { handleFastifyApiError } from './error-handler-fastify.js'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* **UPGRADED:** Automatically generates a comprehensive Fastify schema object that conforms
|
|
13
|
-
* to the full JSON:API specification, including relationships, links, and meta.
|
|
14
|
-
* @param {string} scopeName - The name of the resource type (e.g., 'articles').
|
|
15
|
-
* @param {object} scopeOptions - The full options object for the scope.
|
|
16
|
-
* @returns {object} A complete Fastify schema for all CRUD routes.
|
|
17
|
-
*/
|
|
18
|
-
function _generateFastifySchema (scopeName, scopeOptions = {}) {
|
|
19
|
-
const appSchema = scopeOptions.schema || {}
|
|
20
|
-
const relationshipsSchema = scopeOptions.relationships || {}
|
|
21
|
-
|
|
22
|
-
// --- Reusable Schema Components ---
|
|
23
|
-
const metaObject = { type: 'object', additionalProperties: true }
|
|
24
|
-
const linksObject = {
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
self: { type: 'string', format: 'uri-reference' },
|
|
28
|
-
related: { type: 'string', format: 'uri-reference' },
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
const resourceIdentifierObject = {
|
|
32
|
-
type: 'object',
|
|
33
|
-
required: ['type', 'id'],
|
|
34
|
-
properties: {
|
|
35
|
-
type: { type: 'string' },
|
|
36
|
-
id: { type: 'string' }
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// --- Build Attribute Properties from simple schema ---
|
|
41
|
-
const attributeProperties = {}
|
|
42
|
-
const requiredAttributes = []
|
|
43
|
-
for (const [key, value] of Object.entries(appSchema)) {
|
|
44
|
-
let jsonSchemaType = 'string'
|
|
45
|
-
if (value.type === 'number') jsonSchemaType = 'number'
|
|
46
|
-
if (value.type === 'boolean') jsonSchemaType = 'boolean'
|
|
47
|
-
|
|
48
|
-
attributeProperties[key] = { type: jsonSchemaType }
|
|
49
|
-
if (value.format) attributeProperties[key].format = value.format
|
|
50
|
-
if (value.required) requiredAttributes.push(key)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// --- Build Relationship Properties ---
|
|
54
|
-
const relationshipProperties = {}
|
|
55
|
-
for (const [key, value] of Object.entries(relationshipsSchema)) {
|
|
56
|
-
const isToMany = value.type === 'hasMany'
|
|
57
|
-
relationshipProperties[key] = {
|
|
58
|
-
type: 'object',
|
|
59
|
-
properties: {
|
|
60
|
-
links: linksObject,
|
|
61
|
-
data: isToMany
|
|
62
|
-
? { type: 'array', items: resourceIdentifierObject }
|
|
63
|
-
: resourceIdentifierObject
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// --- Define the core Resource Object schema ---
|
|
69
|
-
const resourceObject = {
|
|
70
|
-
type: 'object',
|
|
71
|
-
required: ['type', 'id'],
|
|
72
|
-
properties: {
|
|
73
|
-
id: { type: 'string' },
|
|
74
|
-
type: { type: 'string', const: scopeName },
|
|
75
|
-
attributes: {
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: attributeProperties
|
|
78
|
-
},
|
|
79
|
-
relationships: {
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: relationshipProperties
|
|
82
|
-
},
|
|
83
|
-
links: linksObject
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// --- Define the full top-level JSON:API Document ---
|
|
88
|
-
const singleDocument = {
|
|
89
|
-
type: 'object',
|
|
90
|
-
properties: {
|
|
91
|
-
data: resourceObject,
|
|
92
|
-
included: { type: 'array', items: { type: 'object' } }, // Generic included for simplicity
|
|
93
|
-
links: linksObject,
|
|
94
|
-
meta: metaObject
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const collectionDocument = {
|
|
98
|
-
type: 'object',
|
|
99
|
-
properties: {
|
|
100
|
-
data: { type: 'array', items: resourceObject },
|
|
101
|
-
included: { type: 'array', items: { type: 'object' } },
|
|
102
|
-
links: { ...linksObject, properties: { ...linksObject.properties, next: { type: 'string' }, prev: { type: 'string' } } },
|
|
103
|
-
meta: metaObject
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// --- Build the final schema for each route ---
|
|
108
|
-
return {
|
|
109
|
-
post: {
|
|
110
|
-
body: {
|
|
111
|
-
type: 'object',
|
|
112
|
-
required: ['data'],
|
|
113
|
-
properties: {
|
|
114
|
-
data: {
|
|
115
|
-
type: 'object',
|
|
116
|
-
required: ['type', 'attributes'],
|
|
117
|
-
properties: {
|
|
118
|
-
type: { type: 'string', const: scopeName },
|
|
119
|
-
attributes: {
|
|
120
|
-
type: 'object',
|
|
121
|
-
required: requiredAttributes,
|
|
122
|
-
properties: attributeProperties
|
|
123
|
-
},
|
|
124
|
-
relationships: {
|
|
125
|
-
type: 'object',
|
|
126
|
-
properties: relationshipProperties
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
response: { 201: singleDocument }
|
|
133
|
-
},
|
|
134
|
-
get: {
|
|
135
|
-
response: { 200: singleDocument }
|
|
136
|
-
},
|
|
137
|
-
query: {
|
|
138
|
-
response: { 200: collectionDocument }
|
|
139
|
-
},
|
|
140
|
-
patch: {
|
|
141
|
-
body: { /* A more complex partial schema would be needed for full validation */ },
|
|
142
|
-
response: { 200: singleDocument }
|
|
143
|
-
},
|
|
144
|
-
put: {
|
|
145
|
-
body: { /* Similar to POST body */ },
|
|
146
|
-
response: { 200: singleDocument }
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export const HttpFastifyPlugin = {
|
|
152
|
-
name: 'http-fastify',
|
|
153
|
-
|
|
154
|
-
install (context, api) {
|
|
155
|
-
const { pluginOptions, log } = context
|
|
156
|
-
const httpOptions = pluginOptions.http || {}
|
|
157
|
-
const { app, prefix = '/api' } = httpOptions
|
|
158
|
-
|
|
159
|
-
if (!app) {
|
|
160
|
-
throw new HookedApiError(
|
|
161
|
-
"The 'http-fastify' plugin requires a Fastify 'app' instance to be passed in the options. Example: api.use(HttpFastifyPlugin, { http: { app: myFastifyApp } })",
|
|
162
|
-
'CONFIGURATION_ERROR'
|
|
163
|
-
)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
log.info(`Fastify HTTP plugin installed. Routes will be prefixed with '${prefix}'.`)
|
|
167
|
-
|
|
168
|
-
const _createFastifyHandler = (methodName) => {
|
|
169
|
-
return async (request, reply) => {
|
|
170
|
-
const { scopeName, id } = request.params
|
|
171
|
-
const apiParams = {
|
|
172
|
-
id,
|
|
173
|
-
inputRecord: request.body,
|
|
174
|
-
queryParams: request.query,
|
|
175
|
-
}
|
|
176
|
-
log.debug(`Fastify request for ${scopeName}.${methodName}`, { id, query: apiParams.queryParams })
|
|
177
|
-
const result = await api.scopes[scopeName][methodName](apiParams)
|
|
178
|
-
switch (methodName) {
|
|
179
|
-
case 'post':
|
|
180
|
-
reply.code(201).send(result)
|
|
181
|
-
break
|
|
182
|
-
case 'delete':
|
|
183
|
-
reply.code(204).send()
|
|
184
|
-
break
|
|
185
|
-
default:
|
|
186
|
-
reply.code(200).send(result)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const _createScopePlugin = (scopeName, scopeOptions) => {
|
|
192
|
-
const fastifySchema = scopeOptions.fastifySchema || _generateFastifySchema(scopeName, scopeOptions)
|
|
193
|
-
|
|
194
|
-
return async (fastifyInstance) => {
|
|
195
|
-
log.info(`Creating Fastify HTTP routes for scope: '${scopeName}'`)
|
|
196
|
-
fastifyInstance.get(`/${scopeName}`, { schema: fastifySchema.query }, _createFastifyHandler('query'))
|
|
197
|
-
fastifyInstance.get(`/${scopeName}/:id`, { schema: fastifySchema.get }, _createFastifyHandler('get'))
|
|
198
|
-
fastifyInstance.post(`/${scopeName}`, { schema: fastifySchema.post }, _createFastifyHandler('post'))
|
|
199
|
-
fastifyInstance.put(`/${scopeName}/:id`, { schema: fastifySchema.put }, _createFastifyHandler('put'))
|
|
200
|
-
fastifyInstance.patch(`/${scopeName}/:id`, { schema: fastifySchema.patch }, _createFastifyHandler('patch'))
|
|
201
|
-
fastifyInstance.delete(`/${scopeName}/:id`, { schema: fastifySchema.delete }, _createFastifyHandler('delete'))
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const originalAddScope = api.addScope
|
|
206
|
-
|
|
207
|
-
api.addScope = (name, options, extras) => {
|
|
208
|
-
const result = originalAddScope.call(api, name, options, extras)
|
|
209
|
-
app.register(_createScopePlugin(name, options), { prefix })
|
|
210
|
-
return result
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
app.setErrorHandler((error, request, reply) => {
|
|
214
|
-
handleFastifyApiError(error, request, reply, log)
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* http-plugin-koa.js
|
|
3
|
-
* This plugin for Hooked API provides a lightweight HTTP layer using the Koa.js framework.
|
|
4
|
-
* It automatically generates JSON:API compliant RESTful routes for each scope using `koa-router`.
|
|
5
|
-
*
|
|
6
|
-
* It assumes you have `koa-bodyparser` installed and used before this plugin.
|
|
7
|
-
* You'll need to install dependencies: npm install koa koa-router koa-bodyparser qs
|
|
8
|
-
*/
|
|
9
|
-
import KoaRouter from 'koa-router'
|
|
10
|
-
import qs from 'qs' // The same query string parser Express uses
|
|
11
|
-
import { HookedApiError } from './hooked-api.js'
|
|
12
|
-
import { handleKoaApiError } from './error-handler-koa.js'
|
|
13
|
-
|
|
14
|
-
export const HttpKoaPlugin = {
|
|
15
|
-
name: 'http-koa',
|
|
16
|
-
|
|
17
|
-
install (context, api) {
|
|
18
|
-
const { pluginOptions, log } = context
|
|
19
|
-
const httpOptions = pluginOptions.http || {}
|
|
20
|
-
const { app, prefix = '/api' } = httpOptions
|
|
21
|
-
|
|
22
|
-
if (!app) {
|
|
23
|
-
throw new HookedApiError(
|
|
24
|
-
"The 'http-koa' plugin requires a Koa 'app' instance to be passed in the options. Example: api.use(HttpKoaPlugin, { http: { app: myKoaApp } })",
|
|
25
|
-
'CONFIGURATION_ERROR'
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Create a router instance for our API routes
|
|
30
|
-
const router = new KoaRouter({ prefix })
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Creates a generic Koa middleware for a specific API method.
|
|
34
|
-
* @param {string} methodName - The name of the scope method to call (e.g., 'get', 'query').
|
|
35
|
-
* @returns {Function} An async Koa middleware function.
|
|
36
|
-
*/
|
|
37
|
-
const _createKoaHandler = (methodName) => {
|
|
38
|
-
return async (ctx) => {
|
|
39
|
-
const { scopeName, id } = ctx.params
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
// 1. Translate Koa ctx into API method params
|
|
43
|
-
const apiParams = {}
|
|
44
|
-
|
|
45
|
-
if (['get', 'put', 'patch', 'delete'].includes(methodName)) {
|
|
46
|
-
apiParams.id = id
|
|
47
|
-
}
|
|
48
|
-
if (['post', 'put', 'patch'].includes(methodName)) {
|
|
49
|
-
// Assumes koa-bodyparser is used
|
|
50
|
-
apiParams.inputRecord = ctx.request.body
|
|
51
|
-
}
|
|
52
|
-
// Use qs to properly parse nested query objects
|
|
53
|
-
apiParams.queryParams = ctx.querystring ? qs.parse(ctx.querystring) : {}
|
|
54
|
-
|
|
55
|
-
log.debug(`Koa request for ${scopeName}.${methodName}`, { id, query: apiParams.queryParams })
|
|
56
|
-
|
|
57
|
-
// 2. Execute the corresponding API method
|
|
58
|
-
const result = await api.scopes[scopeName][methodName](apiParams)
|
|
59
|
-
|
|
60
|
-
// 3. Set the successful Koa response
|
|
61
|
-
switch (methodName) {
|
|
62
|
-
case 'post':
|
|
63
|
-
ctx.status = 201
|
|
64
|
-
ctx.body = result
|
|
65
|
-
break
|
|
66
|
-
case 'delete':
|
|
67
|
-
ctx.status = 204
|
|
68
|
-
// No body for 204
|
|
69
|
-
break
|
|
70
|
-
default:
|
|
71
|
-
ctx.status = 200
|
|
72
|
-
ctx.body = result
|
|
73
|
-
}
|
|
74
|
-
} catch (error) {
|
|
75
|
-
// 4. Handle any errors thrown by the API
|
|
76
|
-
handleKoaApiError(error, ctx, log)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Creates all the standard RESTful routes for a given scope on the router.
|
|
83
|
-
* @param {string} scopeName - The name of the scope to create routes for.
|
|
84
|
-
*/
|
|
85
|
-
const _createRoutesForScope = (scopeName) => {
|
|
86
|
-
const collectionPath = `/${scopeName}`
|
|
87
|
-
const resourcePath = `${collectionPath}/:id`
|
|
88
|
-
|
|
89
|
-
log.info(`Creating Koa HTTP routes for scope: '${scopeName}'`)
|
|
90
|
-
|
|
91
|
-
router.get(collectionPath, _createKoaHandler('query'))
|
|
92
|
-
router.get(resourcePath, _createKoaHandler('get'))
|
|
93
|
-
router.post(collectionPath, _createKoaHandler('post'))
|
|
94
|
-
router.put(resourcePath, _createKoaHandler('put'))
|
|
95
|
-
router.patch(resourcePath, _createKoaHandler('patch'))
|
|
96
|
-
router.del(resourcePath, _createKoaHandler('delete')) // .del is koa-router's alias for delete
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// --- Main Logic: Wrap `addScope` to automate route creation ---
|
|
100
|
-
const originalAddScope = api.addScope
|
|
101
|
-
|
|
102
|
-
api.addScope = (name, options, extras) => {
|
|
103
|
-
const result = originalAddScope.call(api, name, options, extras)
|
|
104
|
-
_createRoutesForScope(name)
|
|
105
|
-
return result
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Apply the router middleware to the Koa app
|
|
109
|
-
app.use(router.routes()).use(router.allowedMethods())
|
|
110
|
-
log.info(`Koa router installed with prefix '${prefix}'.`)
|
|
111
|
-
}
|
|
112
|
-
}
|
package/docs/.bundle/config
DELETED