json-rest-api 1.0.6 → 1.0.8

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 (146) hide show
  1. package/.claude/agents/library-guide-expert.md +29 -0
  2. package/.claude/agents/rest-api-internals-expert.md +53 -0
  3. package/CLAUDE.md +139 -1
  4. package/README.md +2 -5
  5. package/docTest.js +238 -0
  6. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +955 -0
  7. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +54 -0
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +750 -0
  9. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +494 -0
  10. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +398 -0
  11. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +882 -0
  12. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +709 -0
  13. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +1233 -0
  14. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +796 -0
  15. package/{README_X_Relationship_Plugin.md → docs/GUIDE/GUIDE_2_9_Relationships_Urls.md} +1 -4
  16. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +66 -0
  17. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +1246 -0
  18. package/docs/GUIDE/GUIDE_5_Non-Db_Stores.md +0 -0
  19. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +1490 -0
  20. package/{README_X_SocketIO.md → docs/GUIDE/GUIDE_X_SocketIO.md} +17 -17
  21. package/docs/GUIDE/index.md +58 -0
  22. package/docs/GUIDE.md +61 -2238
  23. package/docs/ONBOARDING/Computed_Properties_And_Sparse_Fields.md +398 -0
  24. package/docs/README.md +57 -2239
  25. package/{README_2_Computed_and_hidden_fields.md → docs/README_VARIOUS/GUIDE_2_Computed_and_hidden_fields.md} +22 -17
  26. package/docs/README_VARIOUS/GUIDE_IN_DOCS.md +2277 -0
  27. package/{README.ORIG.md → docs/README_VARIOUS/README.ORIG.md} +8 -8
  28. package/{README_8_Polymorphic_Relationships.md → docs/README_VARIOUS/README_8_Polymorphic_Relationships.md} +1 -1
  29. package/docs/README_VARIOUS/README_IN_DOCS.ms +2277 -0
  30. package/{RELATIONSHIPS_ADVANCED.md → docs/README_VARIOUS/RELATIONSHIPS_ADVANCED.md} +3 -3
  31. package/{correct-schema-format.md → docs/README_VARIOUS/correct-schema-format.md} +13 -13
  32. package/{pagination.md → docs/README_VARIOUS/pagination.md} +11 -8
  33. package/docs/assets/css/style.scss +78 -5
  34. package/docs/index.md +2 -12
  35. package/helper-reorganization-plan.md +85 -0
  36. package/helper-usage-analysis.md +94 -0
  37. package/package.json +5 -4
  38. package/plugins/core/bulk-operations-plugin.js +2 -2
  39. package/plugins/core/connectors/express-plugin.js +99 -33
  40. package/plugins/core/lib/querying/knex-cross-table-search.js +609 -0
  41. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +491 -0
  42. package/plugins/core/lib/querying/knex-pagination-helpers.js +544 -0
  43. package/plugins/core/lib/{knex-process-includes.js → querying/knex-process-includes.js} +65 -50
  44. package/plugins/core/lib/querying/knex-query-helpers-base.js +74 -0
  45. package/plugins/core/lib/{knex-query-helpers.js → querying/knex-query-helpers.js} +416 -180
  46. package/plugins/core/lib/{knex-relationship-includes.js → querying/knex-relationship-includes.js} +430 -114
  47. package/plugins/core/lib/querying/knex-window-queries.js +328 -0
  48. package/plugins/core/lib/querying-writing/compile-schemas.js +328 -0
  49. package/plugins/core/{utils → lib/querying-writing}/connectors-query-parser.js +62 -57
  50. package/plugins/core/lib/{database-capabilities.js → querying-writing/database-capabilities.js} +113 -7
  51. package/plugins/core/lib/querying-writing/database-value-normalizers.js +369 -0
  52. package/plugins/core/lib/querying-writing/default-data-helpers.js +72 -0
  53. package/plugins/core/{utils → lib/querying-writing}/field-utils.js +41 -31
  54. package/plugins/core/{utils → lib/querying-writing}/knex-constants.js +1 -0
  55. package/plugins/core/lib/{knex-field-helpers.js → querying-writing/knex-field-helpers.js} +190 -57
  56. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +162 -0
  57. package/plugins/core/lib/{payload-validators.js → querying-writing/payload-validators.js} +297 -217
  58. package/plugins/core/lib/querying-writing/schema-helpers.js +497 -0
  59. package/plugins/core/lib/querying-writing/scope-validations.js +431 -0
  60. package/plugins/core/lib/{simplified-helpers.js → querying-writing/simplified-helpers.js} +216 -176
  61. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +110 -0
  62. package/plugins/core/lib/writing/many-to-many-manipulations.js +300 -0
  63. package/plugins/core/lib/writing/relationship-processor.js +252 -0
  64. package/plugins/core/rest-api-knex-plugin.js +183 -62
  65. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +7 -0
  66. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +72 -0
  67. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +102 -0
  68. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +50 -0
  69. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +39 -0
  70. package/plugins/core/rest-api-plugin-methods/add-route.js +23 -0
  71. package/plugins/core/rest-api-plugin-methods/check-permissions.js +18 -0
  72. package/plugins/core/rest-api-plugin-methods/common.js +605 -0
  73. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +115 -0
  74. package/plugins/core/rest-api-plugin-methods/delete.js +109 -0
  75. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +186 -0
  76. package/plugins/core/rest-api-plugin-methods/get-related.js +295 -0
  77. package/plugins/core/rest-api-plugin-methods/get-relationship.js +62 -0
  78. package/plugins/core/rest-api-plugin-methods/get.js +187 -0
  79. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +56 -0
  80. package/plugins/core/rest-api-plugin-methods/patch.js +193 -0
  81. package/plugins/core/rest-api-plugin-methods/post-relationship.js +104 -0
  82. package/plugins/core/rest-api-plugin-methods/post.js +157 -0
  83. package/plugins/core/rest-api-plugin-methods/put.js +257 -0
  84. package/plugins/core/rest-api-plugin-methods/query.js +208 -0
  85. package/plugins/core/rest-api-plugin.js +108 -2498
  86. package/plugins/core/socketio-plugin.js +28 -5
  87. package/plugins/storage/local-storage.js +2 -2
  88. package/tests/computed-fields.test.js +483 -0
  89. package/tests/cors.test.js +4 -4
  90. package/tests/curl.test.js +5 -4
  91. package/tests/custom-idproperty-relationships.test.js +891 -0
  92. package/tests/field-getters.test.js +353 -0
  93. package/tests/field-setters.test.js +310 -0
  94. package/tests/fixtures/api-configs.js +800 -28
  95. package/tests/jwt-auth.test.js +0 -2
  96. package/tests/nested-includes.test.js +1 -1
  97. package/tests/pagination-cursor-multifield.test.js +514 -0
  98. package/tests/pagination-enhanced.test.js +12 -9
  99. package/tests/polymorphic-relationships.test.js +10 -8
  100. package/tests/polymorphic-simple.test.js +6 -4
  101. package/tests/positioning-advanced.test.js +12 -12
  102. package/tests/positioning-extended.test.js +25 -25
  103. package/tests/positioning-multifilter.test.js +24 -24
  104. package/tests/positioning.test.js +3 -3
  105. package/tests/query-limits.test.js +24 -8
  106. package/tests/relationship-endpoints.test.js +4 -5
  107. package/tests/relationships.test.js +0 -1
  108. package/tests/socketio.test.js +12 -1
  109. package/tests/virtual-fields.test.js +13 -13
  110. package/PLAN_FOR_WEBSOCKETS.md +0 -398
  111. package/README_1_Initial_Setup.md +0 -393
  112. package/README_X_Hooks.md +0 -647
  113. package/TODO_rest-api-plugin-extras.todo +0 -23
  114. package/connectors_ideas/express-plugin.js +0 -120
  115. package/connectors_ideas/http-plugin.js +0 -138
  116. package/docs/examples/express-plugin.js +0 -366
  117. package/example.js +0 -301
  118. package/plugins/core/HELPER_MODULES.md +0 -285
  119. package/plugins/core/lib/compile-schemas.js +0 -245
  120. package/plugins/core/lib/database-value-normalizers.js +0 -192
  121. package/plugins/core/lib/default-data-helpers.js +0 -100
  122. package/plugins/core/lib/knex-cross-table-search.js +0 -442
  123. package/plugins/core/lib/knex-json-api-helpers.js +0 -84
  124. package/plugins/core/lib/knex-json-api-transformers.js +0 -449
  125. package/plugins/core/lib/knex-pagination-helpers.js +0 -193
  126. package/plugins/core/lib/knex-window-queries.js +0 -142
  127. package/plugins/core/lib/many-to-many-manipulations.js +0 -343
  128. package/plugins/core/lib/relationship-processor.js +0 -278
  129. package/plugins/core/lib/schema-helpers.js +0 -343
  130. package/plugins/core/lib/scope-validations.js +0 -252
  131. package/plugins/core/rest-api-relationships-plugin.js +0 -700
  132. package/plugins/core/utils/knex-query-helpers-base.js +0 -56
  133. /package/{README_X_Permissions.md → docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md} +0 -0
  134. /package/{README_X_Positioning.md → docs/GUIDE/GUIDE_6_Positioning.md} +0 -0
  135. /package/{README_X_Bulk_Operations.md → docs/GUIDE/GUIDE_X_Bulk_Operations.md} +0 -0
  136. /package/{README_X_Cors.md → docs/GUIDE/GUIDE_X_Cors.md} +0 -0
  137. /package/{README_X_Multihome.md → docs/GUIDE/GUIDE_X_Multihome.md} +0 -0
  138. /package/{README_X_Appendices.md → docs/GUIDE/GUIDE_Y_Appendices.md} +0 -0
  139. /package/{QUERY_DEPTH_PROTECTION.md → docs/README_VARIOUS/QUERY_DEPTH_PROTECTION.md} +0 -0
  140. /package/{RELATIONSHIPS.md → docs/README_VARIOUS/RELATIONSHIPS.md} +0 -0
  141. /package/{WEBSOCKET_IMPLEMENTATION_STATUS.md → docs/README_VARIOUS/WEBSOCKET_IMPLEMENTATION_STATUS.md} +0 -0
  142. /package/{helper-functions-chart.md → docs/README_VARIOUS/helper-functions-chart.md} +0 -0
  143. /package/docs/{implementation-hidden-computed-fields.md → README_VARIOUS/implementation-hidden-computed-fields.md} +0 -0
  144. /package/docs/{include-limits-migration-guide.md → README_VARIOUS/include-limits-migration-guide.md} +0 -0
  145. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_behavior.js +0 -0
  146. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_fields_without_defaults.js +0 -0
