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.
Files changed (289) hide show
  1. package/LICENSE +10 -670
  2. package/LICENSE-GPL-3.0 +674 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +39 -30
  5. package/docs/API.md +746 -1273
  6. package/docs/GUIDE/01-getting-started.md +338 -0
  7. package/docs/GUIDE/02-resources-and-relationships.md +33 -0
  8. package/docs/GUIDE/03-running-example.md +87 -0
  9. package/docs/GUIDE/04-creating-and-querying.md +181 -0
  10. package/docs/GUIDE/05-belongs-to.md +177 -0
  11. package/docs/GUIDE/06-has-many.md +184 -0
  12. package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
  13. package/docs/GUIDE/08-many-to-many.md +184 -0
  14. package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
  15. package/docs/GUIDE/10-put-and-patch.md +174 -0
  16. package/docs/GUIDE/11-relationship-endpoints.md +174 -0
  17. package/docs/GUIDE/12-field-transformations.md +287 -0
  18. package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
  19. package/docs/GUIDE/14-custom-resource-methods.md +125 -0
  20. package/docs/GUIDE/15-query-projections.md +266 -0
  21. package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
  22. package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
  23. package/docs/GUIDE/18-labels.md +86 -0
  24. package/docs/GUIDE/19-managed-transactions.md +179 -0
  25. package/docs/GUIDE/20-transaction-outcomes.md +207 -0
  26. package/docs/GUIDE/21-schema-and-migrations.md +634 -0
  27. package/docs/GUIDE/22-version-field-migrations.md +208 -0
  28. package/docs/GUIDE/23-fastify.md +179 -0
  29. package/docs/GUIDE/24-cors.md +172 -0
  30. package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
  31. package/docs/GUIDE/26-file-uploads.md +278 -0
  32. package/docs/GUIDE/27-bulk-operations.md +277 -0
  33. package/docs/GUIDE/28-socketio.md +325 -0
  34. package/docs/GUIDE/29-writing-plugins.md +278 -0
  35. package/docs/GUIDE/30-backend-capabilities.md +100 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +90 -31
  38. package/docs/GUIDE/33-migrating-to-v2.md +3827 -0
  39. package/docs/GUIDE/index.md +51 -59
  40. package/docs/QUICKSTART.md +120 -287
  41. package/docs/architecture.md +75 -0
  42. package/docs/contributing.md +178 -0
  43. package/index.d.ts +36 -0
  44. package/index.js +1 -22
  45. package/lib/enhanced-logger.js +91 -85
  46. package/lib/error-context.js +445 -5
  47. package/lib/error-formatter.js +219 -59
  48. package/lib/knex-transaction.js +64 -0
  49. package/lib/logger-types.d.ts +22 -0
  50. package/lib/missing-package.js +4 -0
  51. package/lib/rest-api-errors.js +103 -8
  52. package/lib/runtime/json-rest-api.js +172 -0
  53. package/lib/transaction-types.d.ts +59 -0
  54. package/package.json +97 -27
  55. package/plugins/core/bulk-operations-plugin.js +191 -184
  56. package/plugins/core/connectors/express-plugin.js +148 -219
  57. package/plugins/core/connectors/fastify-plugin.js +125 -82
  58. package/plugins/core/connectors/lib/busboy-detector.js +74 -156
  59. package/plugins/core/connectors/lib/connector-core.js +144 -20
  60. package/plugins/core/connectors/lib/formidable-detector.js +63 -120
  61. package/plugins/core/connectors/lib/http-validators.js +77 -0
  62. package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
  63. package/plugins/core/connectors/lib/request-helpers.js +10 -1
  64. package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
  65. package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
  66. package/plugins/core/file-handling-plugin.js +87 -174
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
  68. package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
  69. package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
  70. package/plugins/core/lib/anyapi/schema-utils.js +25 -16
  71. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  72. package/plugins/core/lib/dbIntrospection.js +228 -21
  73. package/plugins/core/lib/dbTablesOperations.js +409 -92
  74. package/plugins/core/lib/fractional-positioning.js +12 -48
  75. package/plugins/core/lib/querying/identifier-query.js +19 -0
  76. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  77. package/plugins/core/lib/querying/include-to-many.js +428 -0
  78. package/plugins/core/lib/querying/include-to-one.js +579 -0
  79. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  80. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  81. package/plugins/core/lib/querying/knex-pagination-helpers.js +67 -330
  82. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  83. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  84. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  85. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  86. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  87. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  88. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  89. package/plugins/core/lib/querying/query-constraint.js +27 -0
  90. package/plugins/core/lib/querying/query-field-sort-helpers.js +205 -30
  91. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  92. package/plugins/core/lib/querying/sort-helpers.js +20 -1
  93. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  94. package/plugins/core/lib/querying/url-helpers.js +11 -4
  95. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  96. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  97. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  98. package/plugins/core/lib/querying-writing/database-value-normalizers.js +238 -187
  99. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  100. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  101. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  102. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  103. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  104. package/plugins/core/lib/querying-writing/knex-field-helpers.js +111 -287
  105. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  106. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  107. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  108. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  109. package/plugins/core/lib/querying-writing/request-contracts.js +109 -44
  110. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  111. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  112. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  113. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  114. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  115. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  116. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  117. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  118. package/plugins/core/lib/storage/storage-adapter.js +142 -62
  119. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  120. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  121. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  122. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  123. package/plugins/core/lib/writing/resource-version.js +172 -0
  124. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  125. package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2509
  126. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  127. package/plugins/core/rest-api-cors-plugin.js +52 -205
  128. package/plugins/core/rest-api-knex-plugin.js +45 -1069
  129. package/plugins/core/rest-api-label-plugin.js +25 -38
  130. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  131. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  132. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  133. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  134. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  135. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  136. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  137. package/plugins/core/rest-api-plugin-methods/common.js +291 -385
  138. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  139. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  140. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -145
  141. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  142. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  143. package/plugins/core/rest-api-plugin-methods/get.js +38 -69
  144. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  145. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  146. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  147. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  148. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  149. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  150. package/plugins/core/rest-api-plugin-methods/query.js +39 -82
  151. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  152. package/plugins/core/rest-api-plugin.js +32 -46
  153. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  154. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  155. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  156. package/plugins/core/socketio-plugin.js +364 -344
  157. package/plugins/storage/local-storage.js +40 -36
  158. package/types/autofilter.d.ts +57 -0
  159. package/types/bulk-methods.d.ts +63 -0
  160. package/types/errors.d.ts +118 -0
  161. package/types/fastify-options.d.ts +19 -0
  162. package/types/file-detectors.d.ts +33 -0
  163. package/types/file-storage.d.ts +48 -0
  164. package/types/hook-context.d.ts +180 -0
  165. package/types/plugin-options.d.ts +53 -0
  166. package/types/relationship-methods.d.ts +74 -0
  167. package/types/representations.d.ts +50 -0
  168. package/types/resource-methods.d.ts +95 -0
  169. package/types/resource-schema.d.ts +157 -0
  170. package/types/row-policy.d.ts +31 -0
  171. package/types/runtime.d.ts +132 -0
  172. package/types/transactions.d.ts +21 -0
  173. package/.claude/agents/library-guide-expert.md +0 -30
  174. package/.claude/agents/rest-api-internals-expert.md +0 -54
  175. package/.claude/settings.local.json +0 -70
  176. package/AGENTS.md +0 -34
  177. package/CLAUDE.md +0 -160
  178. package/CRUSH.md +0 -55
  179. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  180. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  181. package/TODO.todo +0 -13
  182. package/connectors_ideas/fastify.js +0 -217
  183. package/connectors_ideas/koa-plugin.js +0 -112
  184. package/docs/.bundle/config +0 -2
  185. package/docs/COMPARISON.md +0 -433
  186. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  187. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  188. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  189. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  190. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  191. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  192. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  193. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1238
  194. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  195. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  196. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  197. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  198. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  199. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  200. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  201. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  202. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  203. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  204. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  205. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  206. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  207. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  208. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  209. package/docs/Gemfile +0 -6
  210. package/docs/Gemfile.lock +0 -308
  211. package/docs/ONBOARDING.md +0 -315
  212. package/docs/_config.yml +0 -36
  213. package/docs/_layouts/default.html +0 -123
  214. package/docs/apple-touch-icon.svg +0 -4
  215. package/docs/assets/css/style.scss +0 -392
  216. package/docs/favicon.svg +0 -4
  217. package/docs/index.md +0 -164
  218. package/docs/mini-guides/file-uploads-complete.md +0 -161
  219. package/eslint.config.js +0 -13
  220. package/examples/url-override-example.js +0 -137
  221. package/fixing_plan.md +0 -112
  222. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  223. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  224. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  225. package/plugins/storage/s3-storage.js +0 -93
  226. package/quickTest.js +0 -136
  227. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  228. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  229. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  230. package/scripts/run-docs.js +0 -133
  231. package/test-debug.js +0 -59
  232. package/tests/README.md +0 -202
  233. package/tests/TEST_TEMPLATE.test.js +0 -178
  234. package/tests/anyapi-basic.test.js +0 -105
  235. package/tests/anyapi-cursor-pagination.test.js +0 -150
  236. package/tests/anyapi-custom-idproperty.test.js +0 -163
  237. package/tests/autofilter.test.js +0 -463
  238. package/tests/bulk-operations.test.js +0 -657
  239. package/tests/computed-fields.test.js +0 -586
  240. package/tests/cors.test.js +0 -834
  241. package/tests/curl.test.js +0 -467
  242. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  243. package/tests/custom-id-simplified-post.test.js +0 -75
  244. package/tests/custom-idproperty-relationships.test.js +0 -932
  245. package/tests/db-introspection.test.js +0 -521
  246. package/tests/db-table-operations.test.js +0 -798
  247. package/tests/fastify-plugin.test.js +0 -184
  248. package/tests/field-getters.test.js +0 -370
  249. package/tests/field-setters.test.js +0 -306
  250. package/tests/file-handling.test.js +0 -118
  251. package/tests/fixtures/api-configs.js +0 -2509
  252. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  253. package/tests/helpers/fake-fastify.js +0 -99
  254. package/tests/helpers/storage-mode.js +0 -65
  255. package/tests/helpers/test-utils.js +0 -203
  256. package/tests/http-connectors-parity.test.js +0 -395
  257. package/tests/id-normalization.test.js +0 -444
  258. package/tests/include-depth-validation.test.js +0 -331
  259. package/tests/includes.test.js +0 -427
  260. package/tests/local-storage.test.js +0 -96
  261. package/tests/logical-id-write-validation.test.js +0 -151
  262. package/tests/nested-includes.test.js +0 -617
  263. package/tests/pagination-cursor-multifield.test.js +0 -643
  264. package/tests/pagination-enhanced.test.js +0 -563
  265. package/tests/polymorphic-relationships.test.js +0 -347
  266. package/tests/polymorphic-simple.test.js +0 -148
  267. package/tests/positioning-advanced.test.js +0 -692
  268. package/tests/positioning-extended.test.js +0 -915
  269. package/tests/positioning-multifilter.test.js +0 -699
  270. package/tests/positioning.test.js +0 -560
  271. package/tests/post-commit-hooks.test.js +0 -120
  272. package/tests/projected-fields.test.js +0 -319
  273. package/tests/public-exports.test.js +0 -15
  274. package/tests/put-create-parity.test.js +0 -216
  275. package/tests/queries.test.js +0 -521
  276. package/tests/query-limits.test.js +0 -584
  277. package/tests/relationship-endpoints.test.js +0 -620
  278. package/tests/relationship-include-storage-adapter.test.js +0 -56
  279. package/tests/relationships.test.js +0 -681
  280. package/tests/rest-api.test.js +0 -337
  281. package/tests/return-record-settings.test.js +0 -184
  282. package/tests/row-policy.test.js +0 -489
  283. package/tests/s3-storage.test.js +0 -38
  284. package/tests/searchschema-knex-behavior.test.js +0 -187
  285. package/tests/searchschema-merge.test.js +0 -151
  286. package/tests/socketio.test.js +0 -860
  287. package/tests/storage-mapping.test.js +0 -362
  288. package/tests/test-development-guide.md +0 -370
  289. package/tests/virtual-fields.test.js +0 -404
