json-rest-api 1.0.0 → 1.0.1

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 (67) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/LICENSE +674 -0
  3. package/README.md +655 -309
  4. package/RELATIONSHIPS.md +1013 -0
  5. package/TODO_rest-api-plugin-extras.js +142 -0
  6. package/connectors_ideas/express-plugin.js +120 -0
  7. package/connectors_ideas/fastify.js +219 -0
  8. package/connectors_ideas/http-plugin.js +138 -0
  9. package/connectors_ideas/koa-plugin.js +113 -0
  10. package/docs/fileUploads.md +722 -0
  11. package/docs/mini-guides/file-uploads-complete.md +159 -0
  12. package/examples/.gitkeep +0 -0
  13. package/examples/express-example.js +262 -0
  14. package/examples/express-plugin.js +366 -0
  15. package/examples/file-upload-example.js +205 -0
  16. package/examples/filename-strategies.js +140 -0
  17. package/examples/knex-basic.js +66 -0
  18. package/index.js +31 -56
  19. package/lib/payload-validators.js +685 -0
  20. package/lib/rest-api-errors.js +58 -0
  21. package/package.json +41 -14
  22. package/payloadValdators.js +686 -0
  23. package/plugins/core/connectors/express-plugin.js +449 -0
  24. package/plugins/core/connectors/http-plugin.js +450 -0
  25. package/plugins/core/file-handling-plugin.js +338 -0
  26. package/plugins/core/lib/busboy-detector.js +167 -0
  27. package/plugins/core/lib/formidable-detector.js +130 -0
  28. package/plugins/core/rest-api-knex-plugin.js +200 -0
  29. package/plugins/core/rest-api-plugin.js +1419 -0
  30. package/plugins/storage/local-storage.js +218 -0
  31. package/plugins/storage/s3-storage.js +125 -0
  32. package/test-examples/package-lock.json +906 -0
  33. package/test-examples/package.json +15 -0
  34. package/test-examples/test-basic-api.js +11 -0
  35. package/test-examples/test-books-resource.js +116 -0
  36. package/test-examples/test-complete-file-upload.js +140 -0
  37. package/test-examples/test-debug.js +28 -0
  38. package/test-examples/test-express-plugin.js +177 -0
  39. package/test-examples/test-express-simple.js +28 -0
  40. package/test-examples/test-express-with-import.js +71 -0
  41. package/test-examples/test-file-upload.js +132 -0
  42. package/test-examples/test-http-plugin.js +159 -0
  43. package/test-examples/test-programmatic-api.js +188 -0
  44. package/test-examples/test-rest-api-plugin.js +13 -0
  45. package/TODO.todo +0 -113
  46. package/api.js +0 -628
  47. package/docs/API.md +0 -1306
  48. package/docs/FIXES_APPLIED.md +0 -59
  49. package/docs/GUIDES.md +0 -1792
  50. package/docs/RESOURCES_IN_EXPRESS.md +0 -456
  51. package/docs/example-versioning.js +0 -168
  52. package/docs/example.js +0 -195
  53. package/plugins/API guide.md +0 -364
  54. package/plugins/api-registry.js +0 -142
  55. package/plugins/api-versioning.md +0 -135
  56. package/plugins/http.js +0 -273
  57. package/plugins/logging.js +0 -255
  58. package/plugins/memory.js +0 -182
  59. package/plugins/mysql.js +0 -753
  60. package/plugins/openapi.js +0 -401
  61. package/plugins/positioning.js +0 -220
  62. package/plugins/security.js +0 -261
  63. package/plugins/validation.js +0 -173
  64. package/plugins/versioning.js +0 -288
  65. package/resource-helper.js +0 -79
  66. package/schema.js +0 -481
  67. package/test-basic.js +0 -107
