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
package/plugins/memory.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import firstBy from 'thenby';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Memory storage plugin for JSON REST API
|
|
5
|
-
*/
|
|
6
|
-
export const MemoryPlugin = {
|
|
7
|
-
install(api, options = {}) {
|
|
8
|
-
// Initialize data storage
|
|
9
|
-
api.memoryData = options.initialData || [];
|
|
10
|
-
api.memoryIdCounter = options.initialIdCounter || 1;
|
|
11
|
-
|
|
12
|
-
// Implement CRUD operations
|
|
13
|
-
api.implement('get', async (context) => {
|
|
14
|
-
const { id, options } = context;
|
|
15
|
-
const idProperty = options.idProperty || api.options.idProperty;
|
|
16
|
-
|
|
17
|
-
const record = api.memoryData.find(item =>
|
|
18
|
-
String(item[idProperty]) === String(id)
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
return record || null;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
api.implement('query', async (context) => {
|
|
25
|
-
const { params, options } = context;
|
|
26
|
-
let data = [...api.memoryData];
|
|
27
|
-
|
|
28
|
-
// Apply filters
|
|
29
|
-
if (params.filter) {
|
|
30
|
-
data = data.filter(item => {
|
|
31
|
-
for (const [key, value] of Object.entries(params.filter)) {
|
|
32
|
-
if (item[key] !== value) return false;
|
|
33
|
-
}
|
|
34
|
-
return true;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Apply search (if search parameter exists)
|
|
39
|
-
if (params.search && options.searchFields) {
|
|
40
|
-
const searchLower = params.search.toLowerCase();
|
|
41
|
-
data = data.filter(item => {
|
|
42
|
-
return options.searchFields.some(field => {
|
|
43
|
-
const fieldValue = String(item[field] || '').toLowerCase();
|
|
44
|
-
return fieldValue.includes(searchLower);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Count total before pagination
|
|
50
|
-
const total = data.length;
|
|
51
|
-
|
|
52
|
-
// Apply sorting
|
|
53
|
-
if (params.sort) {
|
|
54
|
-
const sorts = params.sort.split(',');
|
|
55
|
-
let sortChain = firstBy(() => 0);
|
|
56
|
-
|
|
57
|
-
for (const sortField of sorts) {
|
|
58
|
-
const descending = sortField.startsWith('-');
|
|
59
|
-
const field = sortField.replace(/^-/, '');
|
|
60
|
-
|
|
61
|
-
sortChain = sortChain.thenBy(
|
|
62
|
-
item => item[field],
|
|
63
|
-
{ direction: descending ? -1 : 1, ignoreCase: true }
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
data.sort(sortChain);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Apply pagination
|
|
71
|
-
const pageSize = Number(params.page?.size) || 10;
|
|
72
|
-
const pageNumber = Number(params.page?.number) || 1;
|
|
73
|
-
const skip = (pageNumber - 1) * pageSize;
|
|
74
|
-
|
|
75
|
-
data = data.slice(skip, skip + pageSize);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
results: data,
|
|
79
|
-
meta: {
|
|
80
|
-
total,
|
|
81
|
-
pageSize,
|
|
82
|
-
pageNumber,
|
|
83
|
-
totalPages: Math.ceil(total / pageSize)
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
api.implement('insert', async (context) => {
|
|
89
|
-
const { data, options } = context;
|
|
90
|
-
const idProperty = options.idProperty || api.options.idProperty;
|
|
91
|
-
|
|
92
|
-
// Generate ID if not provided
|
|
93
|
-
if (!data[idProperty]) {
|
|
94
|
-
data[idProperty] = api.memoryIdCounter++;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Handle positioning if enabled
|
|
98
|
-
if (options.positionField && data[options.beforeIdField] !== undefined) {
|
|
99
|
-
await handlePositioning(api, data, options);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Add to memory
|
|
103
|
-
api.memoryData.push(data);
|
|
104
|
-
|
|
105
|
-
return { ...data };
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
api.implement('update', async (context) => {
|
|
109
|
-
const { id, data, options } = context;
|
|
110
|
-
const idProperty = options.idProperty || api.options.idProperty;
|
|
111
|
-
|
|
112
|
-
const index = api.memoryData.findIndex(item =>
|
|
113
|
-
String(item[idProperty]) === String(id)
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
if (index === -1) {
|
|
117
|
-
throw new Error('Resource not found');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Handle positioning
|
|
121
|
-
if (options.positionField && data[options.beforeIdField] !== undefined) {
|
|
122
|
-
await handlePositioning(api, { ...api.memoryData[index], ...data }, options);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Update record
|
|
126
|
-
api.memoryData[index] = { ...api.memoryData[index], ...data };
|
|
127
|
-
|
|
128
|
-
return api.memoryData[index];
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
api.implement('delete', async (context) => {
|
|
132
|
-
const { id, options } = context;
|
|
133
|
-
const idProperty = options.idProperty || api.options.idProperty;
|
|
134
|
-
|
|
135
|
-
const index = api.memoryData.findIndex(item =>
|
|
136
|
-
String(item[idProperty]) === String(id)
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
if (index === -1) {
|
|
140
|
-
throw new Error('Resource not found');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
api.memoryData.splice(index, 1);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Handle record positioning
|
|
150
|
-
*/
|
|
151
|
-
async function handlePositioning(api, record, options) {
|
|
152
|
-
const { positionField, beforeIdField } = options;
|
|
153
|
-
const idProperty = options.idProperty || api.options.idProperty;
|
|
154
|
-
const beforeId = record[beforeIdField];
|
|
155
|
-
|
|
156
|
-
if (beforeId === null) {
|
|
157
|
-
// Place at end
|
|
158
|
-
const maxPosition = Math.max(...api.memoryData.map(r => r[positionField] || 0));
|
|
159
|
-
record[positionField] = maxPosition + 1;
|
|
160
|
-
} else if (beforeId !== undefined) {
|
|
161
|
-
// Find the record to place before
|
|
162
|
-
const beforeRecord = api.memoryData.find(r =>
|
|
163
|
-
String(r[idProperty]) === String(beforeId)
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
if (beforeRecord) {
|
|
167
|
-
const position = beforeRecord[positionField] || 0;
|
|
168
|
-
|
|
169
|
-
// Shift positions of records after this position
|
|
170
|
-
api.memoryData.forEach(r => {
|
|
171
|
-
if (r[positionField] >= position) {
|
|
172
|
-
r[positionField]++;
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
record[positionField] = position;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Remove beforeId from record as it's virtual
|
|
181
|
-
delete record[beforeIdField];
|
|
182
|
-
}
|