@@ -1,76 +1,68 @@
1
- # JSON REST API Complete Guide
2
-
3
- Welcome to the comprehensive guide for JSON REST API. This guide will walk you through everything from initial setup to advanced features.
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
- - **[File Uploads](GUIDE_X_File_Uploads.md)**
31
- Handle file uploads with local storage and a mock S3-style demo adapter.
5
+ # JSON REST API guide
32
6
 
33
- - **[Bulk Operations](GUIDE_X_Bulk_Operations.md)**
34
- Handle multiple records efficiently with bulk create, update, and delete operations.
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
- - **[CORS Configuration](GUIDE_X_Cors.md)**
37
- Set up Cross-Origin Resource Sharing for browser-based applications.
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
- - **[Autofiltering](GUIDE_X_Autofiltering.md)**
40
- Scope datasets automatically using configured context values, without baking in auth semantics.
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
- - **[Knex Schema and Migrations](GUIDE_X_Knex_Schema_And_Migrations.md)**
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
- - **[Query Projections](GUIDE_X_Query_Projections.md)**
49
- Use the optional query-projections plugin to add SQL-backed, output-only derived fields that can participate in sorting and cursor pagination.
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
- - **[Writing Plugins](GUIDE_X_Writing_Plugins.md)**
52
- Build plugins against the supported extension surface, including hooks, scope methods, and query-only read fields.
26
+ ## Relationships and queries
53
27
 
