json-rest-api 1.0.29 → 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 +744 -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} +74 -30
- 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 -177
- 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 +48 -317
- 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 +134 -37
- package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
- package/plugins/core/lib/querying/sort-helpers.js +13 -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 +179 -194
- 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 +100 -290
- 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 +93 -38
- 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 +128 -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 -2485
- 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 -1077
- 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 -395
- 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 -148
- 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 +36 -68
- 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 +37 -81
- 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 -1247
- 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 -148
- 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 -155
- package/tests/fixtures/api-configs.js +0 -2566
- 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-boundaries.test.js +0 -154
- package/tests/pagination-contract.test.js +0 -122
- package/tests/pagination-cursor-multifield.test.js +0 -641
- 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/temporal-boundaries.test.js +0 -208
- package/tests/test-development-guide.md +0 -370
- package/tests/virtual-fields.test.js +0 -404
package/docs/ONBOARDING.md
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
# Developer Contribution Guide
|
|
2
|
-
|
|
3
|
-
This guide is for developers who want to contribute to the json-rest-api codebase and understand its internal architecture.
|
|
4
|
-
|
|
5
|
-
## Introduction
|
|
6
|
-
|
|
7
|
-
json-rest-api is NOT a standalone library - it's a collection of plugins for [hooked-api](https://github.com/mercmobily/hooked-api). Each plugin extends the API with specific functionality by:
|
|
8
|
-
|
|
9
|
-
- Adding methods to the API or to resources
|
|
10
|
-
- Running hooks at strategic points
|
|
11
|
-
- Listening to global events
|
|
12
|
-
|
|
13
|
-
## What Each Plugin Does
|
|
14
|
-
|
|
15
|
-
### Core Pattern
|
|
16
|
-
Every plugin follows this structure:
|
|
17
|
-
```javascript
|
|
18
|
-
export const SomePlugin = {
|
|
19
|
-
name: 'plugin-name',
|
|
20
|
-
dependencies: ['other-plugin'], // optional
|
|
21
|
-
|
|
22
|
-
install({ helpers, addScopeMethod, addApiMethod, vars, addHook, runHooks, on, /* ... */ }) {
|
|
23
|
-
// 1. Add methods (API-level or resource-level)
|
|
24
|
-
// 2. Add hooks to extend behavior
|
|
25
|
-
// 3. Listen to events from other plugins
|
|
26
|
-
// 4. Set up helpers for other plugins to use
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Key Plugins
|
|
32
|
-
- **RestApiPlugin**: Defines REST methods (get, post, patch, delete) and core hooks
|
|
33
|
-
- **RestApiKnexPlugin**: Implements data helpers used by REST methods
|
|
34
|
-
- **ExpressPlugin**: Creates HTTP endpoints by listening to route events
|
|
35
|
-
|
|
36
|
-
## Resources vs Scopes
|
|
37
|
-
|
|
38
|
-
An important concept: `api.resources` is just an alias to `api.scopes`:
|
|
39
|
-
|
|
40
|
-
```javascript
|
|
41
|
-
// In rest-api-plugin.js
|
|
42
|
-
setScopeAlias('resources', 'addResource');
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
This means:
|
|
46
|
-
- `api.resources` === `api.scopes`
|
|
47
|
-
- `api.addResource()` === `api.addScope()`
|
|
48
|
-
- "Resource" is REST terminology, "Scope" is hooked-api terminology
|
|
49
|
-
- They're the same thing!
|
|
50
|
-
|
|
51
|
-
## Global Hooks Run by the Library
|
|
52
|
-
|
|
53
|
-
### Core hooked-api Hooks
|
|
54
|
-
|
|
55
|
-
The hooked-api framework provides several system-level hooks that plugins can use:
|
|
56
|
-
|
|
57
|
-
1. **scope:added** - Fired when a new scope (resource) is added via `api.addScope()` or `api.addResource()`
|
|
58
|
-
- This is the most important hook for plugins that need to set up resources
|
|
59
|
-
- Receives context with `scopeName`, `scopeOptions`, and `vars`
|
|
60
|
-
- Used by rest-api-plugin to compile schemas, validate relationships, and register routes
|
|
61
|
-
|
|
62
|
-
3. **plugin:installed** - Fired after each plugin is installed
|
|
63
|
-
- Receives the plugin name and configuration
|
|
64
|
-
|
|
65
|
-
4. **error** - Global error handling hook
|
|
66
|
-
- Allows plugins to intercept and handle errors
|
|
67
|
-
|
|
68
|
-
Example of using scope:added:
|
|
69
|
-
```javascript
|
|
70
|
-
// This is how rest-api-plugin uses scope:added to set up resources
|
|
71
|
-
addHook('scope:added', 'compileResourceSchemas', {}, async ({ context, scopes, runHooks }) => {
|
|
72
|
-
// context.scopeName contains the resource name
|
|
73
|
-
// This runs for EVERY resource added to the API
|
|
74
|
-
const scope = scopes[context.scopeName];
|
|
75
|
-
await compileSchemas(scope, { context, runHooks });
|
|
76
|
-
});
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Understanding vars and helpers in hooked-api
|
|
80
|
-
|
|
81
|
-
### vars
|
|
82
|
-
The `vars` object is a cascading configuration system:
|
|
83
|
-
- Set at global level: `vars.someValue = 'default'`
|
|
84
|
-
- Override at scope level: `scope.vars.someValue = 'specific'`
|
|
85
|
-
- Values cascade: scope → global → undefined
|
|
86
|
-
|
|
87
|
-
Example from rest-api-plugin:
|
|
88
|
-
```javascript
|
|
89
|
-
vars.queryDefaultLimit = restApiOptions.queryDefaultLimit || DEFAULT_QUERY_LIMIT
|
|
90
|
-
vars.queryMaxLimit = restApiOptions.queryMaxLimit || DEFAULT_MAX_QUERY_LIMIT
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### helpers
|
|
94
|
-
Helpers are shared functions that plugins provide for others to use:
|
|
95
|
-
- Pure functions (no side effects)
|
|
96
|
-
- Set by one plugin, used by others
|
|
97
|
-
- Example: Knex plugin provides `helpers.dataGet`, REST plugin uses it
|
|
98
|
-
|
|
99
|
-
```javascript
|
|
100
|
-
// Knex plugin sets:
|
|
101
|
-
helpers.dataGet = async ({ scopeName, context }) => { /* ... */ }
|
|
102
|
-
|
|
103
|
-
// REST plugin uses:
|
|
104
|
-
context.record = await helpers.dataGet({ scopeName, context, runHooks })
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Plugin Event Listening and Method Definition
|
|
108
|
-
|
|
109
|
-
Plugins interact through three mechanisms:
|
|
110
|
-
|
|
111
|
-
### 1. Global API Methods
|
|
112
|
-
```javascript
|
|
113
|
-
// Define
|
|
114
|
-
addApiMethod('addRoute', addRouteMethod);
|
|
115
|
-
|
|
116
|
-
// Use
|
|
117
|
-
api.addRoute({ method: 'GET', path: '/users', handler: myHandler })
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### 2. Resource Methods
|
|
121
|
-
```javascript
|
|
122
|
-
// Define
|
|
123
|
-
addScopeMethod('get', getMethod);
|
|
124
|
-
|
|
125
|
-
// Use
|
|
126
|
-
api.resources.users.get({ id: '123' })
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### 3. Event Listening
|
|
130
|
-
```javascript
|
|
131
|
-
// Listen
|
|
132
|
-
on('route:added', ({ route, scopeName }) => {
|
|
133
|
-
console.log(`Route added for ${scopeName}`)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
// Emit (done internally by hooked-api)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Relationship Between rest-api-plugin and rest-api-knex-plugin
|
|
140
|
-
|
|
141
|
-
The relationship is complementary:
|
|
142
|
-
|
|
143
|
-
### rest-api-plugin.js
|
|
144
|
-
- Defines the REST API interface (methods like get, post, patch, delete)
|
|
145
|
-
- Orchestrates the request flow through hooks
|
|
146
|
-
- Validates inputs
|
|
147
|
-
- Transforms between formats (JSON:API ↔ simplified)
|
|
148
|
-
- Does NOT touch the database
|
|
149
|
-
|
|
150
|
-
### rest-api-knex-plugin.js
|
|
151
|
-
- Implements the data helpers that rest-api-plugin calls
|
|
152
|
-
- Provides: `dataGet`, `dataPost`, `dataPatch`, `dataDelete`, etc.
|
|
153
|
-
- Handles all database operations
|
|
154
|
-
- Transforms between database format and JSON:API
|
|
155
|
-
- Manages relationships at the database level
|
|
156
|
-
|
|
157
|
-
Example flow:
|
|
158
|
-
```javascript
|
|
159
|
-
// In rest-api-plugin get method:
|
|
160
|
-
await runHooks('beforeDataGet');
|
|
161
|
-
context.record = await helpers.dataGet({ scopeName, context, runHooks });
|
|
162
|
-
await runHooks('afterDataGet');
|
|
163
|
-
|
|
164
|
-
// dataGet is provided by rest-api-knex-plugin
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## API Methods Run Hooks for Extensibility
|
|
168
|
-
|
|
169
|
-
Every REST method (get, post, patch, delete) follows this pattern:
|
|
170
|
-
|
|
171
|
-
```javascript
|
|
172
|
-
async function someMethod({ params, context, runHooks, /* ... */ }) {
|
|
173
|
-
// 1. Validate
|
|
174
|
-
validatePayload(params);
|
|
175
|
-
|
|
176
|
-
// 2. Check permissions
|
|
177
|
-
await scope.checkPermissions({ method: 'get', /* ... */ });
|
|
178
|
-
|
|
179
|
-
// 3. Run before hooks
|
|
180
|
-
await runHooks('beforeData');
|
|
181
|
-
await runHooks('beforeDataGet');
|
|
182
|
-
|
|
183
|
-
// 4. Perform operation (via helper)
|
|
184
|
-
context.record = await helpers.dataGet({ /* ... */ });
|
|
185
|
-
|
|
186
|
-
// 5. Run after hooks
|
|
187
|
-
await runHooks('enrichRecord');
|
|
188
|
-
|
|
189
|
-
// 6. Run finish hooks
|
|
190
|
-
await runHooks('finish');
|
|
191
|
-
await runHooks('finishGet');
|
|
192
|
-
|
|
193
|
-
return context.record;
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
This allows plugins to hook into any phase of the request.
|
|
198
|
-
|
|
199
|
-
## How addRoute() Works in Detail
|
|
200
|
-
|
|
201
|
-
The `addRoute` implementation demonstrates the plugin communication pattern perfectly:
|
|
202
|
-
|
|
203
|
-
### 1. API Method Definition (rest-api-plugin)
|
|
204
|
-
```javascript
|
|
205
|
-
// In rest-api-plugin.js
|
|
206
|
-
addApiMethod('addRoute', addRouteMethod);
|
|
207
|
-
|
|
208
|
-
// In add-route.js
|
|
209
|
-
export default async ({ params, context, runHooks }) => {
|
|
210
|
-
const { method, path, handler } = params;
|
|
211
|
-
|
|
212
|
-
// Validate
|
|
213
|
-
if (!method || !path || !handler) {
|
|
214
|
-
throw new ValidationError('Route requires method, path, and handler');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Copy params to context for hooks
|
|
218
|
-
Object.assign(context, params);
|
|
219
|
-
|
|
220
|
-
// Run the hook - this notifies all listeners
|
|
221
|
-
await runHooks('addRoute');
|
|
222
|
-
|
|
223
|
-
return { registered: true, method, path };
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### 2. Route Registration (registerScopeRoutes hook)
|
|
228
|
-
When a resource is added, routes are automatically registered:
|
|
229
|
-
```javascript
|
|
230
|
-
// In register-scope-routes.js
|
|
231
|
-
await api.addRoute({
|
|
232
|
-
method: 'GET',
|
|
233
|
-
path: `${basePath}/${scopeName}`,
|
|
234
|
-
handler: createRouteHandler(scopeName, 'query')
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
await api.addRoute({
|
|
238
|
-
method: 'GET',
|
|
239
|
-
path: `${basePath}/${scopeName}/:id`,
|
|
240
|
-
handler: createRouteHandler(scopeName, 'get')
|
|
241
|
-
});
|
|
242
|
-
// ... etc for POST, PUT, PATCH, DELETE
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### 3. Transport Implementation (express-plugin)
|
|
246
|
-
The Express plugin listens for the addRoute hook:
|
|
247
|
-
```javascript
|
|
248
|
-
// In express-plugin.js
|
|
249
|
-
addHook('addRoute', 'expressRouteCreator', {}, async ({ context }) => {
|
|
250
|
-
const { method, path, handler } = context;
|
|
251
|
-
|
|
252
|
-
// Convert to Express format
|
|
253
|
-
const expressMethod = method.toLowerCase();
|
|
254
|
-
const expressPath = convertToExpressPattern(path);
|
|
255
|
-
|
|
256
|
-
// Create Express route
|
|
257
|
-
router[expressMethod](expressPath, async (req, res) => {
|
|
258
|
-
try {
|
|
259
|
-
// Call the generic handler
|
|
260
|
-
const result = await handler({
|
|
261
|
-
queryString: req.url.split('?')[1] || '',
|
|
262
|
-
headers: req.headers,
|
|
263
|
-
params: req.params,
|
|
264
|
-
body: req.body,
|
|
265
|
-
context: createContext(req, res, 'express')
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Send response
|
|
269
|
-
res.status(200).json(result);
|
|
270
|
-
} catch (error) {
|
|
271
|
-
// Handle errors
|
|
272
|
-
handleError(error, req, res);
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### 4. The Handler Function
|
|
279
|
-
The handler passed to addRoute is transport-agnostic:
|
|
280
|
-
```javascript
|
|
281
|
-
const createRouteHandler = (scopeName, methodName) => {
|
|
282
|
-
return async ({ queryString, headers, params, body, context }) => {
|
|
283
|
-
const scope = api.scopes[scopeName];
|
|
284
|
-
|
|
285
|
-
// Build method parameters
|
|
286
|
-
const methodParams = {};
|
|
287
|
-
if (params.id) methodParams.id = params.id;
|
|
288
|
-
if (body) methodParams.inputRecord = body;
|
|
289
|
-
if (queryString) methodParams.queryParams = parseJsonApiQuery(queryString);
|
|
290
|
-
|
|
291
|
-
// Call the resource method
|
|
292
|
-
return await scope[methodName](methodParams, context);
|
|
293
|
-
};
|
|
294
|
-
};
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
This architecture means:
|
|
298
|
-
- The REST plugin doesn't know about Express
|
|
299
|
-
- The Express plugin doesn't know about REST semantics
|
|
300
|
-
- They communicate through the addRoute hook
|
|
301
|
-
- Other transports (Fastify, Koa) can implement the same hook
|
|
302
|
-
|
|
303
|
-
## Summary
|
|
304
|
-
|
|
305
|
-
The power of json-rest-api comes from:
|
|
306
|
-
1. **Plugin composition** - Each plugin does one thing well
|
|
307
|
-
2. **Hook-based extensibility** - Any behavior can be extended
|
|
308
|
-
3. **Transport agnosticism** - REST logic is separate from HTTP handling
|
|
309
|
-
4. **Pure helpers** - Data operations are predictable and testable
|
|
310
|
-
|
|
311
|
-
When contributing:
|
|
312
|
-
- Identify which plugin your change belongs in
|
|
313
|
-
- Use hooks to extend, don't modify core code
|
|
314
|
-
- Keep helpers pure
|
|
315
|
-
- Follow the established patterns
|
package/docs/_config.yml
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
title: JSON REST API
|
|
2
|
-
description: A lightweight, plugin-based REST API framework for Node.js
|
|
3
|
-
baseurl: "/json-rest-api"
|
|
4
|
-
url: "https://mobily-enterprises.github.io"
|
|
5
|
-
|
|
6
|
-
plugins:
|
|
7
|
-
- jekyll-relative-links
|
|
8
|
-
- jekyll-seo-tag
|
|
9
|
-
|
|
10
|
-
relative_links:
|
|
11
|
-
enabled: true
|
|
12
|
-
collections: true
|
|
13
|
-
|
|
14
|
-
include:
|
|
15
|
-
- README.md
|
|
16
|
-
|
|
17
|
-
exclude:
|
|
18
|
-
- vendor/
|
|
19
|
-
- Gemfile
|
|
20
|
-
- Gemfile.lock
|
|
21
|
-
|
|
22
|
-
highlighter: rouge
|
|
23
|
-
|
|
24
|
-
markdown: kramdown
|
|
25
|
-
kramdown:
|
|
26
|
-
input: GFM
|
|
27
|
-
syntax_highlighter: rouge
|
|
28
|
-
syntax_highlighter_opts:
|
|
29
|
-
block:
|
|
30
|
-
line_numbers: false
|
|
31
|
-
|
|
32
|
-
defaults:
|
|
33
|
-
- scope:
|
|
34
|
-
path: ""
|
|
35
|
-
values:
|
|
36
|
-
layout: "default"
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{% if page.title %}{{ page.title }} - {% endif %}{{ site.title }}</title>
|
|
7
|
-
<meta name="description" content="{{ page.description | default: site.description }}">
|
|
8
|
-
<link rel="icon" type="image/svg+xml" href="{{ '/favicon.svg' | relative_url }}">
|
|
9
|
-
<link rel="apple-touch-icon" href="{{ '/apple-touch-icon.svg' | relative_url }}">
|
|
10
|
-
<link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
|
|
11
|
-
{% seo %}
|
|
12
|
-
<style>
|
|
13
|
-
.highlight {
|
|
14
|
-
position: relative;
|
|
15
|
-
}
|
|
16
|
-
pre {
|
|
17
|
-
position: relative;
|
|
18
|
-
}
|
|
19
|
-
.copy-button {
|
|
20
|
-
position: absolute;
|
|
21
|
-
top: 8px;
|
|
22
|
-
right: 8px;
|
|
23
|
-
padding: 6px 12px;
|
|
24
|
-
font-size: 12px;
|
|
25
|
-
font-weight: 500;
|
|
26
|
-
background: rgba(255, 255, 255, 0.9);
|
|
27
|
-
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
28
|
-
border-radius: 6px;
|
|
29
|
-
cursor: pointer;
|
|
30
|
-
transition: all 0.2s;
|
|
31
|
-
color: #333;
|
|
32
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
33
|
-
}
|
|
34
|
-
.copy-button:hover {
|
|
35
|
-
background: rgba(255, 255, 255, 1);
|
|
36
|
-
border-color: rgba(0, 0, 0, 0.2);
|
|
37
|
-
transform: translateY(-1px);
|
|
38
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
39
|
-
}
|
|
40
|
-
.copy-button:active {
|
|
41
|
-
transform: translateY(0);
|
|
42
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
43
|
-
}
|
|
44
|
-
.copy-button.copied {
|
|
45
|
-
background: #10b981;
|
|
46
|
-
color: white;
|
|
47
|
-
border-color: #10b981;
|
|
48
|
-
}
|
|
49
|
-
</style>
|
|
50
|
-
</head>
|
|
51
|
-
<body>
|
|
52
|
-
<header>
|
|
53
|
-
<div class="wrapper">
|
|
54
|
-
<h1><a href="{{ '/' | relative_url }}">{{ site.title }}</a></h1>
|
|
55
|
-
<nav>
|
|
56
|
-
<a href="{{ '/QUICKSTART' | relative_url }}">Quick Start</a>
|
|
57
|
-
<a href="{{ '/GUIDE' | relative_url }}">Guide</a>
|
|
58
|
-
<a href="{{ '/API' | relative_url }}">API Reference</a>
|
|
59
|
-
<a href="{{ '/ONBOARDING' | relative_url }}">Contribute</a>
|
|
60
|
-
<a href="{{ '/COMPARISON' | relative_url }}">Why json-rest-api</a>
|
|
61
|
-
</nav>
|
|
62
|
-
</div>
|
|
63
|
-
</header>
|
|
64
|
-
|
|
65
|
-
<main>
|
|
66
|
-
<div class="page-content">
|
|
67
|
-
{{ content }}
|
|
68
|
-
</div>
|
|
69
|
-
</main>
|
|
70
|
-
|
|
71
|
-
<footer>
|
|
72
|
-
<div class="wrapper">
|
|
73
|
-
<p>{{ site.title }} © {{ 'now' | date: '%Y' }} - MIT License</p>
|
|
74
|
-
</div>
|
|
75
|
-
</footer>
|
|
76
|
-
|
|
77
|
-
<script>
|
|
78
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
79
|
-
// Add copy buttons to all code blocks
|
|
80
|
-
document.querySelectorAll('pre').forEach(function(pre) {
|
|
81
|
-
// Skip if button already exists
|
|
82
|
-
if (pre.querySelector('.copy-button')) return;
|
|
83
|
-
|
|
84
|
-
const button = document.createElement('button');
|
|
85
|
-
button.className = 'copy-button';
|
|
86
|
-
button.textContent = 'Copy';
|
|
87
|
-
button.addEventListener('click', function() {
|
|
88
|
-
const code = pre.querySelector('code') ?
|
|
89
|
-
pre.querySelector('code').textContent :
|
|
90
|
-
pre.textContent;
|
|
91
|
-
|
|
92
|
-
navigator.clipboard.writeText(code).then(function() {
|
|
93
|
-
button.textContent = '✓ Copied!';
|
|
94
|
-
button.classList.add('copied');
|
|
95
|
-
setTimeout(() => {
|
|
96
|
-
button.textContent = 'Copy';
|
|
97
|
-
button.classList.remove('copied');
|
|
98
|
-
}, 2000);
|
|
99
|
-
}).catch(function() {
|
|
100
|
-
// Fallback for older browsers
|
|
101
|
-
const textarea = document.createElement('textarea');
|
|
102
|
-
textarea.value = code;
|
|
103
|
-
textarea.style.position = 'fixed';
|
|
104
|
-
textarea.style.opacity = '0';
|
|
105
|
-
document.body.appendChild(textarea);
|
|
106
|
-
textarea.select();
|
|
107
|
-
document.execCommand('copy');
|
|
108
|
-
document.body.removeChild(textarea);
|
|
109
|
-
|
|
110
|
-
button.textContent = '✓ Copied!';
|
|
111
|
-
button.classList.add('copied');
|
|
112
|
-
setTimeout(() => {
|
|
113
|
-
button.textContent = 'Copy';
|
|
114
|
-
button.classList.remove('copied');
|
|
115
|
-
}, 2000);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
pre.appendChild(button);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
</script>
|
|
122
|
-
</body>
|
|
123
|
-
</html>
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180">
|
|
2
|
-
<rect width="180" height="180" rx="20" fill="#1976d2"/>
|
|
3
|
-
<text x="90" y="120" font-family="system-ui, -apple-system, sans-serif" font-size="80" font-weight="bold" text-anchor="middle" fill="white">API</text>
|
|
4
|
-
</svg>
|