json-rest-api 1.0.29 → 2.1.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 +733 -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 +103 -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 +3838 -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 +37 -0
- package/index.js +3 -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 +70 -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 +586 -418
- 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 +120 -56
- package/plugins/core/lib/anyapi/stored-definition.js +109 -0
- 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 +290 -2475
- 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/anyapi.d.ts +30 -0
- 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 +65 -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/GUIDE/index.md
CHANGED
|
@@ -1,76 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
### Core Chapters
|
|
8
|
-
|
|
9
|
-
1. **[Initial Setup](GUIDE_1_Initial_Setup.md)**
|
|
10
|
-
Get started with JSON REST API, create your first API instance, and understand the basic concepts.
|
|
11
|
-
|
|
12
|
-
2. **[Data and Relations](GUIDE_2_Data_And_Relations.md)**
|
|
13
|
-
Learn how to define resources, set up relationships, and work with your data model.
|
|
14
|
-
|
|
15
|
-
3. **[Field Transformations](GUIDE_3_Field_Transformations.md)**
|
|
16
|
-
Transform data with virtual fields, getters, setters, computed fields, and visibility control.
|
|
17
|
-
|
|
18
|
-
4. **[Non-Database Resources](GUIDE_5_Non-Db_Resources.md)**
|
|
19
|
-
Connect your API to alternative data sources beyond traditional databases.
|
|
20
|
-
|
|
21
|
-
5. **[Positioning](GUIDE_6_Positioning.md)**
|
|
22
|
-
Implement drag-and-drop functionality with automatic position management.
|
|
23
|
-
|
|
24
|
-
6. **[Hooks, Data Management, and Plugins](GUIDE_7_Hooks_Data_Management_And_Plugins.md)**
|
|
25
|
-
Master the hook system for data validation, transformation, and business logic.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
### Additional Topics
|
|
1
|
+
---
|
|
2
|
+
title: Guide
|
|
3
|
+
---
|
|
29
4
|
|
|
30
|
-
|
|
31
|
-
Handle file uploads with local storage and a mock S3-style demo adapter.
|
|
5
|
+
# JSON REST API guide
|
|
32
6
|
|
|
33
|
-
-
|
|
34
|
-
|
|
7
|
+
Use JSON REST API as a mini-ORM through resource methods, or expose the same
|
|
8
|
+
resources over HTTP. Start with chapters 01–04, then follow the relationship
|
|
9
|
+
tutorials or jump to the contract you need. Each runnable chapter uses a fresh
|
|
10
|
+
database unless it explicitly says otherwise.
|
|
35
11
|
|
|
36
|
-
|
|
37
|
-
|
|
12
|
+
Upgrading an application? Start with [33. Migrating to v2](33-migrating-to-v2.md).
|
|
13
|
+
Before choosing storage, read [30. Backend capabilities and limits](30-backend-capabilities.md).
|
|
38
14
|
|
|
39
|
-
|
|
40
|
-
|
|
15
|
+
The examples require Node.js 24 or newer and familiarity with JavaScript and npm.
|
|
16
|
+
Development verification targets Node 24.
|
|
41
17
|
|
|
42
|
-
- **[Row Policies](GUIDE_X_Row_Policies.md)**
|
|
43
|
-
Apply mandatory server-side visibility predicates before pagination, counts, includes, and relationship loading.
|
|
44
18
|
|
|
45
|
-
|
|
46
|
-
Create tables, inspect live table snapshots, and generate create or additive diff migrations from table-backed resource scopes.
|
|
19
|
+
## Getting started
|
|
47
20
|
|
|
48
|
-
-
|
|
49
|
-
|
|
21
|
+
- [01. Getting started](01-getting-started.md)
|
|
22
|
+
- [02. Resources and relationships](02-resources-and-relationships.md)
|
|
23
|
+
- [03. Running example](03-running-example.md)
|
|
24
|
+
- [04. Creating and querying records](04-creating-and-querying.md)
|
|
50
25
|
|
|
51
|
-
|
|
52
|
-
Build plugins against the supported extension surface, including hooks, scope methods, and query-only read fields.
|
|
26
|
+
## Relationships and queries
|
|
53
27
|
|
|
54
|
-
-
|
|
55
|
-
|
|
28
|
+
- [05. Belongs-to relationships](05-belongs-to.md)
|
|
29
|
+
- [06. Has-many relationships](06-has-many.md)
|
|
30
|
+
- [07. Polymorphic relationships](07-polymorphic-relationships.md)
|
|
31
|
+
- [08. Many-to-many relationships](08-many-to-many.md)
|
|
32
|
+
- [09. Pagination and sorting](09-pagination-and-sorting.md)
|
|
33
|
+
- [10. PUT and PATCH](10-put-and-patch.md)
|
|
34
|
+
- [11. Relationship endpoints](11-relationship-endpoints.md)
|
|
56
35
|
|
|
57
|
-
|
|
58
|
-
Add real-time capabilities to your API with WebSocket support.
|
|
36
|
+
## Resource behavior
|
|
59
37
|
|
|
60
|
-
-
|
|
61
|
-
|
|
38
|
+
- [12. Field transformations](12-field-transformations.md)
|
|
39
|
+
- [13. Hooks and lifecycle](13-hooks-and-lifecycle.md)
|
|
40
|
+
- [14. Custom resource methods](14-custom-resource-methods.md)
|
|
41
|
+
- [15. Query projections](15-query-projections.md)
|
|
42
|
+
- [16. Autofiltering](16-autofiltering.md)
|
|
43
|
+
- [17. Row policies](17-row-policies.md)
|
|
44
|
+
- [18. Labels](18-labels.md)
|
|
62
45
|
|
|
63
|
-
|
|
64
|
-
Reference material, troubleshooting, and additional resources.
|
|
46
|
+
## Transactions and schema
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
- [19. Managed transactions](19-managed-transactions.md)
|
|
49
|
+
- [20. Transaction outcomes](20-transaction-outcomes.md)
|
|
50
|
+
- [21. Schema and migrations](21-schema-and-migrations.md)
|
|
51
|
+
- [22. Version-field migrations](22-version-field-migrations.md)
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
## Transports and extensions
|
|
69
54
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
55
|
+
- [23. Fastify integration](23-fastify.md)
|
|
56
|
+
- [24. CORS](24-cors.md)
|
|
57
|
+
- [25. URL management](25-url-management.md)
|
|
58
|
+
- [26. File uploads](26-file-uploads.md)
|
|
59
|
+
- [27. Bulk operations](27-bulk-operations.md)
|
|
60
|
+
- [28. Socket.IO integration](28-socketio.md)
|
|
61
|
+
- [29. Writing plugins](29-writing-plugins.md)
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
## Limits and migration
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
- [30. Backend capabilities and limits](30-backend-capabilities.md)
|
|
66
|
+
- [31. Positioning (experimental)](31-positioning.md)
|
|
67
|
+
- [32. Date and time](32-date-and-time.md)
|
|
68
|
+
- [33. Migrating to v2](33-migrating-to-v2.md)
|
package/docs/QUICKSTART.md
CHANGED
|
@@ -1,346 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Quickstart"
|
|
3
|
+
---
|
|
4
|
+
|
|
1
5
|
# Quickstart
|
|
2
6
|
|
|
7
|
+
Use Node 24 or newer. Development verification runs on Node 24. This example
|
|
8
|
+
uses an in-memory SQLite database: restarting the process discards its records.
|
|
3
9
|
|
|
4
|
-
##
|
|
10
|
+
## Install
|
|
5
11
|
|
|
6
12
|
```bash
|
|
7
13
|
mkdir quickstart-api
|
|
8
14
|
cd quickstart-api
|
|
9
|
-
npm init
|
|
10
|
-
npm
|
|
11
|
-
npm install knex
|
|
12
|
-
npm install better-sqlite3
|
|
13
|
-
npm install express
|
|
15
|
+
npm init -y
|
|
16
|
+
npm pkg set type=module
|
|
17
|
+
npm install json-rest-api knex better-sqlite3 express
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
These
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
These examples use the revised API described in the
|
|
21
|
+
[migration guide](GUIDE/33-migrating-to-v2.md). Until that release is published,
|
|
22
|
+
install the intended library tarball in place of the registry package.
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
## Define resources
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
Create `index.js` with the following code. Install the HTTP connector before
|
|
27
|
+
registering resources so it can register their routes.
|
|
23
28
|
|
|
24
29
|
```javascript
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import { RestApiPlugin, RestApiKnexPlugin, ExpressPlugin } from 'json-rest-api'; // Added: ExpressPlugin
|
|
29
|
-
import { Api } from 'hooked-api';
|
|
30
|
-
import knexLib from 'knex';
|
|
31
|
-
import util from 'util';
|
|
32
|
-
import express from 'express'; // Added: Express
|
|
30
|
+
import { JsonRestApi, RestApiPlugin, RestApiKnexPlugin, ExpressPlugin } from 'json-rest-api'
|
|
31
|
+
import knexLib from 'knex'
|
|
32
|
+
import express from 'express'
|
|
33
33
|
|
|
34
|
-
// Utility used throughout this guide
|
|
35
|
-
const inspect = (obj) => util.inspect(obj, { depth: 8 })
|
|
36
|
-
|
|
37
|
-
// Create a Knex instance connected to SQLite in-memory database
|
|
38
34
|
const knex = knexLib({
|
|
39
35
|
client: 'better-sqlite3',
|
|
40
|
-
connection: {
|
|
41
|
-
filename: ':memory:'
|
|
42
|
-
},
|
|
36
|
+
connection: { filename: ':memory:' },
|
|
43
37
|
useNullAsDefault: true
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// Install plugins
|
|
50
|
-
await api.use(RestApiPlugin); // URLs auto-detected from request headers
|
|
51
|
-
await api.use(RestApiKnexPlugin, { knex });
|
|
52
|
-
await api.use(ExpressPlugin, { mountPath: '/api' }); // Added: Express Plugin
|
|
53
|
-
|
|
54
|
-
/// *** ...programmatic calls here... ***
|
|
38
|
+
})
|
|
39
|
+
const api = new JsonRestApi({ name: 'book-catalog-api' })
|
|
40
|
+
await api.use(RestApiPlugin)
|
|
41
|
+
await api.use(RestApiKnexPlugin, { knex })
|
|
42
|
+
await api.use(ExpressPlugin, { mountPath: '/api' })
|
|
55
43
|
|
|
56
|
-
// Create the express server and add the API's routes
|
|
57
|
-
const app = express();
|
|
58
|
-
app.use(api.http.express.router);
|
|
59
|
-
app.use(api.http.express.notFoundRouter);
|
|
60
|
-
|
|
61
|
-
app.listen(3000, () => {
|
|
62
|
-
console.log('Express server started on port 3000. API available at http://localhost:3000/api');
|
|
63
|
-
}).on('error', (err) => {
|
|
64
|
-
console.error('Failed to start server:', err);
|
|
65
|
-
process.exit(1)
|
|
66
|
-
});
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Add a couple of resources
|
|
70
|
-
|
|
71
|
-
In the snippet above, add a couple of related resourcs:
|
|
72
|
-
|
|
73
|
-
```javascript
|
|
74
|
-
// Define publishers resource
|
|
75
44
|
await api.addResource('publishers', {
|
|
76
45
|
schema: {
|
|
77
|
-
name: { type: 'string', required: true, max: 255, search: true
|
|
46
|
+
name: { type: 'string', required: true, max: 255, search: true }
|
|
78
47
|
},
|
|
79
48
|
relationships: {
|
|
80
|
-
|
|
81
|
-
authors: { type: 'hasMany', target: 'authors', foreignKey: 'publisher_id' },
|
|
82
|
-
},
|
|
83
|
-
searchSchema: { // Adding search schema for publishers
|
|
84
|
-
name: { type: 'string', filterOperator: 'like' }
|
|
49
|
+
authors: { type: 'hasMany', target: 'authors', foreignKey: 'publisher_id' }
|
|
85
50
|
}
|
|
86
|
-
})
|
|
87
|
-
await api.resources.publishers.createKnexTable();
|
|
88
|
-
|
|
89
|
-
// Define authors resource, which belongs to a publisher
|
|
51
|
+
})
|
|
90
52
|
await api.addResource('authors', {
|
|
91
53
|
schema: {
|
|
92
54
|
name: { type: 'string', required: true, max: 100, search: true },
|
|
93
|
-
surname: { type: 'string', required: true, max: 100
|
|
55
|
+
surname: { type: 'string', required: true, max: 100 },
|
|
94
56
|
publisher_id: { type: 'id', belongsTo: 'publishers', as: 'publisher', nullable: true }
|
|
95
57
|
},
|
|
96
|
-
searchSchema: {
|
|
97
|
-
|
|
98
|
-
surname: { type: 'string', filterOperator: 'like' },
|
|
99
|
-
publisher: { type: 'id', actualField: 'publisher_id', nullable: true },
|
|
100
|
-
publisherName: { type: 'string', actualField: 'publishers.name', filterOperator: 'like' } // Cross-table search
|
|
58
|
+
searchSchema: {
|
|
59
|
+
nameContains: { type: 'string', actualField: 'name', filterOperator: 'contains' }
|
|
101
60
|
}
|
|
102
|
-
})
|
|
103
|
-
await api.resources.
|
|
104
|
-
|
|
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
|
-
|
|
110
|
-
## Run the program
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
$ node index.js
|
|
114
|
-
2025-08-01T00:25:50.730Z [INFO] [book-catalog-api] Installing plugin 'rest-api'
|
|
115
|
-
2025-08-01T00:25:50.736Z [INFO] [book-catalog-api] Plugin 'rest-api' installed successfully { duration: '2ms' }
|
|
116
|
-
2025-08-01T00:25:50.736Z [INFO] [book-catalog-api] Installing plugin 'rest-api-knex' { options: '[Object with methods]' }
|
|
117
|
-
2025-08-01T00:25:50.745Z [INFO] [book-catalog-api:plugin:rest-api-knex] Database capabilities detected: { database: 'SQLite', version: '3.50.2', windowFunctions: true }
|
|
118
|
-
2025-08-01T00:25:50.746Z [INFO] [book-catalog-api:plugin:rest-api-knex] RestApiKnexPlugin installed - basic CRUD operations ready
|
|
119
|
-
2025-08-01T00:25:50.747Z [INFO] [book-catalog-api] Plugin 'rest-api-knex' installed successfully { duration: '10ms' }
|
|
120
|
-
2025-08-01T00:25:50.747Z [INFO] [book-catalog-api] Installing plugin 'express' { options: { mountPath: '/api' } }
|
|
121
|
-
2025-08-01T00:25:50.750Z [INFO] [book-catalog-api:plugin:express] Express plugin initialized successfully
|
|
122
|
-
2025-08-01T00:25:50.751Z [INFO] [book-catalog-api] Plugin 'express' installed successfully { duration: '4ms' }
|
|
123
|
-
2025-08-01T00:25:50.751Z [INFO] [book-catalog-api] Scope 'publishers' added successfully
|
|
124
|
-
2025-08-01T00:25:50.758Z [INFO] [book-catalog-api:global] Routes registered for scope 'publishers'
|
|
125
|
-
2025-08-01T00:25:50.763Z [INFO] [book-catalog-api] Scope 'authors' added successfully
|
|
126
|
-
2025-08-01T00:25:50.765Z [INFO] [book-catalog-api:global] Routes registered for scope 'authors'
|
|
127
|
-
Express server started on port 3000. API available at http://localhost:3000/api
|
|
61
|
+
})
|
|
62
|
+
await api.resources.publishers.createKnexTable()
|
|
63
|
+
await api.resources.authors.createKnexTable()
|
|
128
64
|
```
|
|
129
65
|
|
|
130
|
-
|
|
66
|
+
`searchSchema` declares accepted public filters; `actualField` maps a filter to
|
|
67
|
+
a resource field. See [searching](GUIDE/04-creating-and-querying.md)
|
|
68
|
+
for more complex filters and [schema migrations](GUIDE/21-schema-and-migrations.md)
|
|
69
|
+
for persistent databases.
|
|
131
70
|
|
|
132
|
-
##
|
|
71
|
+
## Call the API programmatically
|
|
133
72
|
|
|
134
|
-
|
|
135
|
-
Now, just after the creation of the knex table for authors, make some queries programmatically:
|
|
73
|
+
Append this code before starting the HTTP server:
|
|
136
74
|
|
|
137
75
|
```javascript
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
76
|
+
const publisher = await api.resources.publishers.post({
|
|
77
|
+
data: { name: 'Penguin Random House' }
|
|
78
|
+
})
|
|
79
|
+
const author = await api.resources.authors.post({
|
|
80
|
+
data: { name: 'George', surname: 'Orwell', publisher: publisher.id }
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const found = await api.resources.authors.query({
|
|
84
|
+
queryParams: {
|
|
85
|
+
filters: { nameContains: 'Georg' },
|
|
86
|
+
sort: ['surname'],
|
|
87
|
+
page: { number: 1, size: 10 }
|
|
148
88
|
}
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
89
|
+
})
|
|
90
|
+
console.log('Matching authors:', found.data)
|
|
91
|
+
console.log('Pagination:', found.meta.pagination)
|
|
92
|
+
|
|
93
|
+
const withAuthors = await api.resources.publishers.get({
|
|
94
|
+
id: publisher.id,
|
|
95
|
+
queryParams: { include: ['authors'] }
|
|
96
|
+
})
|
|
97
|
+
console.log('Publisher and included authors:', withAuthors)
|
|
98
|
+
|
|
99
|
+
const updated = await api.resources.authors.patch({
|
|
100
|
+
id: author.id,
|
|
101
|
+
data: { surname: 'Orwell (Eric Blair)' },
|
|
102
|
+
returning: 'minimal'
|
|
103
|
+
})
|
|
104
|
+
console.log('Updated identifier:', updated)
|
|
105
|
+
|
|
106
|
+
const document = await api.resources.publishers.post({
|
|
107
|
+
format: 'jsonapi',
|
|
108
|
+
document: {
|
|
154
109
|
data: {
|
|
155
110
|
type: 'publishers',
|
|
156
|
-
attributes: {
|
|
157
|
-
name: 'Oxford University Press'
|
|
158
|
-
}
|
|
111
|
+
attributes: { name: 'Oxford University Press' }
|
|
159
112
|
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
console.log('JSON:API response:', inspect(oxfordResult));
|
|
164
|
-
|
|
165
|
-
// Create an author linked to the first publisher (simplified)
|
|
166
|
-
const authorResult = await api.resources.authors.post({
|
|
167
|
-
name: 'George',
|
|
168
|
-
surname: 'Orwell',
|
|
169
|
-
publisher: penguinResult.id
|
|
170
|
-
});
|
|
171
|
-
console.log('Created author:', inspect(authorResult));
|
|
172
|
-
|
|
173
|
-
// Get all publishers
|
|
174
|
-
const allPublishers = await api.resources.publishers.query({});
|
|
175
|
-
console.log('All publishers:', inspect(allPublishers));
|
|
176
|
-
|
|
177
|
-
// Get publisher with included authors
|
|
178
|
-
const publisherWithAuthors = await api.resources.publishers.get({
|
|
179
|
-
id: penguinResult.id,
|
|
180
|
-
include: ['authors']
|
|
181
|
-
});
|
|
182
|
-
console.log('Publisher with authors:', inspect(publisherWithAuthors));
|
|
183
|
-
|
|
184
|
-
// Search authors by name
|
|
185
|
-
const searchResult = await api.resources.authors.query({
|
|
186
|
-
filter: { name: 'George' }
|
|
187
|
-
});
|
|
188
|
-
console.log('Search results:', inspect(searchResult));
|
|
189
|
-
|
|
190
|
-
// Update an author
|
|
191
|
-
const updateResult = await api.resources.authors.patch({
|
|
192
|
-
id: authorResult.id,
|
|
193
|
-
surname: 'Orwell (Eric Blair)'
|
|
194
|
-
});
|
|
195
|
-
console.log('Updated author:', inspect(updateResult));
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
console.log('JSON:API publisher:', document.data)
|
|
196
116
|
```
|
|
197
117
|
|
|
198
|
-
|
|
118
|
+
Programmatic calls default to `format: 'plain'` and `returning: 'full'`.
|
|
119
|
+
Writes accept either plain resource values in `data` or a JSON:API document in
|
|
120
|
+
`document`, never both. Read selection, filtering,
|
|
121
|
+
sorting and pagination go in `queryParams`; identifiers and response options
|
|
122
|
+
remain method parameters.
|
|
199
123
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
124
|
+
Plain reads return a record for `get`, and a collection with `data` for `query`.
|
|
125
|
+
The filtered query above returns George and pagination metadata with `total: 1`.
|
|
126
|
+
The PATCH returns `{ type: 'authors', id: author.id }` because it selects
|
|
127
|
+
`returning: 'minimal'`. Use `returning: 'none'` for an undefined write result.
|
|
128
|
+
`format` selects only the output. You can request JSON:API output from plain
|
|
129
|
+
`data`, or plain output from a JSON:API `document`. The input key selects the
|
|
130
|
+
input contract; the library does not guess from its contents.
|
|
203
131
|
|
|
204
|
-
|
|
132
|
+
## Start the HTTP server
|
|
205
133
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
Created author: { id: '1', name: 'George', surname: 'Orwell', publisher: { id: '1' } }
|
|
219
|
-
All publishers: {
|
|
220
|
-
data: [
|
|
221
|
-
{ id: '1', name: 'Penguin Random House', authors: [ { id: '1' } ] },
|
|
222
|
-
{ id: '2', name: 'HarperCollins', authors: [] },
|
|
223
|
-
{ id: '3', name: 'Oxford University Press', authors: [] }
|
|
224
|
-
],
|
|
225
|
-
links: { self: '/api/publishers' }
|
|
226
|
-
}
|
|
227
|
-
Publisher with authors: { id: '1', name: 'Penguin Random House', authors: [ { id: '1' } ] }
|
|
228
|
-
Search results: {
|
|
229
|
-
data: [ { id: '1', name: 'George', surname: 'Orwell', publisher: { id: '1' } } ],
|
|
230
|
-
links: { self: '/api/authors' }
|
|
231
|
-
}
|
|
232
|
-
Updated author: {
|
|
233
|
-
id: '1',
|
|
234
|
-
name: 'George',
|
|
235
|
-
surname: 'Orwell (Eric Blair)',
|
|
236
|
-
publisher: { id: '1' }
|
|
134
|
+
Append this last block:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
const app = express()
|
|
138
|
+
app.use(api.http.express.router)
|
|
139
|
+
app.use(api.http.express.notFoundRouter)
|
|
140
|
+
const server = app.listen(3000, () => {
|
|
141
|
+
console.log('API listening at http://localhost:3000/api')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
async function shutdown () {
|
|
145
|
+
server.close(async () => { await knex.destroy() })
|
|
237
146
|
}
|
|
147
|
+
process.once('SIGINT', shutdown)
|
|
148
|
+
process.once('SIGTERM', shutdown)
|
|
238
149
|
```
|
|
239
150
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
151
|
+
Run `node index.js`. HTTP requests use JSON:API documents. The connector handles
|
|
152
|
+
request-body parsing. The following commands assume a fresh run of the example;
|
|
153
|
+
use returned IDs when adapting them to an existing database. `--globoff` keeps
|
|
154
|
+
curl from interpreting the square brackets in query parameters.
|
|
243
155
|
|
|
244
156
|
```bash
|
|
245
|
-
|
|
246
|
-
# Get all publishers
|
|
247
157
|
curl http://localhost:3000/api/publishers
|
|
158
|
+
curl --globoff 'http://localhost:3000/api/publishers/1?include=authors'
|
|
159
|
+
curl --globoff 'http://localhost:3000/api/authors?filter[nameContains]=Georg'
|
|
160
|
+
curl --globoff 'http://localhost:3000/api/authors?fields[authors]=name,surname'
|
|
161
|
+
curl --globoff 'http://localhost:3000/api/publishers?page[number]=1&page[size]=10'
|
|
162
|
+
curl 'http://localhost:3000/api/authors?sort=-surname'
|
|
248
163
|
|
|
249
|
-
# Get all authors
|
|
250
|
-
curl http://localhost:3000/api/authors
|
|
251
|
-
|
|
252
|
-
# Get a specific publisher with included authors
|
|
253
|
-
curl "http://localhost:3000/api/publishers/1?include=authors"
|
|
254
|
-
|
|
255
|
-
# Search authors by name
|
|
256
|
-
curl "http://localhost:3000/api/authors?filter[name]=George"
|
|
257
|
-
|
|
258
|
-
# Search authors by publisher name (cross-table search)
|
|
259
|
-
curl "http://localhost:3000/api/authors?filter[publisherName]=Penguin"
|
|
260
|
-
|
|
261
|
-
# Get authors with sparse fields (only name and surname)
|
|
262
|
-
curl "http://localhost:3000/api/authors?fields[authors]=name,surname"
|
|
263
|
-
|
|
264
|
-
# Update an author
|
|
265
|
-
curl -X PATCH http://localhost:3000/api/authors/1 \
|
|
266
|
-
-H "Content-Type: application/vnd.api+json" \
|
|
267
|
-
-d '{
|
|
268
|
-
"data": {
|
|
269
|
-
"type": "authors",
|
|
270
|
-
"id": "1",
|
|
271
|
-
"attributes": {
|
|
272
|
-
"surname": "Orwell (Blair)"
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}'
|
|
276
|
-
|
|
277
|
-
# Create a new author
|
|
278
164
|
curl -X POST http://localhost:3000/api/authors \
|
|
279
|
-
-H
|
|
280
|
-
-d '{
|
|
281
|
-
"data": {
|
|
282
|
-
"type": "authors",
|
|
283
|
-
"attributes": {
|
|
284
|
-
"name": "Jane",
|
|
285
|
-
"surname": "Austen"
|
|
286
|
-
},
|
|
287
|
-
"relationships": {
|
|
288
|
-
"publisher": {
|
|
289
|
-
"data": { "type": "publishers", "id": "2" }
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}'
|
|
165
|
+
-H 'Content-Type: application/vnd.api+json' \
|
|
166
|
+
-d '{"data":{"type":"authors","attributes":{"name":"Jane","surname":"Austen"},"relationships":{"publisher":{"data":{"type":"publishers","id":"1"}}}}}'
|
|
294
167
|
|
|
295
|
-
# Update the new author's surname
|
|
296
168
|
curl -X PATCH http://localhost:3000/api/authors/2 \
|
|
297
|
-
-H
|
|
298
|
-
-d '{
|
|
299
|
-
"data": {
|
|
300
|
-
"type": "authors",
|
|
301
|
-
"id": "2",
|
|
302
|
-
"attributes": {
|
|
303
|
-
"surname": "Austen (1775-1817)"
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}'
|
|
169
|
+
-H 'Content-Type: application/vnd.api+json' \
|
|
170
|
+
-d '{"data":{"type":"authors","id":"2","attributes":{"surname":"Austen (1775-1817)"}}}'
|
|
307
171
|
|
|
308
|
-
# Update author's relationship to a different publisher
|
|
309
|
-
curl -X PATCH http://localhost:3000/api/authors/2 \
|
|
310
|
-
-H "Content-Type: application/vnd.api+json" \
|
|
311
|
-
-d '{
|
|
312
|
-
"data": {
|
|
313
|
-
"type": "authors",
|
|
314
|
-
"id": "2",
|
|
315
|
-
"relationships": {
|
|
316
|
-
"publisher": {
|
|
317
|
-
"data": { "type": "publishers", "id": "1" }
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}'
|
|
322
|
-
|
|
323
|
-
# Delete the newly created author
|
|
324
172
|
curl -X DELETE http://localhost:3000/api/authors/2
|
|
325
|
-
|
|
326
|
-
# Get publishers with pagination
|
|
327
|
-
curl "http://localhost:3000/api/publishers?page[offset]=0&page[limit]=10"
|
|
328
|
-
|
|
329
|
-
# Sort authors by surname descending
|
|
330
|
-
curl "http://localhost:3000/api/authors?sort=-surname"
|
|
331
173
|
```
|
|
332
174
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
You've successfully set up a basic JSON REST API! This quickstart covered the essentials, but there's much more to explore.
|
|
336
|
-
|
|
337
|
-
Check out the [full guide](./GUIDE) to learn about:
|
|
338
|
-
- Advanced relationships (many-to-many, polymorphic)
|
|
339
|
-
- Permission hooks, request auth context, and autofiltering
|
|
340
|
-
- Hooks and middleware
|
|
341
|
-
- Custom validation
|
|
342
|
-
- Pagination strategies
|
|
343
|
-
- Performance optimization
|
|
344
|
-
- And much more!
|
|
175
|
+
For an API without an HTTP server, omit the connector/server setup and call
|
|
176
|
+
`await knex.destroy()` after the programmatic operations finish.
|
|
345
177
|
|
|
346
|
-
|
|
178
|
+
Continue with the [full guide](GUIDE/index.md),
|
|
179
|
+
[API reference](API.md), and [verified backend capabilities](GUIDE/30-backend-capabilities.md).
|