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.
- package/.claude/agents/library-guide-expert.md +29 -0
- package/.claude/agents/rest-api-internals-expert.md +53 -0
- package/CLAUDE.md +139 -1
- package/README.md +2 -5
- package/docTest.js +238 -0
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +955 -0
- package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +54 -0
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +750 -0
- package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +494 -0
- package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +398 -0
- package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +882 -0
- package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +709 -0
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +1233 -0
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +796 -0
- package/{README_X_Relationship_Plugin.md → docs/GUIDE/GUIDE_2_9_Relationships_Urls.md} +1 -4
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +66 -0
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +1246 -0
- package/docs/GUIDE/GUIDE_5_Non-Db_Stores.md +0 -0
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +1490 -0
- package/{README_X_SocketIO.md → docs/GUIDE/GUIDE_X_SocketIO.md} +17 -17
- package/docs/GUIDE/index.md +58 -0
- package/docs/GUIDE.md +61 -2238
- package/docs/ONBOARDING/Computed_Properties_And_Sparse_Fields.md +398 -0
- package/docs/README.md +57 -2239
- package/{README_2_Computed_and_hidden_fields.md → docs/README_VARIOUS/GUIDE_2_Computed_and_hidden_fields.md} +22 -17
- package/docs/README_VARIOUS/GUIDE_IN_DOCS.md +2277 -0
- package/{README.ORIG.md → docs/README_VARIOUS/README.ORIG.md} +8 -8
- package/{README_8_Polymorphic_Relationships.md → docs/README_VARIOUS/README_8_Polymorphic_Relationships.md} +1 -1
- package/docs/README_VARIOUS/README_IN_DOCS.ms +2277 -0
- package/{RELATIONSHIPS_ADVANCED.md → docs/README_VARIOUS/RELATIONSHIPS_ADVANCED.md} +3 -3
- package/{correct-schema-format.md → docs/README_VARIOUS/correct-schema-format.md} +13 -13
- package/{pagination.md → docs/README_VARIOUS/pagination.md} +11 -8
- package/docs/assets/css/style.scss +78 -5
- package/docs/index.md +2 -12
- package/helper-reorganization-plan.md +85 -0
- package/helper-usage-analysis.md +94 -0
- package/package.json +5 -4
- package/plugins/core/bulk-operations-plugin.js +2 -2
- package/plugins/core/connectors/express-plugin.js +99 -33
- package/plugins/core/lib/querying/knex-cross-table-search.js +609 -0
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +491 -0
- package/plugins/core/lib/querying/knex-pagination-helpers.js +544 -0
- package/plugins/core/lib/{knex-process-includes.js → querying/knex-process-includes.js} +65 -50
- package/plugins/core/lib/querying/knex-query-helpers-base.js +74 -0
- package/plugins/core/lib/{knex-query-helpers.js → querying/knex-query-helpers.js} +416 -180
- package/plugins/core/lib/{knex-relationship-includes.js → querying/knex-relationship-includes.js} +430 -114
- package/plugins/core/lib/querying/knex-window-queries.js +328 -0
- package/plugins/core/lib/querying-writing/compile-schemas.js +328 -0
- package/plugins/core/{utils → lib/querying-writing}/connectors-query-parser.js +62 -57
- package/plugins/core/lib/{database-capabilities.js → querying-writing/database-capabilities.js} +113 -7
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +369 -0
- package/plugins/core/lib/querying-writing/default-data-helpers.js +72 -0
- package/plugins/core/{utils → lib/querying-writing}/field-utils.js +41 -31
- package/plugins/core/{utils → lib/querying-writing}/knex-constants.js +1 -0
- package/plugins/core/lib/{knex-field-helpers.js → querying-writing/knex-field-helpers.js} +190 -57
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +162 -0
- package/plugins/core/lib/{payload-validators.js → querying-writing/payload-validators.js} +297 -217
- package/plugins/core/lib/querying-writing/schema-helpers.js +497 -0
- package/plugins/core/lib/querying-writing/scope-validations.js +431 -0
- package/plugins/core/lib/{simplified-helpers.js → querying-writing/simplified-helpers.js} +216 -176
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +110 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +300 -0
- package/plugins/core/lib/writing/relationship-processor.js +252 -0
- package/plugins/core/rest-api-knex-plugin.js +183 -62
- package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +7 -0
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +72 -0
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +102 -0
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +50 -0
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +39 -0
- package/plugins/core/rest-api-plugin-methods/add-route.js +23 -0
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +18 -0
- package/plugins/core/rest-api-plugin-methods/common.js +605 -0
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +115 -0
- package/plugins/core/rest-api-plugin-methods/delete.js +109 -0
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +186 -0
- package/plugins/core/rest-api-plugin-methods/get-related.js +295 -0
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +62 -0
- package/plugins/core/rest-api-plugin-methods/get.js +187 -0
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +56 -0
- package/plugins/core/rest-api-plugin-methods/patch.js +193 -0
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +104 -0
- package/plugins/core/rest-api-plugin-methods/post.js +157 -0
- package/plugins/core/rest-api-plugin-methods/put.js +257 -0
- package/plugins/core/rest-api-plugin-methods/query.js +208 -0
- package/plugins/core/rest-api-plugin.js +108 -2498
- package/plugins/core/socketio-plugin.js +28 -5
- package/plugins/storage/local-storage.js +2 -2
- package/tests/computed-fields.test.js +483 -0
- package/tests/cors.test.js +4 -4
- package/tests/curl.test.js +5 -4
- package/tests/custom-idproperty-relationships.test.js +891 -0
- package/tests/field-getters.test.js +353 -0
- package/tests/field-setters.test.js +310 -0
- package/tests/fixtures/api-configs.js +800 -28
- package/tests/jwt-auth.test.js +0 -2
- package/tests/nested-includes.test.js +1 -1
- package/tests/pagination-cursor-multifield.test.js +514 -0
- package/tests/pagination-enhanced.test.js +12 -9
- package/tests/polymorphic-relationships.test.js +10 -8
- package/tests/polymorphic-simple.test.js +6 -4
- package/tests/positioning-advanced.test.js +12 -12
- package/tests/positioning-extended.test.js +25 -25
- package/tests/positioning-multifilter.test.js +24 -24
- package/tests/positioning.test.js +3 -3
- package/tests/query-limits.test.js +24 -8
- package/tests/relationship-endpoints.test.js +4 -5
- package/tests/relationships.test.js +0 -1
- package/tests/socketio.test.js +12 -1
- package/tests/virtual-fields.test.js +13 -13
- package/PLAN_FOR_WEBSOCKETS.md +0 -398
- package/README_1_Initial_Setup.md +0 -393
- package/README_X_Hooks.md +0 -647
- package/TODO_rest-api-plugin-extras.todo +0 -23
- package/connectors_ideas/express-plugin.js +0 -120
- package/connectors_ideas/http-plugin.js +0 -138
- package/docs/examples/express-plugin.js +0 -366
- package/example.js +0 -301
- package/plugins/core/HELPER_MODULES.md +0 -285
- package/plugins/core/lib/compile-schemas.js +0 -245
- package/plugins/core/lib/database-value-normalizers.js +0 -192
- package/plugins/core/lib/default-data-helpers.js +0 -100
- package/plugins/core/lib/knex-cross-table-search.js +0 -442
- package/plugins/core/lib/knex-json-api-helpers.js +0 -84
- package/plugins/core/lib/knex-json-api-transformers.js +0 -449
- package/plugins/core/lib/knex-pagination-helpers.js +0 -193
- package/plugins/core/lib/knex-window-queries.js +0 -142
- package/plugins/core/lib/many-to-many-manipulations.js +0 -343
- package/plugins/core/lib/relationship-processor.js +0 -278
- package/plugins/core/lib/schema-helpers.js +0 -343
- package/plugins/core/lib/scope-validations.js +0 -252
- package/plugins/core/rest-api-relationships-plugin.js +0 -700
- package/plugins/core/utils/knex-query-helpers-base.js +0 -56
- /package/{README_X_Permissions.md → docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md} +0 -0
- /package/{README_X_Positioning.md → docs/GUIDE/GUIDE_6_Positioning.md} +0 -0
- /package/{README_X_Bulk_Operations.md → docs/GUIDE/GUIDE_X_Bulk_Operations.md} +0 -0
- /package/{README_X_Cors.md → docs/GUIDE/GUIDE_X_Cors.md} +0 -0
- /package/{README_X_Multihome.md → docs/GUIDE/GUIDE_X_Multihome.md} +0 -0
- /package/{README_X_Appendices.md → docs/GUIDE/GUIDE_Y_Appendices.md} +0 -0
- /package/{QUERY_DEPTH_PROTECTION.md → docs/README_VARIOUS/QUERY_DEPTH_PROTECTION.md} +0 -0
- /package/{RELATIONSHIPS.md → docs/README_VARIOUS/RELATIONSHIPS.md} +0 -0
- /package/{WEBSOCKET_IMPLEMENTATION_STATUS.md → docs/README_VARIOUS/WEBSOCKET_IMPLEMENTATION_STATUS.md} +0 -0
- /package/{helper-functions-chart.md → docs/README_VARIOUS/helper-functions-chart.md} +0 -0
- /package/docs/{implementation-hidden-computed-fields.md → README_VARIOUS/implementation-hidden-computed-fields.md} +0 -0
- /package/docs/{include-limits-migration-guide.md → README_VARIOUS/include-limits-migration-guide.md} +0 -0
- /package/{readmeSnippets → docs/README_VARIOUS}/test_put_behavior.js +0 -0
- /package/{readmeSnippets → docs/README_VARIOUS}/test_put_fields_without_defaults.js +0 -0
|
@@ -223,13 +223,13 @@ api.addResource('users', {
|
|
|
223
223
|
```javascript
|
|
224
224
|
searchSchema: {
|
|
225
225
|
// Simple field search
|
|
226
|
-
title: { type: 'string',
|
|
226
|
+
title: { type: 'string', filterOperator: 'like' },
|
|
227
227
|
|
|
228
228
|
// Cross-table search
|
|
229
229
|
authorName: {
|
|
230
230
|
type: 'string',
|
|
231
231
|
actualField: 'users.name', // Table.field notation
|
|
232
|
-
|
|
232
|
+
filterOperator: 'like'
|
|
233
233
|
},
|
|
234
234
|
|
|
235
235
|
// Multi-field search
|
|
@@ -254,7 +254,7 @@ searchSchema: {
|
|
|
254
254
|
searchSchema: {
|
|
255
255
|
trackableTitle: {
|
|
256
256
|
type: 'string',
|
|
257
|
-
|
|
257
|
+
filterOperator: 'like',
|
|
258
258
|
polymorphicField: 'trackable', // References relationship name
|
|
259
259
|
targetFields: {
|
|
260
260
|
articles: 'title', // When type=articles, search title
|
|
@@ -6,7 +6,7 @@ The format you're using with `indexed: true` is not recognized by the REST API p
|
|
|
6
6
|
```javascript
|
|
7
7
|
// INCORRECT - This won't work for filtering
|
|
8
8
|
{
|
|
9
|
-
title: { type: 'string', indexed: true, search: {
|
|
9
|
+
title: { type: 'string', indexed: true, search: { filterOperator: 'like' } },
|
|
10
10
|
status: { type: 'string', indexed: true, search: true }
|
|
11
11
|
}
|
|
12
12
|
```
|
|
@@ -43,13 +43,13 @@ For partial string matching:
|
|
|
43
43
|
title: {
|
|
44
44
|
type: 'string',
|
|
45
45
|
search: {
|
|
46
|
-
|
|
46
|
+
filterOperator: 'like' // Enables LIKE filtering
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
body: {
|
|
50
50
|
type: 'string',
|
|
51
51
|
search: {
|
|
52
|
-
|
|
52
|
+
filterOperator: 'like'
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -67,10 +67,10 @@ For creating multiple filter parameters from a single field:
|
|
|
67
67
|
type: 'datetime',
|
|
68
68
|
search: {
|
|
69
69
|
published_after: {
|
|
70
|
-
|
|
70
|
+
filterOperator: '>='
|
|
71
71
|
},
|
|
72
72
|
published_before: {
|
|
73
|
-
|
|
73
|
+
filterOperator: '<='
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -119,7 +119,7 @@ api.addResource('products', {
|
|
|
119
119
|
searchSchema: {
|
|
120
120
|
name: {
|
|
121
121
|
type: 'string',
|
|
122
|
-
|
|
122
|
+
filterOperator: 'like'
|
|
123
123
|
},
|
|
124
124
|
category: {
|
|
125
125
|
type: 'string' // Exact match
|
|
@@ -127,12 +127,12 @@ api.addResource('products', {
|
|
|
127
127
|
price_min: {
|
|
128
128
|
type: 'number',
|
|
129
129
|
actualField: 'price',
|
|
130
|
-
|
|
130
|
+
filterOperator: '>='
|
|
131
131
|
},
|
|
132
132
|
price_max: {
|
|
133
133
|
type: 'number',
|
|
134
134
|
actualField: 'price',
|
|
135
|
-
|
|
135
|
+
filterOperator: '<='
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
});
|
|
@@ -151,7 +151,7 @@ const articlesSchema = {
|
|
|
151
151
|
type: 'string',
|
|
152
152
|
required: true,
|
|
153
153
|
search: {
|
|
154
|
-
|
|
154
|
+
filterOperator: 'like' // Enables contains/LIKE search
|
|
155
155
|
}
|
|
156
156
|
},
|
|
157
157
|
|
|
@@ -173,10 +173,10 @@ const articlesSchema = {
|
|
|
173
173
|
type: 'datetime',
|
|
174
174
|
search: {
|
|
175
175
|
created_after: {
|
|
176
|
-
|
|
176
|
+
filterOperator: '>='
|
|
177
177
|
},
|
|
178
178
|
created_before: {
|
|
179
|
-
|
|
179
|
+
filterOperator: '<='
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
},
|
|
@@ -199,8 +199,8 @@ api.addResource('articles', {
|
|
|
199
199
|
|
|
200
200
|
1. **Remove `indexed: true`** - This property is not used by the REST API plugin for filtering
|
|
201
201
|
2. **Use `search: true`** for simple equality filters
|
|
202
|
-
3. **Use `search: {
|
|
203
|
-
4. **Use `search: { field_name: {
|
|
202
|
+
3. **Use `search: { filterOperator: 'like' }`** for contains/partial matching
|
|
203
|
+
4. **Use `search: { field_name: { filterOperator: 'operator' } }`** for custom filter names
|
|
204
204
|
5. The filter validation happens in the `query` method of the REST API plugin
|
|
205
205
|
6. If no `searchSchema` is provided, it's automatically generated from fields with the `search` property
|
|
206
206
|
|
|
@@ -165,31 +165,34 @@ const secondPage = await api.resources.books.query({
|
|
|
165
165
|
"pageSize": 5,
|
|
166
166
|
"hasMore": true,
|
|
167
167
|
"cursor": {
|
|
168
|
-
"next": "
|
|
168
|
+
"next": "id:10" // Simple cursor format
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
},
|
|
172
172
|
"links": {
|
|
173
173
|
"self": "https://api.example.com/v1/books?page[size]=5&sort=-id",
|
|
174
174
|
"first": "https://api.example.com/v1/books?page[size]=5&sort=-id",
|
|
175
|
-
"next": "https://api.example.com/v1/books?page[size]=5&sort=-id&page[after]=
|
|
175
|
+
"next": "https://api.example.com/v1/books?page[size]=5&sort=-id&page[after]=id:10"
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
### How Cursors Work
|
|
181
181
|
|
|
182
|
-
Cursors
|
|
182
|
+
Cursors use a simple format containing the sort field values of the last record:
|
|
183
183
|
|
|
184
184
|
```javascript
|
|
185
|
-
//
|
|
186
|
-
const cursor = "
|
|
185
|
+
// Single field cursor (id=10)
|
|
186
|
+
const cursor = "id:10";
|
|
187
187
|
|
|
188
|
-
//
|
|
189
|
-
|
|
188
|
+
// Multi-field cursor (category='Fruit', name='Cherry')
|
|
189
|
+
const cursor = "category:Fruit,name:Cherry";
|
|
190
|
+
|
|
191
|
+
// With special characters (URL-encoded values)
|
|
192
|
+
const cursor = "title:Chapter%202%3A%20The%20Journey";
|
|
190
193
|
```
|
|
191
194
|
|
|
192
|
-
This allows efficient pagination by using WHERE clauses instead of OFFSET.
|
|
195
|
+
This allows efficient pagination by using WHERE clauses instead of OFFSET. Values are URL-encoded to safely handle special characters like colons and commas.
|
|
193
196
|
|
|
194
197
|
## Pagination Metadata
|
|
195
198
|
|
|
@@ -180,13 +180,86 @@ pre code {
|
|
|
180
180
|
line-height: 1.5;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
.
|
|
185
|
-
.
|
|
186
|
-
.
|
|
187
|
-
.
|
|
183
|
+
/* Rouge syntax highlighting - VS Code Dark+ theme */
|
|
184
|
+
.highlight .hll { background-color: #515151 }
|
|
185
|
+
.highlight { color: #d4d4d4; }
|
|
186
|
+
.highlight .c { color: #6a9955 } /* Comment */
|
|
187
|
+
.highlight .err { color: #f44747 } /* Error */
|
|
188
|
+
.highlight .k { color: #569cd6 } /* Keyword */
|
|
189
|
+
.highlight .l { color: #b5cea8 } /* Literal */
|
|
190
|
+
.highlight .n { color: #d4d4d4 } /* Name */
|
|
191
|
+
.highlight .o { color: #d4d4d4 } /* Operator */
|
|
192
|
+
.highlight .p { color: #d4d4d4 } /* Punctuation */
|
|
193
|
+
.highlight .cm { color: #6a9955 } /* Comment.Multiline */
|
|
194
|
+
.highlight .cp { color: #6a9955 } /* Comment.Preproc */
|
|
195
|
+
.highlight .c1 { color: #6a9955 } /* Comment.Single */
|
|
196
|
+
.highlight .cs { color: #6a9955 } /* Comment.Special */
|
|
197
|
+
.highlight .gd { color: #f44747 } /* Generic.Deleted */
|
|
198
|
+
.highlight .ge { font-style: italic } /* Generic.Emph */
|
|
199
|
+
.highlight .gh { color: #d4d4d4; font-weight: bold } /* Generic.Heading */
|
|
200
|
+
.highlight .gi { color: #4ec9b0 } /* Generic.Inserted */
|
|
201
|
+
.highlight .gp { color: #6a9955; font-weight: bold } /* Generic.Prompt */
|
|
202
|
+
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
|
203
|
+
.highlight .gu { color: #d4d4d4; font-weight: bold } /* Generic.Subheading */
|
|
204
|
+
.highlight .kc { color: #569cd6 } /* Keyword.Constant */
|
|
205
|
+
.highlight .kd { color: #569cd6 } /* Keyword.Declaration */
|
|
206
|
+
.highlight .kn { color: #c586c0 } /* Keyword.Namespace */
|
|
207
|
+
.highlight .kp { color: #569cd6 } /* Keyword.Pseudo */
|
|
208
|
+
.highlight .kr { color: #569cd6 } /* Keyword.Reserved */
|
|
209
|
+
.highlight .kt { color: #4ec9b0 } /* Keyword.Type */
|
|
210
|
+
.highlight .ld { color: #ce9178 } /* Literal.Date */
|
|
211
|
+
.highlight .m { color: #b5cea8 } /* Literal.Number */
|
|
212
|
+
.highlight .s { color: #ce9178 } /* Literal.String */
|
|
213
|
+
.highlight .na { color: #9cdcfe } /* Name.Attribute */
|
|
214
|
+
.highlight .nb { color: #9cdcfe } /* Name.Builtin */
|
|
215
|
+
.highlight .nc { color: #4ec9b0 } /* Name.Class */
|
|
216
|
+
.highlight .no { color: #569cd6 } /* Name.Constant */
|
|
217
|
+
.highlight .nd { color: #c586c0 } /* Name.Decorator */
|
|
218
|
+
.highlight .ni { color: #d4d4d4 } /* Name.Entity */
|
|
219
|
+
.highlight .ne { color: #4ec9b0 } /* Name.Exception */
|
|
220
|
+
.highlight .nf { color: #dcdcaa } /* Name.Function */
|
|
221
|
+
.highlight .nl { color: #d4d4d4 } /* Name.Label */
|
|
222
|
+
.highlight .nn { color: #d4d4d4 } /* Name.Namespace */
|
|
223
|
+
.highlight .nx { color: #9cdcfe } /* Name.Other */
|
|
224
|
+
.highlight .py { color: #d4d4d4 } /* Name.Property */
|
|
225
|
+
.highlight .nt { color: #569cd6 } /* Name.Tag */
|
|
226
|
+
.highlight .nv { color: #9cdcfe } /* Name.Variable */
|
|
227
|
+
.highlight .ow { color: #c586c0 } /* Operator.Word */
|
|
228
|
+
.highlight .w { color: #d4d4d4 } /* Text.Whitespace */
|
|
229
|
+
.highlight .mf { color: #b5cea8 } /* Literal.Number.Float */
|
|
230
|
+
.highlight .mh { color: #b5cea8 } /* Literal.Number.Hex */
|
|
231
|
+
.highlight .mi { color: #b5cea8 } /* Literal.Number.Integer */
|
|
232
|
+
.highlight .mo { color: #b5cea8 } /* Literal.Number.Oct */
|
|
233
|
+
.highlight .sb { color: #ce9178 } /* Literal.String.Backtick */
|
|
234
|
+
.highlight .sc { color: #ce9178 } /* Literal.String.Char */
|
|
235
|
+
.highlight .sd { color: #6a9955 } /* Literal.String.Doc */
|
|
236
|
+
.highlight .s2 { color: #ce9178 } /* Literal.String.Double */
|
|
237
|
+
.highlight .se { color: #d7ba7d } /* Literal.String.Escape */
|
|
238
|
+
.highlight .sh { color: #ce9178 } /* Literal.String.Heredoc */
|
|
239
|
+
.highlight .si { color: #ce9178 } /* Literal.String.Interpol */
|
|
240
|
+
.highlight .sx { color: #ce9178 } /* Literal.String.Other */
|
|
241
|
+
.highlight .sr { color: #d16969 } /* Literal.String.Regex */
|
|
242
|
+
.highlight .s1 { color: #ce9178 } /* Literal.String.Single */
|
|
243
|
+
.highlight .ss { color: #ce9178 } /* Literal.String.Symbol */
|
|
244
|
+
.highlight .bp { color: #9cdcfe } /* Name.Builtin.Pseudo */
|
|
245
|
+
.highlight .vc { color: #9cdcfe } /* Name.Variable.Class */
|
|
246
|
+
.highlight .vg { color: #9cdcfe } /* Name.Variable.Global */
|
|
247
|
+
.highlight .vi { color: #9cdcfe } /* Name.Variable.Instance */
|
|
248
|
+
.highlight .il { color: #b5cea8 } /* Literal.Number.Integer.Long */
|
|
249
|
+
|
|
250
|
+
/* Language-specific adjustments */
|
|
251
|
+
.language-javascript .nx { color: #9cdcfe }
|
|
252
|
+
.language-javascript .s1,
|
|
253
|
+
.language-javascript .s2 { color: #ce9178 }
|
|
254
|
+
.language-javascript .kd { color: #569cd6 }
|
|
255
|
+
.language-javascript .k { color: #c586c0 }
|
|
256
|
+
.language-javascript .o { color: #d4d4d4 }
|
|
257
|
+
.language-javascript .p { color: #d4d4d4 }
|
|
258
|
+
.language-javascript .c1 { color: #6a9955 }
|
|
188
259
|
|
|
189
260
|
.language-bash { color: #4ec9b0; }
|
|
261
|
+
.language-bash .nv { color: #9cdcfe; }
|
|
262
|
+
.language-bash .s2 { color: #ce9178; }
|
|
190
263
|
|
|
191
264
|
ul, ol {
|
|
192
265
|
margin-bottom: 16px;
|
package/docs/index.md
CHANGED
|
@@ -50,6 +50,7 @@ JSON REST API is a lightweight, plugin-based framework that makes building REST
|
|
|
50
50
|
<p>Follow industry standards with native JSON:API support. Compatible with any JSON:API client library.</p>
|
|
51
51
|
</div>
|
|
52
52
|
|
|
53
|
+
<!--
|
|
53
54
|
<div class="feature-card">
|
|
54
55
|
<h3>🌐 Microservices Ready</h3>
|
|
55
56
|
<p>Build distributed systems with native microservices support. Multiple transports, service discovery, and more.</p>
|
|
@@ -64,6 +65,7 @@ JSON REST API is a lightweight, plugin-based framework that makes building REST
|
|
|
64
65
|
<h3>🔄 API Gateway</h3>
|
|
65
66
|
<p>Transform into an API gateway to orchestrate external services with circuit breakers and saga support.</p>
|
|
66
67
|
</div>
|
|
68
|
+
-->
|
|
67
69
|
</div>
|
|
68
70
|
|
|
69
71
|
## Quick Example
|
|
@@ -137,15 +139,3 @@ npm install json-rest-api
|
|
|
137
139
|
- [API Reference]({{ '/API' | relative_url }}) - Detailed API documentation
|
|
138
140
|
- [Tutorial]({{ '/ONBOARDING' | relative_url }}) - Step-by-step walkthrough
|
|
139
141
|
- [GitHub](https://github.com/mobily-enterprises/json-rest-api) - Source code and issues
|
|
140
|
-
|
|
141
|
-
### Advanced Topics
|
|
142
|
-
|
|
143
|
-
- [API Gateway]({{ '/GUIDE_8_API_Gateway' | relative_url }}) - Orchestrate external services
|
|
144
|
-
- [CLI Interface]({{ '/GUIDE_9_CLI_Interface' | relative_url }}) - Command-line interface for your API
|
|
145
|
-
|
|
146
|
-
### Enterprise Features
|
|
147
|
-
|
|
148
|
-
- [Enterprise Guide]({{ '/enterprise/ENTERPRISE_GUIDE' | relative_url }}) - Complete guide for enterprise teams
|
|
149
|
-
- [Microservices Architecture]({{ '/enterprise/GUIDE_8_Microservices' | relative_url }}) - Build distributed systems
|
|
150
|
-
- [CQRS Pattern]({{ '/enterprise/GUIDE_9_CQRS' | relative_url }}) - Command Query Responsibility Segregation
|
|
151
|
-
- [Domain-Driven Design]({{ '/enterprise/GUIDE_11_Domain_Driven_Design' | relative_url }}) - DDD patterns and implementation
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Helper Reorganization Plan
|
|
2
|
+
|
|
3
|
+
## Files to Split and Move
|
|
4
|
+
|
|
5
|
+
### 1. payload-validators.js
|
|
6
|
+
This file contains method-specific validators that should be split:
|
|
7
|
+
|
|
8
|
+
**Move to `querying/payload-validators-querying.js`:**
|
|
9
|
+
- `validateGetPayload` (used only by GET)
|
|
10
|
+
- `validateQueryPayload` (used only by QUERY)
|
|
11
|
+
- `validateIncludeDepth` (helper used by GET/QUERY validators)
|
|
12
|
+
|
|
13
|
+
**Move to `writing/payload-validators-writing.js`:**
|
|
14
|
+
- `validatePostPayload` (used only by POST)
|
|
15
|
+
- `validatePutPayload` (used only by PUT)
|
|
16
|
+
- `validatePatchPayload` (used only by PATCH)
|
|
17
|
+
- `validateResourceIdentifier` (helper used by writing validators)
|
|
18
|
+
- `validateRelationship` (helper used by writing validators)
|
|
19
|
+
|
|
20
|
+
### 2. knex-field-helpers.js
|
|
21
|
+
This file has mixed functions:
|
|
22
|
+
|
|
23
|
+
**Move to `querying/knex-field-helpers-querying.js`:**
|
|
24
|
+
- `buildFieldSelection` (used only by GET/QUERY for sparse fieldsets)
|
|
25
|
+
- `getRequestedComputedFields` (used only by GET/QUERY)
|
|
26
|
+
|
|
27
|
+
**Keep in `querying-writing/knex-field-helpers.js`:**
|
|
28
|
+
- `isNonDatabaseField` (used by both reading and writing)
|
|
29
|
+
- `getForeignKeyFields` (re-exported, used by both)
|
|
30
|
+
- `filterHiddenFields` (re-exported, used by both)
|
|
31
|
+
|
|
32
|
+
### 3. knex-json-api-transformers.js
|
|
33
|
+
This file has functions with different usage:
|
|
34
|
+
|
|
35
|
+
**Move to `querying/knex-json-api-transformers-querying.js`:**
|
|
36
|
+
- `toJsonApiRecord` (used only by QUERY)
|
|
37
|
+
- `buildJsonApiResponse` (used only by GET/QUERY)
|
|
38
|
+
|
|
39
|
+
**Move to `writing/knex-json-api-transformers-writing.js`:**
|
|
40
|
+
- `processBelongsToRelationships` (used only by PUT/PATCH)
|
|
41
|
+
|
|
42
|
+
**Keep in `querying-writing/knex-json-api-transformers.js`:**
|
|
43
|
+
- `toJsonApiRecordWithBelongsTo` (used by GET minimal and DELETE)
|
|
44
|
+
|
|
45
|
+
### 4. simplified-helpers.js
|
|
46
|
+
Based on the analysis, this file likely contains:
|
|
47
|
+
- `transformSimplifiedToJsonApi` - used by writing methods
|
|
48
|
+
- `transformJsonApiToSimplified` - used by all methods (should stay shared)
|
|
49
|
+
- `transformSingleJsonApiToSimplified` - used by all methods (should stay shared)
|
|
50
|
+
|
|
51
|
+
Need to verify the actual usage of each function.
|
|
52
|
+
|
|
53
|
+
## Summary of New Structure
|
|
54
|
+
|
|
55
|
+
### `querying/` (10 files total)
|
|
56
|
+
- knex-cross-table-search.js ✓
|
|
57
|
+
- knex-pagination-helpers.js ✓
|
|
58
|
+
- knex-process-includes.js ✓
|
|
59
|
+
- knex-query-helpers.js ✓
|
|
60
|
+
- knex-relationship-includes.js ✓
|
|
61
|
+
- knex-window-queries.js ✓
|
|
62
|
+
- **payload-validators-querying.js** (NEW - split from payload-validators.js)
|
|
63
|
+
- **knex-field-helpers-querying.js** (NEW - split from knex-field-helpers.js)
|
|
64
|
+
- **knex-json-api-transformers-querying.js** (NEW - split from knex-json-api-transformers.js)
|
|
65
|
+
|
|
66
|
+
### `writing/` (5 files total)
|
|
67
|
+
- many-to-many-manipulations.js ✓
|
|
68
|
+
- relationship-processor.js ✓
|
|
69
|
+
- **payload-validators-writing.js** (NEW - split from payload-validators.js)
|
|
70
|
+
- **knex-json-api-transformers-writing.js** (NEW - split from knex-json-api-transformers.js)
|
|
71
|
+
- **simplified-helpers-writing.js** (NEW - if transformSimplifiedToJsonApi is only used by writing)
|
|
72
|
+
|
|
73
|
+
### `querying-writing/` (remaining shared files)
|
|
74
|
+
- compile-schemas.js ✓
|
|
75
|
+
- database-capabilities.js ✓
|
|
76
|
+
- database-value-normalizers.js ✓
|
|
77
|
+
- default-data-helpers.js ✓
|
|
78
|
+
- knex-field-helpers.js (reduced - only shared functions)
|
|
79
|
+
- knex-json-api-helpers.js ✓
|
|
80
|
+
- knex-json-api-transformers.js (reduced - only shared functions)
|
|
81
|
+
- schema-helpers.js ✓
|
|
82
|
+
- scope-validations.js ✓
|
|
83
|
+
- simplified-helpers.js (possibly reduced if some functions move to writing)
|
|
84
|
+
|
|
85
|
+
This reorganization will create a much more balanced structure with clearer separation of concerns.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# REST API Helper Usage Analysis
|
|
2
|
+
|
|
3
|
+
This document analyzes which helpers from `plugins/core/lib/` are used by each REST API method (get, query, post, put, patch, delete).
|
|
4
|
+
|
|
5
|
+
## Helper Categorization
|
|
6
|
+
|
|
7
|
+
### 1. Helpers Used ONLY by Querying Methods (GET, QUERY)
|
|
8
|
+
|
|
9
|
+
#### From rest-api-plugin.js:
|
|
10
|
+
- **parseJsonApiQuery** - Parses JSON:API query strings into query parameters
|
|
11
|
+
- **getRequestedComputedFields** - Determines which computed fields are requested based on sparse fieldsets
|
|
12
|
+
|
|
13
|
+
#### From rest-api-knex-plugin.js:
|
|
14
|
+
- **buildFieldSelection** - Builds field selection for sparse fieldsets and tracks computed field dependencies
|
|
15
|
+
- **buildQuerySelection** - Applies field selection to Knex query
|
|
16
|
+
- **loadRelationshipIdentifiers** - Loads hasMany relationship identifiers for included resources
|
|
17
|
+
- **processIncludes** - Processes relationship includes based on query parameters
|
|
18
|
+
- **toJsonApiRecord** - Transforms database records to JSON:API format
|
|
19
|
+
- **buildJsonApiResponse** - Builds complete JSON:API response with data and included resources
|
|
20
|
+
- **polymorphicFiltersHook** - Handles filtering for polymorphic relationships
|
|
21
|
+
- **crossTableFiltersHook** - Handles cross-table filtering with JOINs
|
|
22
|
+
- **basicFiltersHook** - Handles basic table filtering
|
|
23
|
+
- **calculatePaginationMeta** - Calculates pagination metadata
|
|
24
|
+
- **generatePaginationLinks** - Generates pagination links for offset-based pagination
|
|
25
|
+
- **generateCursorPaginationLinks** - Generates pagination links for cursor-based pagination
|
|
26
|
+
- **buildCursorMeta** - Builds cursor pagination metadata
|
|
27
|
+
- **parseCursor** - Parses cursor strings for cursor pagination
|
|
28
|
+
|
|
29
|
+
### 2. Helpers Used ONLY by Writing Methods (POST, PUT, PATCH, DELETE)
|
|
30
|
+
|
|
31
|
+
#### From rest-api-plugin.js:
|
|
32
|
+
- **validatePostPayload** - Validates POST request payload
|
|
33
|
+
- **validatePutPayload** - Validates PUT request payload
|
|
34
|
+
- **validatePatchPayload** - Validates PATCH request payload
|
|
35
|
+
- **processRelationships** - Extracts foreign keys from JSON:API relationships
|
|
36
|
+
- **updateManyToManyRelationship** - Updates many-to-many relationships intelligently
|
|
37
|
+
- **createPivotRecords** - Creates pivot table records for many-to-many relationships
|
|
38
|
+
- **transformSimplifiedToJsonApi** - Transforms simplified API format to JSON:API
|
|
39
|
+
|
|
40
|
+
#### From rest-api-knex-plugin.js:
|
|
41
|
+
- **processBelongsToRelationships** - Processes belongsTo relationships to extract foreign keys
|
|
42
|
+
- **stripNonDatabaseFields** - Removes computed and virtual fields before database operations
|
|
43
|
+
|
|
44
|
+
### 3. Helpers Used by BOTH Querying and Writing Methods
|
|
45
|
+
|
|
46
|
+
#### From rest-api-plugin.js:
|
|
47
|
+
- **validateQueryPayload** - Used by QUERY method
|
|
48
|
+
- **validateGetPayload** - Used by GET method
|
|
49
|
+
- **compileSchemas** - Used during scope initialization (affects all methods)
|
|
50
|
+
- **normalizeRecordAttributes** - Normalizes database values (used by GET and QUERY)
|
|
51
|
+
- **transformJsonApiToSimplified** - Transforms JSON:API to simplified format (used by all methods when simplified mode is enabled)
|
|
52
|
+
- **filterHiddenFields** - Filters hidden fields from responses (used by all methods)
|
|
53
|
+
- **createDefaultDataHelpers** - Creates default helper implementations
|
|
54
|
+
|
|
55
|
+
#### From rest-api-knex-plugin.js:
|
|
56
|
+
- **toJsonApiRecordWithBelongsTo** - Used by GET (minimal record) and data fetching operations
|
|
57
|
+
- **getForeignKeyFields** - While imported, not directly used in the analyzed code
|
|
58
|
+
- **isNonDatabaseField** - While imported, not directly used in the analyzed code
|
|
59
|
+
|
|
60
|
+
## Summary by Method
|
|
61
|
+
|
|
62
|
+
### GET Method
|
|
63
|
+
**Uses:** validateGetPayload, getRequestedComputedFields, normalizeRecordAttributes, filterHiddenFields, transformJsonApiToSimplified, buildFieldSelection, buildQuerySelection, loadRelationshipIdentifiers, processIncludes, buildJsonApiResponse, toJsonApiRecordWithBelongsTo
|
|
64
|
+
|
|
65
|
+
### QUERY Method
|
|
66
|
+
**Uses:** validateQueryPayload, getRequestedComputedFields, normalizeRecordAttributes, filterHiddenFields, transformJsonApiToSimplified, parseJsonApiQuery, buildFieldSelection, buildQuerySelection, polymorphicFiltersHook, crossTableFiltersHook, basicFiltersHook, calculatePaginationMeta, generatePaginationLinks, generateCursorPaginationLinks, buildCursorMeta, parseCursor, loadRelationshipIdentifiers, processIncludes, buildJsonApiResponse
|
|
67
|
+
|
|
68
|
+
### POST Method
|
|
69
|
+
**Uses:** validatePostPayload, processRelationships, createPivotRecords, transformSimplifiedToJsonApi, filterHiddenFields, transformJsonApiToSimplified, stripNonDatabaseFields
|
|
70
|
+
|
|
71
|
+
### PUT Method
|
|
72
|
+
**Uses:** validatePutPayload, processRelationships, updateManyToManyRelationship, createPivotRecords, transformSimplifiedToJsonApi, filterHiddenFields, transformJsonApiToSimplified, processBelongsToRelationships, stripNonDatabaseFields
|
|
73
|
+
|
|
74
|
+
### PATCH Method
|
|
75
|
+
**Uses:** validatePatchPayload, processRelationships, updateManyToManyRelationship, transformSimplifiedToJsonApi, filterHiddenFields, transformJsonApiToSimplified, processBelongsToRelationships, stripNonDatabaseFields
|
|
76
|
+
|
|
77
|
+
### DELETE Method
|
|
78
|
+
**Uses:** toJsonApiRecordWithBelongsTo (for minimal record fetching)
|
|
79
|
+
|
|
80
|
+
## Key Observations
|
|
81
|
+
|
|
82
|
+
1. **Clear Separation**: There's a clear separation between read and write helpers, with minimal overlap.
|
|
83
|
+
|
|
84
|
+
2. **Query Complexity**: Query methods use the most helpers due to filtering, pagination, includes, and sparse fieldsets.
|
|
85
|
+
|
|
86
|
+
3. **Relationship Handling**: Write methods focus heavily on relationship processing and validation.
|
|
87
|
+
|
|
88
|
+
4. **Format Transformation**: Both read and write methods use format transformation helpers for simplified API mode.
|
|
89
|
+
|
|
90
|
+
5. **DELETE Simplicity**: DELETE method uses the fewest helpers, only needing minimal record fetching.
|
|
91
|
+
|
|
92
|
+
6. **Validation Pattern**: Each write method has its own specific payload validator.
|
|
93
|
+
|
|
94
|
+
7. **Database Abstraction**: The knex plugin handles all direct database operations, while the REST API plugin handles validation and transformation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-rest-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
"homepage": "https://github.com/mobily-enterprises/jsonrestapi#readme",
|
|
23
23
|
"description": "REST API plugin for hooked-api with JSON:API compliance",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"hooked-api": "^1.0.
|
|
26
|
-
"json-rest-schema": "^1.0.
|
|
25
|
+
"hooked-api": "^1.0.14",
|
|
26
|
+
"json-rest-schema": "^1.0.8",
|
|
27
|
+
"semver": "^7.7.2"
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|
|
29
30
|
"@socket.io/redis-adapter": "^8.3.0",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
},
|
|
80
81
|
"devDependencies": {
|
|
81
82
|
"@socket.io/redis-adapter": "^8.3.0",
|
|
82
|
-
"better-sqlite3": "^11.
|
|
83
|
+
"better-sqlite3": "^11.10.0",
|
|
83
84
|
"express": "^5.1.0",
|
|
84
85
|
"fractional-indexing": "^3.2.0",
|
|
85
86
|
"jsonwebtoken": "^9.0.2",
|
|
@@ -348,8 +348,8 @@ export const BulkOperationsPlugin = {
|
|
|
348
348
|
|
|
349
349
|
// Hook into scope creation to add bulk routes
|
|
350
350
|
addHook('afterAddScope', 'bulkOperationsRoutes', {}, async ({ scopeName }) => {
|
|
351
|
-
const
|
|
352
|
-
const scopePath = `${
|
|
351
|
+
const urlPrefix = api.vars.transport?.mountPath || '';
|
|
352
|
+
const scopePath = `${urlPrefix}/${scopeName}`;
|
|
353
353
|
|
|
354
354
|
// Create route handlers
|
|
355
355
|
const createBulkRouteHandler = (method) => {
|