crud-api-express 1.0.3 → 1.0.5
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/dist/index.d.ts +6 -0
- package/dist/index.js +38 -9
- package/package.json +1 -1
- package/readme.md +2 -1
- package/src/index.ts +58 -34
package/dist/index.d.ts
CHANGED
|
@@ -44,8 +44,14 @@ declare class CrudController<T extends Document> {
|
|
|
44
44
|
private model;
|
|
45
45
|
private endpoint;
|
|
46
46
|
private router;
|
|
47
|
+
private routes;
|
|
47
48
|
constructor(model: Model<T>, endpoint: string, options?: CrudOptions<T>);
|
|
48
49
|
private configureRoutes;
|
|
49
50
|
getRouter(): Router;
|
|
51
|
+
getRoutes(): {
|
|
52
|
+
method: string;
|
|
53
|
+
path: string;
|
|
54
|
+
params?: string[];
|
|
55
|
+
}[];
|
|
50
56
|
}
|
|
51
57
|
export default CrudController;
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ class CrudController {
|
|
|
5
5
|
this.model = model;
|
|
6
6
|
this.endpoint = endpoint;
|
|
7
7
|
this.router = Router();
|
|
8
|
+
this.routes = [];
|
|
8
9
|
this.configureRoutes(options);
|
|
9
10
|
}
|
|
10
11
|
configureRoutes(options) {
|
|
@@ -12,13 +13,17 @@ class CrudController {
|
|
|
12
13
|
const applyMiddleware = (routeHandler) => {
|
|
13
14
|
return [...middleware, routeHandler];
|
|
14
15
|
};
|
|
16
|
+
// Helper to register a route
|
|
17
|
+
const registerRoute = (method, path, params) => {
|
|
18
|
+
this.routes.push({ method, path, params });
|
|
19
|
+
};
|
|
15
20
|
// Create
|
|
16
21
|
if (methods.includes('POST')) {
|
|
17
|
-
|
|
22
|
+
const path = `/${this.endpoint}`;
|
|
23
|
+
this.router.post(path, applyMiddleware(async (req, res) => {
|
|
18
24
|
const method = 'POST';
|
|
19
25
|
try {
|
|
20
|
-
const
|
|
21
|
-
const result = await item.save();
|
|
26
|
+
const result = await this.model.create(req.body);
|
|
22
27
|
if (options.relatedModel && options.relatedMethods?.includes('POST')) {
|
|
23
28
|
await options.relatedModel.create({ [options.relatedField]: result._id, ...req.body });
|
|
24
29
|
}
|
|
@@ -28,9 +33,12 @@ class CrudController {
|
|
|
28
33
|
onError(res, method, error);
|
|
29
34
|
}
|
|
30
35
|
}));
|
|
36
|
+
registerRoute('POST', path);
|
|
31
37
|
}
|
|
38
|
+
// Read all
|
|
32
39
|
if (methods.includes('GET')) {
|
|
33
|
-
|
|
40
|
+
const path = `/${this.endpoint}`;
|
|
41
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
34
42
|
const method = 'GET';
|
|
35
43
|
try {
|
|
36
44
|
const { filter, sort, page, limit } = req.query;
|
|
@@ -65,9 +73,12 @@ class CrudController {
|
|
|
65
73
|
onError(res, method, error);
|
|
66
74
|
}
|
|
67
75
|
}));
|
|
76
|
+
registerRoute('GET', path, ['filter', 'sort', 'page', 'limit']);
|
|
68
77
|
}
|
|
78
|
+
// Read one
|
|
69
79
|
if (methods.includes('GET')) {
|
|
70
|
-
|
|
80
|
+
const path = `/${this.endpoint}/:id`;
|
|
81
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
71
82
|
const method = 'GET';
|
|
72
83
|
try {
|
|
73
84
|
let item;
|
|
@@ -97,9 +108,12 @@ class CrudController {
|
|
|
97
108
|
onError(res, method, error);
|
|
98
109
|
}
|
|
99
110
|
}));
|
|
111
|
+
registerRoute('GET', path, ['id']);
|
|
100
112
|
}
|
|
113
|
+
// Update
|
|
101
114
|
if (methods.includes('PUT')) {
|
|
102
|
-
|
|
115
|
+
const path = `/${this.endpoint}/:id`;
|
|
116
|
+
this.router.put(path, applyMiddleware(async (req, res) => {
|
|
103
117
|
const method = 'PUT';
|
|
104
118
|
try {
|
|
105
119
|
const item = await this.model.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
|
|
@@ -115,9 +129,12 @@ class CrudController {
|
|
|
115
129
|
onError(res, method, error);
|
|
116
130
|
}
|
|
117
131
|
}));
|
|
132
|
+
registerRoute('PUT', path, ['id']);
|
|
118
133
|
}
|
|
134
|
+
// Delete multiple
|
|
119
135
|
if (methods.includes('DELETE')) {
|
|
120
|
-
|
|
136
|
+
const path = `/${this.endpoint}`;
|
|
137
|
+
this.router.delete(path, applyMiddleware(async (req, res) => {
|
|
121
138
|
const method = 'DELETE';
|
|
122
139
|
try {
|
|
123
140
|
const query = req.query.filter ? JSON.parse(req.query.filter) : {};
|
|
@@ -134,9 +151,12 @@ class CrudController {
|
|
|
134
151
|
onError(res, method, error);
|
|
135
152
|
}
|
|
136
153
|
}));
|
|
154
|
+
registerRoute('DELETE', path, ['filter']);
|
|
137
155
|
}
|
|
156
|
+
// Delete one
|
|
138
157
|
if (methods.includes('DELETE')) {
|
|
139
|
-
|
|
158
|
+
const path = `/${this.endpoint}/:id`;
|
|
159
|
+
this.router.delete(path, applyMiddleware(async (req, res) => {
|
|
140
160
|
const method = 'DELETE';
|
|
141
161
|
try {
|
|
142
162
|
const item = await this.model.findByIdAndDelete(req.params.id);
|
|
@@ -152,9 +172,12 @@ class CrudController {
|
|
|
152
172
|
onError(res, method, error);
|
|
153
173
|
}
|
|
154
174
|
}));
|
|
175
|
+
registerRoute('DELETE', path, ['id']);
|
|
155
176
|
}
|
|
177
|
+
// Aggregate
|
|
156
178
|
if (methods.includes('GET') && options.aggregatePipeline) {
|
|
157
|
-
|
|
179
|
+
const path = `/${this.endpoint}/aggregate`;
|
|
180
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
158
181
|
const method = 'GET (Aggregate)';
|
|
159
182
|
try {
|
|
160
183
|
const pipeline = options.aggregatePipeline ?? [];
|
|
@@ -165,12 +188,15 @@ class CrudController {
|
|
|
165
188
|
onError(res, method, error);
|
|
166
189
|
}
|
|
167
190
|
}));
|
|
191
|
+
registerRoute('GET', path);
|
|
168
192
|
}
|
|
193
|
+
// Custom routes
|
|
169
194
|
if (options.customRoutes) {
|
|
170
195
|
options.customRoutes.forEach(route => {
|
|
171
196
|
const { method, path, handler } = route;
|
|
172
197
|
if (methods.includes(method.toUpperCase())) {
|
|
173
198
|
this.router[method](`/${this.endpoint}${path}`, applyMiddleware(handler));
|
|
199
|
+
registerRoute(method.toUpperCase(), `/${this.endpoint}${path}`);
|
|
174
200
|
}
|
|
175
201
|
});
|
|
176
202
|
}
|
|
@@ -178,6 +204,9 @@ class CrudController {
|
|
|
178
204
|
getRouter() {
|
|
179
205
|
return this.router;
|
|
180
206
|
}
|
|
207
|
+
getRoutes() {
|
|
208
|
+
return this.routes;
|
|
209
|
+
}
|
|
181
210
|
}
|
|
182
211
|
|
|
183
212
|
export { CrudController as default };
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -54,7 +54,7 @@ const exampleController = new CrudController(ExampleModel, 'examples', {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
const mongoURI = '
|
|
57
|
+
const mongoURI = 'mdhd';
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
mongoose.connect(mongoURI, { useNewUrlParser: false, useUnifiedTopology: false })
|
|
@@ -66,6 +66,7 @@ mongoose.connect(mongoURI, { useNewUrlParser: false, useUnifiedTopology: false }
|
|
|
66
66
|
app.use(express.json());
|
|
67
67
|
|
|
68
68
|
app.use('/api', exampleController.getRouter());
|
|
69
|
+
console.log(exampleController.getRoutes());
|
|
69
70
|
|
|
70
71
|
const PORT = process.env.PORT || 3000;
|
|
71
72
|
app.listen(PORT, () => {
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Request, Response, Router, NextFunction } from 'express';
|
|
2
2
|
import { Document, Model, Aggregate } from 'mongoose';
|
|
3
3
|
|
|
4
4
|
interface CrudOptions<T extends Document> {
|
|
@@ -17,11 +17,13 @@ class CrudController<T extends Document> {
|
|
|
17
17
|
private model: Model<T>;
|
|
18
18
|
private endpoint: string;
|
|
19
19
|
private router: Router;
|
|
20
|
+
private routes: { method: string, path: string, params?: string[] }[];
|
|
20
21
|
|
|
21
22
|
constructor(model: Model<T>, endpoint: string, options: CrudOptions<T> = {}) {
|
|
22
23
|
this.model = model;
|
|
23
24
|
this.endpoint = endpoint;
|
|
24
25
|
this.router = Router();
|
|
26
|
+
this.routes = [];
|
|
25
27
|
this.configureRoutes(options);
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -33,18 +35,22 @@ class CrudController<T extends Document> {
|
|
|
33
35
|
methods = ['POST', 'GET', 'PUT', 'DELETE']
|
|
34
36
|
} = options;
|
|
35
37
|
|
|
36
|
-
|
|
37
38
|
const applyMiddleware = (routeHandler: (req: Request, res: Response) => void) => {
|
|
38
39
|
return [...middleware, routeHandler];
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
// Helper to register a route
|
|
43
|
+
const registerRoute = (method: string, path: string, params?: string[]) => {
|
|
44
|
+
this.routes.push({ method, path, params });
|
|
45
|
+
};
|
|
46
|
+
|
|
41
47
|
// Create
|
|
42
48
|
if (methods.includes('POST')) {
|
|
43
|
-
|
|
49
|
+
const path = `/${this.endpoint}`;
|
|
50
|
+
this.router.post(path, applyMiddleware(async (req, res) => {
|
|
44
51
|
const method = 'POST';
|
|
45
52
|
try {
|
|
46
|
-
const
|
|
47
|
-
const result:any = await item.save();
|
|
53
|
+
const result:any = await this.model.create(req.body);
|
|
48
54
|
if (options.relatedModel && options.relatedMethods?.includes('POST')) {
|
|
49
55
|
await options.relatedModel.create({ [options.relatedField!]: result._id, ...req.body });
|
|
50
56
|
}
|
|
@@ -53,11 +59,13 @@ class CrudController<T extends Document> {
|
|
|
53
59
|
onError(res, method, error);
|
|
54
60
|
}
|
|
55
61
|
}));
|
|
62
|
+
registerRoute('POST', path);
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
// Read all
|
|
59
66
|
if (methods.includes('GET')) {
|
|
60
|
-
|
|
67
|
+
const path = `/${this.endpoint}`;
|
|
68
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
61
69
|
const method = 'GET';
|
|
62
70
|
try {
|
|
63
71
|
const { filter, sort, page, limit } = req.query;
|
|
@@ -91,10 +99,13 @@ class CrudController<T extends Document> {
|
|
|
91
99
|
onError(res, method, error);
|
|
92
100
|
}
|
|
93
101
|
}));
|
|
102
|
+
registerRoute('GET', path, ['filter', 'sort', 'page', 'limit']);
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
// Read one
|
|
96
106
|
if (methods.includes('GET')) {
|
|
97
|
-
|
|
107
|
+
const path = `/${this.endpoint}/:id`;
|
|
108
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
98
109
|
const method = 'GET';
|
|
99
110
|
try {
|
|
100
111
|
let item: T | null;
|
|
@@ -122,11 +133,13 @@ class CrudController<T extends Document> {
|
|
|
122
133
|
onError(res, method, error);
|
|
123
134
|
}
|
|
124
135
|
}));
|
|
136
|
+
registerRoute('GET', path, ['id']);
|
|
125
137
|
}
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
// Update
|
|
128
140
|
if (methods.includes('PUT')) {
|
|
129
|
-
|
|
141
|
+
const path = `/${this.endpoint}/:id`;
|
|
142
|
+
this.router.put(path, applyMiddleware(async (req, res) => {
|
|
130
143
|
const method = 'PUT';
|
|
131
144
|
try {
|
|
132
145
|
const item = await this.model.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
|
|
@@ -141,32 +154,35 @@ class CrudController<T extends Document> {
|
|
|
141
154
|
onError(res, method, error);
|
|
142
155
|
}
|
|
143
156
|
}));
|
|
157
|
+
registerRoute('PUT', path, ['id']);
|
|
144
158
|
}
|
|
145
159
|
|
|
146
|
-
|
|
147
|
-
if (methods.includes('DELETE')) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
// Delete multiple
|
|
161
|
+
if (methods.includes('DELETE')) {
|
|
162
|
+
const path = `/${this.endpoint}`;
|
|
163
|
+
this.router.delete(path, applyMiddleware(async (req, res) => {
|
|
164
|
+
const method = 'DELETE';
|
|
165
|
+
try {
|
|
166
|
+
const query = req.query.filter ? JSON.parse(req.query.filter as string) : {};
|
|
167
|
+
const deleteResult:any = await this.model.deleteMany(query);
|
|
168
|
+
if (deleteResult.deletedCount === 0) {
|
|
169
|
+
return res.status(404).send();
|
|
170
|
+
}
|
|
171
|
+
if (options.relatedModel && options.relatedMethods?.includes('DELETE')) {
|
|
172
|
+
await options.relatedModel.deleteMany({ [options.relatedField!]: { $in: query } });
|
|
173
|
+
}
|
|
174
|
+
onSuccess(res, method, deleteResult);
|
|
175
|
+
} catch (error: any) {
|
|
176
|
+
onError(res, method, error);
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
registerRoute('DELETE', path, ['filter']);
|
|
162
180
|
}
|
|
163
|
-
}));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
181
|
|
|
182
|
+
// Delete one
|
|
168
183
|
if (methods.includes('DELETE')) {
|
|
169
|
-
|
|
184
|
+
const path = `/${this.endpoint}/:id`;
|
|
185
|
+
this.router.delete(path, applyMiddleware(async (req, res) => {
|
|
170
186
|
const method = 'DELETE';
|
|
171
187
|
try {
|
|
172
188
|
const item = await this.model.findByIdAndDelete(req.params.id);
|
|
@@ -181,11 +197,13 @@ if (methods.includes('DELETE')) {
|
|
|
181
197
|
onError(res, method, error);
|
|
182
198
|
}
|
|
183
199
|
}));
|
|
200
|
+
registerRoute('DELETE', path, ['id']);
|
|
184
201
|
}
|
|
185
202
|
|
|
186
|
-
|
|
203
|
+
// Aggregate
|
|
187
204
|
if (methods.includes('GET') && options.aggregatePipeline) {
|
|
188
|
-
|
|
205
|
+
const path = `/${this.endpoint}/aggregate`;
|
|
206
|
+
this.router.get(path, applyMiddleware(async (req, res) => {
|
|
189
207
|
const method = 'GET (Aggregate)';
|
|
190
208
|
try {
|
|
191
209
|
const pipeline:any = options.aggregatePipeline ?? [];
|
|
@@ -195,14 +213,16 @@ if (methods.includes('DELETE')) {
|
|
|
195
213
|
onError(res, method, error);
|
|
196
214
|
}
|
|
197
215
|
}));
|
|
216
|
+
registerRoute('GET', path);
|
|
198
217
|
}
|
|
199
218
|
|
|
200
|
-
|
|
219
|
+
// Custom routes
|
|
201
220
|
if (options.customRoutes) {
|
|
202
221
|
options.customRoutes.forEach(route => {
|
|
203
222
|
const { method, path, handler } = route;
|
|
204
223
|
if (methods.includes(method.toUpperCase() as 'POST' | 'GET' | 'PUT' | 'DELETE')) {
|
|
205
224
|
this.router[method](`/${this.endpoint}${path}`, applyMiddleware(handler));
|
|
225
|
+
registerRoute(method.toUpperCase(), `/${this.endpoint}${path}`);
|
|
206
226
|
}
|
|
207
227
|
});
|
|
208
228
|
}
|
|
@@ -211,6 +231,10 @@ if (methods.includes('DELETE')) {
|
|
|
211
231
|
public getRouter(): Router {
|
|
212
232
|
return this.router;
|
|
213
233
|
}
|
|
234
|
+
|
|
235
|
+
public getRoutes(): { method: string, path: string, params?: string[] }[] {
|
|
236
|
+
return this.routes;
|
|
237
|
+
}
|
|
214
238
|
}
|
|
215
239
|
|
|
216
240
|
export default CrudController;
|