json-rest-api 1.0.0 → 1.0.2
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/settings.local.json +16 -0
- package/LICENSE +674 -0
- package/README.md +655 -309
- package/RELATIONSHIPS.md +1013 -0
- package/TODO_rest-api-plugin-extras.js +142 -0
- package/connectors_ideas/express-plugin.js +120 -0
- package/connectors_ideas/fastify.js +219 -0
- package/connectors_ideas/http-plugin.js +138 -0
- package/connectors_ideas/koa-plugin.js +113 -0
- package/docs/fileUploads.md +722 -0
- package/docs/mini-guides/file-uploads-complete.md +159 -0
- package/examples/.gitkeep +0 -0
- package/examples/express-example.js +262 -0
- package/examples/express-plugin.js +366 -0
- package/examples/file-upload-example.js +205 -0
- package/examples/filename-strategies.js +140 -0
- package/examples/knex-basic.js +66 -0
- package/index.js +31 -56
- package/lib/payload-validators.js +685 -0
- package/lib/rest-api-errors.js +58 -0
- package/package.json +41 -14
- package/payloadValdators.js +686 -0
- package/plugins/core/connectors/express-plugin.js +449 -0
- package/plugins/core/connectors/http-plugin.js +450 -0
- package/plugins/core/file-handling-plugin.js +338 -0
- package/plugins/core/lib/busboy-detector.js +167 -0
- package/plugins/core/lib/formidable-detector.js +130 -0
- package/plugins/core/rest-api-knex-plugin.js +200 -0
- package/plugins/core/rest-api-plugin.js +1419 -0
- package/plugins/storage/local-storage.js +218 -0
- package/plugins/storage/s3-storage.js +125 -0
- package/test-examples/package-lock.json +906 -0
- package/test-examples/package.json +15 -0
- package/test-examples/test-basic-api.js +11 -0
- package/test-examples/test-books-resource.js +116 -0
- package/test-examples/test-complete-file-upload.js +140 -0
- package/test-examples/test-debug.js +28 -0
- package/test-examples/test-express-plugin.js +177 -0
- package/test-examples/test-express-simple.js +28 -0
- package/test-examples/test-express-with-import.js +71 -0
- package/test-examples/test-file-upload.js +132 -0
- package/test-examples/test-http-plugin.js +159 -0
- package/test-examples/test-programmatic-api.js +188 -0
- package/test-examples/test-rest-api-plugin.js +13 -0
- package/TODO.todo +0 -113
- package/api.js +0 -628
- package/docs/API.md +0 -1306
- package/docs/FIXES_APPLIED.md +0 -59
- package/docs/GUIDES.md +0 -1792
- package/docs/RESOURCES_IN_EXPRESS.md +0 -456
- package/docs/example-versioning.js +0 -168
- package/docs/example.js +0 -195
- package/plugins/API guide.md +0 -364
- package/plugins/api-registry.js +0 -142
- package/plugins/api-versioning.md +0 -135
- package/plugins/http.js +0 -273
- package/plugins/logging.js +0 -255
- package/plugins/memory.js +0 -182
- package/plugins/mysql.js +0 -753
- package/plugins/openapi.js +0 -401
- package/plugins/positioning.js +0 -220
- package/plugins/security.js +0 -261
- package/plugins/validation.js +0 -173
- package/plugins/versioning.js +0 -288
- package/resource-helper.js +0 -79
- package/schema.js +0 -481
- 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
|
+
}
|