54
- - **[Fastify Integration](GUIDE_X_Fastify.md)**
55
- Register REST routes on Fastify and reject malformed write payloads at the transport layer using exported resource schemas.
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
- - **[Socket.IO Integration](GUIDE_X_SocketIO.md)**
58
- Add real-time capabilities to your API with WebSocket support.
36
+ ## Resource behavior
59
37
 
60
- - **[URL Management](GUIDE_X_URL_Management.md)**
61
- Configure URL generation for proxies, CDNs, and multi-tenant scenarios.
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
- - **[Appendices](GUIDE_Y_Appendices.md)**
64
- Reference material, troubleshooting, and additional resources.
46
+ ## Transactions and schema
65
47
 
66
- ## Prerequisites
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
- Before starting this guide, you should have:
53
+ ## Transports and extensions
69
54
 
70
- - Node.js 20+ installed
71
- - Basic knowledge of JavaScript and REST APIs
72
- - Familiarity with npm/yarn package management
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
- Ready to get started? Head to [Chapter 1: Initial Setup](GUIDE_1_Initial_Setup.md) →
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)
@@ -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
- ## Make a new npm project and install the basic NPM modules
10
+ ## Install
5
11
 
6
12
  ```bash
7
13
  mkdir quickstart-api
8
14
  cd quickstart-api
9
- npm init
10
- npm install json-rest-api
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 modules are all defined as peer dependencies and will be
17
-
18
- ## Use ESM syntax for importing
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
- Make sure package.json has `type: "module"` in it
24
+ ## Define resources
21
25
 
22
- ## Create a basic file
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
- // index.js
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
- // Create API instance
47
- const api = new Api({ name: 'book-catalog-api'});
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, indexed: true },
46
+ name: { type: 'string', required: true, max: 255, search: true }
78
47
  },
79
48
  relationships: {
80
- // A publisher has many authors
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, search: true },
55
+ surname: { type: 'string', required: true, max: 100 },
94
56
  publisher_id: { type: 'id', belongsTo: 'publishers', as: 'publisher', nullable: true }
95
57
  },
96
- searchSchema: { // Adding search schema for authors
97
- name: { type: 'string', filterOperator: 'like' },
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.authors.createKnexTable();
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
- Success!
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
- ## Try the API programmatically
71
+ ## Call the API programmatically
133
72
 
134
- Stop the server (CTRL-C).
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
- // Method 1: Simplified mode without inputRecord (most concise)
139
- const penguinResult = await api.resources.publishers.post({
140
- name: 'Penguin Random House'
141
- });
142
- console.log('Created publisher:', inspect(penguinResult));
143
-
144
- // Method 2: Simplified mode with inputRecord (explicit)
145
- const harperResult = await api.resources.publishers.post({
146
- inputRecord: {
147
- name: 'HarperCollins'
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
- // Method 3: Full JSON:API mode (standards compliant)
152
- const oxfordResult = await api.resources.publishers.post({
153
- inputRecord: {
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
- simplified: false
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
- The API supports three different ways to interact with resources programmatically:
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
- 1. **Simplified mode without inputRecord** (default): Pass attributes directly as top-level properties. This is the most concise approach.
201
- 2. **Simplified mode with inputRecord**: Explicitly wrap attributes in an `inputRecord` property. Still returns simplified objects.
202
- 3. **Full JSON:API mode**: Set `simplified: false` to use the complete JSON:API specification format for both requests and responses. This provides full standards compliance and access to all JSON:API features.
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
- Restart the server, and watch the output:
132
+ ## Start the HTTP server
205
133
 
206
- ```text
207
- Created publisher: { id: '1', name: 'Penguin Random House', authors_ids: [] }
208
- JSON:API response: {
209
- data: {
210
- type: 'publishers',
211
- id: '3',
212
- attributes: { name: 'Oxford University Press' },
213
- relationships: { authors: { data: [] } },
214
- links: { self: '/api/publishers/3' }
215
- },
216
- links: { self: '/api/publishers/3' }
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
- ## Try the API via cURL
241
-
242
- With the server running on port 3000 and the data created programmatically above, you can interact with the API using cURL:
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 "Content-Type: application/vnd.api+json" \
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 "Content-Type: application/vnd.api+json" \
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
- ## Read the guide and party!
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
- Happy coding!
178
+ Continue with the [full guide](GUIDE/index.md),
179
+ [API reference](API.md), and [verified backend capabilities](GUIDE/30-backend-capabilities.md).