@@ -1,393 +0,0 @@
1
-
2
- ## Defining the Basic Tables
3
-
4
- The documentation uses a consistent example throughout - a book catalog system with authors, publishers, and countries.
5
-
6
- **Important**: The five tables defined below (countries, publishers, authors, books, and book_authors) form the foundation for all examples, tests, and documentation in this guide. We'll consistently reference this same schema structure to demonstrate all features of the library. At times, we will change the definition of some of them to show specific features.
7
-
8
- Also for brevity, the `inspect()` function will be assumed to be set:
9
-
10
- ```javascript
11
- import { RestApiPlugin, RestApiKnexPlugin } from 'json-rest-api';
12
- import { Api } from 'hooked-api';
13
- import knexLib from 'knex';
14
- import util from 'util';
15
-
16
- // Utility used throughout this guide
17
- const inspect = (obj) => util.inspect(obj, { depth: 5 })
18
-
19
- // Create a Knex instance connected to SQLite in-memory database
20
- const knex = knexLib({
21
- client: 'sqlite3',
22
- connection: {
23
- filename: ':memory:'
24
- },
25
- useNullAsDefault: true
26
- });
27
-
28
- // Create API instance
29
- const api = new Api({
30
- name: 'book-catalog-api',
31
- version: '1.0.0'
32
- });
33
-
34
- // Install plugins
35
- await api.use(RestApiPlugin);
36
- await api.use(RestApiKnexPlugin, { knex });
37
-
38
- // Define schemas for our book catalog system
39
-
40
- // Countries table
41
- await api.addResource('countries', {
42
- schema: {
43
- id: { type: 'id' },
44
- name: { type: 'string', required: true, max: 100, search: true },
45
- code: { type: 'string', max: 2, unique: true, search: true }, // ISO country code
46
- },
47
- relationships: {
48
- publishers: { hasMany: 'publishers', foreignKey: 'country_id' },
49
- books: { hasMany: 'books', foreignKey: 'country_id' }
50
- },
51
- });
52
- await api.resources.countries.createKnexTable()
53
-
54
- // Publishers table
55
- await api.addResource('publishers', {
56
- schema: {
57
- id: { type: 'id' },
58
- name: { type: 'string', required: true, max: 200, search: true },
59
- country_id: { type: 'number', belongsTo: 'countries', as: 'country' },
60
- },
61
- relationships: {
62
- books: { hasMany: 'books', foreignKey: 'publisher_id' },
63
- reviews: { hasMany: 'reviews', via: 'reviewable' }
64
- }
65
- });
66
- await api.resources.publishers.createKnexTable()
67
-
68
- // Authors table
69
- await api.addResource('authors', {
70
- schema: {
71
- id: { type: 'id' },
72
- name: { type: 'string', required: true, max: 200, search: true },
73
- },
74
- relationships: {
75
- books: { hasMany: 'books', through: 'book_authors', foreignKey: 'author_id', otherKey: 'book_id' },
76
- reviews: { hasMany: 'reviews', via: 'reviewable' }
77
- }
78
- });
79
- await api.resources.authors.createKnexTable()
80
-
81
- // Books table
82
- await api.addResource('books', {
83
- schema: {
84
- id: { type: 'id' },
85
- title: { type: 'string', required: true, max: 300, search: true },
86
- country_id: { type: 'number', required: true, belongsTo: 'countries', as: 'country' },
87
- publisher_id: { type: 'number', belongsTo: 'publishers', as: 'publisher' },
88
- year: { type: 'number', search: true },
89
- isbn: { type: 'string', search: true },
90
- inStock: { type: 'boolean', default: true },
91
- rating: { type: 'number', default: 0 },
92
- tags: { type: 'array', default: [] },
93
- metadata: { type: 'object', default: {} }
94
- },
95
- relationships: {
96
- authors: { hasMany: 'authors', through: 'book_authors', foreignKey: 'book_id', otherKey: 'author_id' },
97
- reviews: { hasMany: 'reviews', via: 'reviewable' }
98
- }
99
- });
100
- await api.resources.books.createKnexTable()
101
-
102
- // Book-Authors pivot table (many-to-many relationship)
103
- await api.addResource('book_authors', {
104
- schema: {
105
- id: { type: 'id' },
106
- book_id: { type: 'number', required: true, belongsTo: 'books', as: 'book' },
107
- author_id: { type: 'number', required: true, belongsTo: 'authors', as: 'author' },
108
- }
109
- });
110
- await api.resources.book_authors.createKnexTable()
111
-
112
- // Reviews table (polymorphic - can review books, authors, or publishers)
113
- await api.addResource('reviews', {
114
- schema: {
115
- id: { type: 'id' },
116
- review_author: { type: 'string', required: true, max: 100 },
117
- review_text: { type: 'string', required: true, max: 5000 },
118
- review_rating: { type: 'number', required: true, min: 1, max: 5 },
119
- reviewable_type: { type: 'string', required: true },
120
- reviewable_id: { type: 'number', required: true },
121
- // Define the polymorphic field
122
- reviewable: {
123
- belongsToPolymorphic: {
124
- types: ['books', 'authors', 'publishers'],
125
- typeField: 'reviewable_type',
126
- idField: 'reviewable_id'
127
- },
128
- as: 'reviewable'
129
- }
130
- }
131
- });
132
- await api.resources.reviews.createKnexTable()
133
- ```
134
-
135
- ### Database Options
136
-
137
- The `json-rest-api` library uses `knex` as its database abstraction layer, which supports a wide variety of SQL databases. In the example above, we configured `knex` to use an in-memory SQLite database for simplicity:
138
-
139
- ```javascript
140
- const knex = knexLib({
141
- client: 'sqlite3',
142
- connection: {
143
- filename: ':memory:' // In-memory database for quick examples
144
- },
145
- useNullAsDefault: true // Recommended for SQLite
146
- });
147
- ```
148
-
149
- To connect to a different database, you would simply change the `client` and `connection` properties in the `knexLib` configuration. Here are a few common examples:
150
-
151
- **PostgreSQL:**
152
-
153
- ```javascript
154
- const knex = knexLib({
155
- client: 'pg', // PostgreSQL client
156
- connection: {
157
- host: '127.0.0.1',
158
- user: 'your_username',
159
- password: 'your_password',
160
- database: 'your_database_name',
161
- port: 5432 // Default PostgreSQL port
162
- }
163
- });
164
- ```
165
- **MySQL / MariaDB:**
166
-
167
- ```javascript
168
- const knex = knexLib({
169
- client: 'mysql', // or 'mariasql' for MariaDB
170
- connection: {
171
- host: '127.0.0.1',
172
- user: 'your_username',
173
- password: 'your_password',
174
- database: 'your_database_name',
175
- port: 3306 // Default MySQL/MariaDB port
176
- }
177
- });
178
- ```
179
-
180
- Remember to install the corresponding `knex` driver for your chosen database (e.g., `npm install pg` for PostgreSQL, `npm install mysql2` for MySQL).
181
-
182
- ## Basic Usage
183
-
184
- The `json-rest-api` plugin extends your `hooked-api` instance with powerful RESTful capabilities, allowing you to interact with your defined resources both programmatically within your application code and via standard HTTP requests.
185
-
186
- ### Programmatic Usage
187
-
188
- Once your resources are defined using `api.addResource()`, you can directly call CRUD (Create, Read, Update, Delete) methods on `api.resources.<resourceName>`.
189
-
190
- Let's start by creating a `country` record:
191
-
192
- ```javascript
193
- // Example: Create a country
194
- const countryUs = await api.resources.countries.post({
195
- name: 'United States',
196
- code: 'US'
197
- });
198
- console.log('Created Country:', inspect(countryUs));
199
- // Expected Output:
200
- // TODO: Check what this will return
201
- ```
202
-
203
- Now, let's retrieve this country data using its ID:
204
-
205
- ```javascript
206
- // Example: Refetch a country by ID
207
- const countryUsRefetched = await api.resources.countries.get({
208
- id: countryUs.data.id, // Use the ID returned from the POST operation
209
- });
210
- console.log('Refetched Country:', inspect(countryUsRefetched));
211
- // Expected Output:
212
- // TODO: Check
213
- ```
214
-
215
- ### REST Usage (HTTP Endpoints)
216
-
217
- To expose your API resources via HTTP, you need to install one of the connector plugins:
218
-
219
- * **`ExpressPlugin`**: If you are using `Express.js` in your application.
220
-
221
- * **`(Coming soon)`**: Fastify and Koa are planned and coming soon
222
-
223
- Thanks to the ExpressPlugin, json-rest-api is able to export an Express router that you can just `use()` in Express:
224
-
225
- ```javascript
226
- // In your main application file (e.g., app.js)
227
- import { ExpressPlugin, RestApiPlugin, RestApiKnexPlugin } from 'json-rest-api';
228
- import { Api } from 'hooked-api';
229
- import express from 'express';
230
- import knexLib from 'knex';
231
- import util from 'util';
232
-
233
- // ... (Knex and API instance setup as shown in "Defining the Basic Tables")
234
-
235
- const app = express();
236
-
237
- // Install the Express Plugin
238
- await api.use(ExpressPlugin, {
239
- basePath: '/api' // All API routes will be under /api
240
- });
241
-
242
- // Mount the API router
243
- app.use(api.http.express.router); // Mounts the router generated by ExpressPlugin
244
- // Alternatively, for more control: app.use('/my-custom-path', api.http.express.router);
245
-
246
- app.listen(3000, () => {
247
- console.log('Express server started on port 3000. API available at http://localhost:3000/api');
248
- });
249
- ```
250
-
251
- ### Making the CURL calls
252
-
253
- Once the server is running, you can interact with your API using tools like `curl`.
254
-
255
- **REST Example: Create a Country**
256
-
257
- ```bash
258
- curl -X POST -H "Content-Type: application/vnd.api+json" \
259
- -d '{
260
- "data": {
261
- "type": "countries",
262
- "attributes": {
263
- "name": "United Kingdom",
264
- "code": "UK"
265
- }
266
- }
267
- }' http://localhost:3000/api/countries
268
- ```
269
-
270
- **REST Example: Get a Country by ID**
271
-
272
- ```bash
273
- curl -X GET http://localhost:3000/api/countries/2
274
- ```
275
-
276
-
277
- **From now on, all examples will provide both programmatic usage and `curl` usage.** This ensures you understand how to interact with the API directly in your code and how it translates to standard HTTP requests.
278
-
279
- ### Simplified Mode
280
-
281
- TODO: Explain what simplified mode is, and what its defaults are. API use is simplified, online use is non-simplified.
282
- Explain where the settings come from
283
-
284
- TODO: Explain how to declare 'books' simplified, and show that it will work in simplified mode. Note: cover simplifiedApi
285
- and simplifiedTransport (as options).
286
-
287
- In "simplified mode":
288
-
289
- * **Input:** You can pass plain JavaScript objects directly for attributes, and related resource IDs for relationships.
290
-
291
- * **Output:** Responses are flattened, with `id` and `attributes` merged directly into the top-level object, and `belongsTo` relationships are represented as foreign key IDs. <--- TODO: check this
292
-
293
- The `simplified` mode is controlled by options passed during plugin installation or directly to method calls. It cascades, meaning a setting at a lower level overrides a higher one:
294
-
295
- TODO: Redo the next bit, since now we have two different flags, one of the API and one for the network connections
296
- 1. **Global (default):** `RestApiPlugin`'s options (`simplified: true/false`).
297
-
298
- 2. **Per-Resource:** `addResource()` options (`simplified: true/false`).
299
-
300
- 3. **Per-Method Call:** The `params` object passed to individual `api.resources.<resource>.method()` calls.
301
-
302
- By default, `simplifiedApi` is `true` and simplifiedTransport is `false` for HTTP calls (to maintain JSON:API compliance on the wire).
303
-
304
-
305
- ### Return Full Record
306
-
307
- TODO: Explain the returnFullRecord option in detail
308
-
309
- ### Search (Filtering)
310
-
311
- TODO
312
-
313
- ### Sparse Fields
314
-
315
- The JSON:API specification allows clients to request only a subset of fields for a given resource, a feature known as "sparse fieldsets". This is crucial for optimizing network traffic by reducing the size of the response payload, especially when dealing with large records.
316
-
317
- You can specify which fields to return using the `fields[resourceType]=field1,field2` query parameter.
318
-
319
- **Programmatic Example: Get only `name` for `countries`**
320
-
321
- ```javascript
322
- TODO
323
- ```
324
-
325
- **HTTP Example: Get Books with only `title` and `isbn`**
326
-
327
- TODO
328
-
329
- Sparse fieldsets also apply to `included` resources. If you request related data, you can specify which fields of those related resources should be returned as well.
330
-
331
-
332
-
333
- ## belongsTo records
334
-
335
- ### Search (belongsTo)
336
-
337
- ### Sparse fields (belongsTo)
338
-
339
-
340
-
341
-
342
- ## hasMany records
343
-
344
- ### Search (hasMany)
345
-
346
- ### Sparse fields (hasMany)
347
-
348
-
349
-
350
-
351
- ## hasMany records
352
-
353
- ### Search (hasMany)
354
-
355
- ### Sparse fields (hasMany)
356
-
357
-
358
-
359
-
360
- ## Many to many (hasMany with through records)
361
-
362
- ### Search (many to many)
363
-
364
- ### Sparse fields (many to many)
365
-
366
-
367
-
368
-
369
-
370
-
371
- ## Next Steps
372
-
373
- - [Schema Definition Guide](docs/schemas.md) - Learn about all field types and validation rules
374
- - [Relationships Guide](docs/relationships.md) - Deep dive into relationship configuration
375
- - [Querying Guide](docs/querying.md) - Advanced filtering, sorting, and pagination
376
- - [File Uploads Guide](docs/file-uploads.md) - Handle file uploads with various storage backends
377
- - [Authentication Guide](docs/authentication.md) - Add authentication and authorization
378
- - [Testing Guide](docs/testing.md) - Write tests for your API
379
-
380
- ## License
381
-
382
- GPL-3.0-or-later
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-