@@ -0,0 +1,200 @@
1
+
2
+ export const RestApiKnexPlugin = {
3
+ name: 'rest-api-knex',
4
+ dependencies: ['rest-api'],
5
+
6
+ async install({ helpers, vars, pluginOptions, api, log, scopes }) {
7
+
8
+ // Get Knex configuration from plugin options
9
+ const knexOptions = pluginOptions.knex || pluginOptions['rest-api-knex'];
10
+ if (!knexOptions || !knexOptions.knex) {
11
+ throw new Error('RestApiKnexPlugin requires a knex instance in pluginOptions');
12
+ }
13
+
14
+ const knex = knexOptions.knex;
15
+
16
+ // Helper to get table name for a scope
17
+ const getTableName = (scopeName) => {
18
+ const scopeOptions = scopes[scopeName]?.options || {};
19
+ return scopeOptions.tableName || scopeName;
20
+ };
21
+
22
+ // Helper to convert DB record to JSON:API format
23
+ const toJsonApi = (scopeName, record) => {
24
+ if (!record) return null;
25
+
26
+ const idProperty = vars.idProperty || 'id';
27
+ const { [idProperty]: id, ...attributes } = record;
28
+
29
+ return {
30
+ type: scopeName,
31
+ id: String(id),
32
+ attributes
33
+ };
34
+ };
35
+
36
+ // GET - retrieve a single record by ID
37
+ helpers.dataGet = async ({ scopeName, id }) => {
38
+ const tableName = getTableName(scopeName);
39
+ const idProperty = vars.idProperty || 'id';
40
+
41
+ log.debug(`[Knex] GET ${tableName}/${id}`);
42
+
43
+ const record = await knex(tableName)
44
+ .where(idProperty, id)
45
+ .first();
46
+
47
+ if (!record) {
48
+ const error = new Error(`Record not found: ${scopeName}/${id}`);
49
+ error.code = 'REST_API_RESOURCE';
50
+ error.subtype = 'not_found';
51
+ throw error;
52
+ }
53
+
54
+ return {
55
+ data: toJsonApi(scopeName, record)
56
+ };
57
+ };
58
+
59
+ // QUERY - retrieve multiple records
60
+ helpers.dataQuery = async ({ scopeName, queryParams = {} }) => {
61
+ const tableName = getTableName(scopeName);
62
+
63
+ log.debug(`[Knex] QUERY ${tableName}`, queryParams);
64
+
65
+ // Very basic implementation - just get all records
66
+ // Ignoring include, fields, filter, sort, page for now
67
+ const records = await knex(tableName).select('*');
68
+
69
+ return {
70
+ data: records.map(record => toJsonApi(scopeName, record))
71
+ };
72
+ };
73
+
74
+ // POST - create a new record
75
+ helpers.dataPost = async ({ scopeName, inputRecord }) => {
76
+ const tableName = getTableName(scopeName);
77
+ const idProperty = vars.idProperty || 'id';
78
+
79
+ log.debug(`[Knex] POST ${tableName}`, inputRecord);
80
+
81
+ // Extract attributes from JSON:API format
82
+ const attributes = inputRecord.data.attributes;
83
+
84
+ // Insert and get the new ID
85
+ const [id] = await knex(tableName).insert(attributes).returning(idProperty);
86
+
87
+ // Fetch the created record
88
+ const newRecord = await knex(tableName)
89
+ .where(idProperty, id)
90
+ .first();
91
+
92
+ return {
93
+ data: toJsonApi(scopeName, newRecord)
94
+ };
95
+ };
96
+
97
+ // PUT - replace an entire record
98
+ helpers.dataPut = async ({ scopeName, id, inputRecord }) => {
99
+ const tableName = getTableName(scopeName);
100
+ const idProperty = vars.idProperty || 'id';
101
+
102
+ log.debug(`[Knex] PUT ${tableName}/${id}`, inputRecord);
103
+
104
+ // Extract attributes from JSON:API format
105
+ const attributes = inputRecord.data.attributes;
106
+
107
+ // Check if record exists
108
+ const exists = await knex(tableName)
109
+ .where(idProperty, id)
110
+ .first();
111
+
112
+ if (!exists) {
113
+ const error = new Error(`Record not found: ${scopeName}/${id}`);
114
+ error.code = 'REST_API_RESOURCE';
115
+ error.subtype = 'not_found';
116
+ throw error;
117
+ }
118
+
119
+ // Update the record (replace all fields)
120
+ await knex(tableName)
121
+ .where(idProperty, id)
122
+ .update(attributes);
123
+
124
+ // Fetch the updated record
125
+ const updatedRecord = await knex(tableName)
126
+ .where(idProperty, id)
127
+ .first();
128
+
129
+ return {
130
+ data: toJsonApi(scopeName, updatedRecord)
131
+ };
132
+ };
133
+
134
+ // PATCH - partially update a record
135
+ helpers.dataPatch = async ({ scopeName, id, inputRecord }) => {
136
+ const tableName = getTableName(scopeName);
137
+ const idProperty = vars.idProperty || 'id';
138
+
139
+ log.debug(`[Knex] PATCH ${tableName}/${id}`, inputRecord);
140
+
141
+ // Extract attributes from JSON:API format
142
+ const attributes = inputRecord.data.attributes;
143
+
144
+ // Check if record exists
145
+ const exists = await knex(tableName)
146
+ .where(idProperty, id)
147
+ .first();
148
+
149
+ if (!exists) {
150
+ const error = new Error(`Record not found: ${scopeName}/${id}`);
151
+ error.code = 'REST_API_RESOURCE';
152
+ error.subtype = 'not_found';
153
+ throw error;
154
+ }
155
+
156
+ // Update only provided fields
157
+ await knex(tableName)
158
+ .where(idProperty, id)
159
+ .update(attributes);
160
+
161
+ // Fetch the updated record
162
+ const updatedRecord = await knex(tableName)
163
+ .where(idProperty, id)
164
+ .first();
165
+
166
+ return {
167
+ data: toJsonApi(scopeName, updatedRecord)
168
+ };
169
+ };
170
+
171
+ // DELETE - remove a record
172
+ helpers.dataDelete = async ({ scopeName, id }) => {
173
+ const tableName = getTableName(scopeName);
174
+ const idProperty = vars.idProperty || 'id';
175
+
176
+ log.debug(`[Knex] DELETE ${tableName}/${id}`);
177
+
178
+ // Check if record exists
179
+ const exists = await knex(tableName)
180
+ .where(idProperty, id)
181
+ .first();
182
+
183
+ if (!exists) {
184
+ const error = new Error(`Record not found: ${scopeName}/${id}`);
185
+ error.code = 'REST_API_RESOURCE';
186
+ error.subtype = 'not_found';
187
+ throw error;
188
+ }
189
+
190
+ // Delete the record
191
+ await knex(tableName)
192
+ .where(idProperty, id)
193
+ .delete();
194
+
195
+ return { success: true };
196
+ };
197
+
198
+ log.info('RestApiKnexPlugin installed - basic CRUD operations ready');
199
+ }
200
+ }