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.
Files changed (294) 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 +744 -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 +733 -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 +103 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +74 -30
  38. package/docs/GUIDE/33-migrating-to-v2.md +3838 -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 +37 -0
  44. package/index.js +3 -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 +70 -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 -177
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +586 -418
  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 +120 -56
  71. package/plugins/core/lib/anyapi/stored-definition.js +109 -0
  72. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  73. package/plugins/core/lib/dbIntrospection.js +228 -21
  74. package/plugins/core/lib/dbTablesOperations.js +409 -92
  75. package/plugins/core/lib/fractional-positioning.js +12 -48
  76. package/plugins/core/lib/querying/identifier-query.js +19 -0
  77. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  78. package/plugins/core/lib/querying/include-to-many.js +428 -0
  79. package/plugins/core/lib/querying/include-to-one.js +579 -0
  80. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  81. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  82. package/plugins/core/lib/querying/knex-pagination-helpers.js +48 -317
  83. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  84. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  85. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  86. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  87. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  88. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  89. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  90. package/plugins/core/lib/querying/query-constraint.js +27 -0
  91. package/plugins/core/lib/querying/query-field-sort-helpers.js +134 -37
  92. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  93. package/plugins/core/lib/querying/sort-helpers.js +13 -1
  94. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  95. package/plugins/core/lib/querying/url-helpers.js +11 -4
  96. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  97. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  98. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  99. package/plugins/core/lib/querying-writing/database-value-normalizers.js +179 -194
  100. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  101. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  102. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  103. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  104. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  105. package/plugins/core/lib/querying-writing/knex-field-helpers.js +100 -290
  106. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  107. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  108. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  109. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  110. package/plugins/core/lib/querying-writing/request-contracts.js +93 -38
  111. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  112. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  113. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  114. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  115. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  116. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  117. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  118. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  119. package/plugins/core/lib/storage/storage-adapter.js +128 -62
  120. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  121. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  122. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  123. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  124. package/plugins/core/lib/writing/resource-version.js +172 -0
  125. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  126. package/plugins/core/rest-api-anyapi-knex-plugin.js +290 -2475
  127. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  128. package/plugins/core/rest-api-cors-plugin.js +52 -205
  129. package/plugins/core/rest-api-knex-plugin.js +45 -1077
  130. package/plugins/core/rest-api-label-plugin.js +25 -38
  131. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  132. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  133. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  134. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  135. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  136. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  137. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  138. package/plugins/core/rest-api-plugin-methods/common.js +291 -395
  139. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  140. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  141. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -148
  142. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  143. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  144. package/plugins/core/rest-api-plugin-methods/get.js +36 -68
  145. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  146. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  147. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  148. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  149. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  150. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  151. package/plugins/core/rest-api-plugin-methods/query.js +37 -81
  152. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  153. package/plugins/core/rest-api-plugin.js +32 -46
  154. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  155. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  156. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  157. package/plugins/core/socketio-plugin.js +364 -344
  158. package/plugins/storage/local-storage.js +40 -36
  159. package/types/anyapi.d.ts +30 -0
  160. package/types/autofilter.d.ts +57 -0
  161. package/types/bulk-methods.d.ts +63 -0
  162. package/types/errors.d.ts +118 -0
  163. package/types/fastify-options.d.ts +19 -0
  164. package/types/file-detectors.d.ts +33 -0
  165. package/types/file-storage.d.ts +48 -0
  166. package/types/hook-context.d.ts +180 -0
  167. package/types/plugin-options.d.ts +65 -0
  168. package/types/relationship-methods.d.ts +74 -0
  169. package/types/representations.d.ts +50 -0
  170. package/types/resource-methods.d.ts +95 -0
  171. package/types/resource-schema.d.ts +157 -0
  172. package/types/row-policy.d.ts +31 -0
  173. package/types/runtime.d.ts +132 -0
  174. package/types/transactions.d.ts +21 -0
  175. package/.claude/agents/library-guide-expert.md +0 -30
  176. package/.claude/agents/rest-api-internals-expert.md +0 -54
  177. package/.claude/settings.local.json +0 -70
  178. package/AGENTS.md +0 -34
  179. package/CLAUDE.md +0 -160
  180. package/CRUSH.md +0 -55
  181. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  182. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  183. package/TODO.todo +0 -13
  184. package/connectors_ideas/fastify.js +0 -217
  185. package/connectors_ideas/koa-plugin.js +0 -112
  186. package/docs/.bundle/config +0 -2
  187. package/docs/COMPARISON.md +0 -433
  188. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  189. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  190. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  191. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  192. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  193. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  194. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  195. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1247
  196. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  197. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  198. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  199. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  200. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  201. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  202. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  203. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  204. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  205. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  206. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  207. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  208. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  209. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  210. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  211. package/docs/Gemfile +0 -6
  212. package/docs/Gemfile.lock +0 -308
  213. package/docs/ONBOARDING.md +0 -315
  214. package/docs/_config.yml +0 -36
  215. package/docs/_layouts/default.html +0 -123
  216. package/docs/apple-touch-icon.svg +0 -4
  217. package/docs/assets/css/style.scss +0 -392
  218. package/docs/favicon.svg +0 -4
  219. package/docs/index.md +0 -164
  220. package/docs/mini-guides/file-uploads-complete.md +0 -161
  221. package/eslint.config.js +0 -13
  222. package/examples/url-override-example.js +0 -137
  223. package/fixing_plan.md +0 -112
  224. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  225. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  226. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  227. package/plugins/storage/s3-storage.js +0 -93
  228. package/quickTest.js +0 -136
  229. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  230. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  231. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  232. package/scripts/run-docs.js +0 -133
  233. package/test-debug.js +0 -59
  234. package/tests/README.md +0 -202
  235. package/tests/TEST_TEMPLATE.test.js +0 -178
  236. package/tests/anyapi-basic.test.js +0 -105
  237. package/tests/anyapi-cursor-pagination.test.js +0 -148
  238. package/tests/anyapi-custom-idproperty.test.js +0 -163
  239. package/tests/autofilter.test.js +0 -463
  240. package/tests/bulk-operations.test.js +0 -657
  241. package/tests/computed-fields.test.js +0 -586
  242. package/tests/cors.test.js +0 -834
  243. package/tests/curl.test.js +0 -467
  244. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  245. package/tests/custom-id-simplified-post.test.js +0 -75
  246. package/tests/custom-idproperty-relationships.test.js +0 -932
  247. package/tests/db-introspection.test.js +0 -521
  248. package/tests/db-table-operations.test.js +0 -798
  249. package/tests/fastify-plugin.test.js +0 -184
  250. package/tests/field-getters.test.js +0 -370
  251. package/tests/field-setters.test.js +0 -306
  252. package/tests/file-handling.test.js +0 -155
  253. package/tests/fixtures/api-configs.js +0 -2566
  254. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  255. package/tests/helpers/fake-fastify.js +0 -99
  256. package/tests/helpers/storage-mode.js +0 -65
  257. package/tests/helpers/test-utils.js +0 -203
  258. package/tests/http-connectors-parity.test.js +0 -395
  259. package/tests/id-normalization.test.js +0 -444
  260. package/tests/include-depth-validation.test.js +0 -331
  261. package/tests/includes.test.js +0 -427
  262. package/tests/local-storage.test.js +0 -96
  263. package/tests/logical-id-write-validation.test.js +0 -151
  264. package/tests/nested-includes.test.js +0 -617
  265. package/tests/pagination-boundaries.test.js +0 -154
  266. package/tests/pagination-contract.test.js +0 -122
  267. package/tests/pagination-cursor-multifield.test.js +0 -641
  268. package/tests/pagination-enhanced.test.js +0 -563
  269. package/tests/polymorphic-relationships.test.js +0 -347
  270. package/tests/polymorphic-simple.test.js +0 -148
  271. package/tests/positioning-advanced.test.js +0 -692
  272. package/tests/positioning-extended.test.js +0 -915
  273. package/tests/positioning-multifilter.test.js +0 -699
  274. package/tests/positioning.test.js +0 -560
  275. package/tests/post-commit-hooks.test.js +0 -120
  276. package/tests/projected-fields.test.js +0 -319
  277. package/tests/public-exports.test.js +0 -15
  278. package/tests/put-create-parity.test.js +0 -216
  279. package/tests/queries.test.js +0 -521
  280. package/tests/query-limits.test.js +0 -584
  281. package/tests/relationship-endpoints.test.js +0 -620
  282. package/tests/relationship-include-storage-adapter.test.js +0 -56
  283. package/tests/relationships.test.js +0 -681
  284. package/tests/rest-api.test.js +0 -337
  285. package/tests/return-record-settings.test.js +0 -184
  286. package/tests/row-policy.test.js +0 -489
  287. package/tests/s3-storage.test.js +0 -38
  288. package/tests/searchschema-knex-behavior.test.js +0 -187
  289. package/tests/searchschema-merge.test.js +0 -151
  290. package/tests/socketio.test.js +0 -860
  291. package/tests/storage-mapping.test.js +0 -362
  292. package/tests/temporal-boundaries.test.js +0 -208
  293. package/tests/test-development-guide.md +0 -370
  294. 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).