crud-api-express 1.1.0 → 1.1.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/dist/index.cjs ADDED
@@ -0,0 +1,214 @@
1
+ 'use strict';
2
+
3
+ var express = require('express');
4
+
5
+ class CrudController {
6
+ constructor(model, endpoint, options = {}) {
7
+ this.model = model;
8
+ this.endpoint = endpoint;
9
+ this.router = express.Router();
10
+ this.routes = [];
11
+ this.configureRoutes(options);
12
+ }
13
+ configureRoutes(options) {
14
+ const { middleware = [], onSuccess = (res, method, result) => res.status(200).send(result), onError = (res, method, error) => res.status(400).send(error), methods = ['POST', 'GET', 'PUT', 'DELETE'] } = options;
15
+ const applyMiddleware = (routeHandler) => {
16
+ return [...middleware, routeHandler];
17
+ };
18
+ // Helper to register a route
19
+ const registerRoute = (method, path, params) => {
20
+ this.routes.push({ method, path, params });
21
+ };
22
+ // Create
23
+ if (methods.includes('POST')) {
24
+ const path = `/${this.endpoint}`;
25
+ this.router.post(path, applyMiddleware(async (req, res) => {
26
+ const method = 'POST';
27
+ try {
28
+ const result = await this.model.create(req.body);
29
+ if (options.relatedModel && options.relatedMethods?.includes('POST')) {
30
+ await options.relatedModel.create({ [options.relatedField]: result._id, ...req.body });
31
+ }
32
+ onSuccess(res, method, result);
33
+ }
34
+ catch (error) {
35
+ onError(res, method, error);
36
+ }
37
+ }));
38
+ registerRoute('POST', path);
39
+ }
40
+ // Read all
41
+ if (methods.includes('GET')) {
42
+ const path = `/${this.endpoint}`;
43
+ this.router.get(path, applyMiddleware(async (req, res) => {
44
+ const method = 'GET';
45
+ try {
46
+ const { filter, sort, page, limit } = req.query;
47
+ const query = filter ? JSON.parse(filter) : {};
48
+ const sortOrder = sort ? JSON.parse(sort) : {};
49
+ const pageNumber = parseInt(page, 10) || 1;
50
+ const pageSize = parseInt(limit, 10) || 10;
51
+ const skip = (pageNumber - 1) * pageSize;
52
+ let items;
53
+ if (options.relatedModel && options.relatedMethods?.includes('GET')) {
54
+ items = await this.model.aggregate([
55
+ { $match: query },
56
+ {
57
+ $lookup: {
58
+ from: options.relatedModel.collection.name,
59
+ localField: options.relatedField,
60
+ foreignField: '_id',
61
+ as: 'relatedData'
62
+ }
63
+ },
64
+ { $sort: sortOrder },
65
+ { $skip: skip },
66
+ { $limit: pageSize }
67
+ ]);
68
+ }
69
+ else {
70
+ items = await this.model.find(query).sort(sortOrder).skip(skip).limit(pageSize);
71
+ }
72
+ onSuccess(res, method, items);
73
+ }
74
+ catch (error) {
75
+ onError(res, method, error);
76
+ }
77
+ }));
78
+ registerRoute('GET', path, ['filter', 'sort', 'page', 'limit']);
79
+ }
80
+ // Read one
81
+ if (methods.includes('GET')) {
82
+ const path = `/${this.endpoint}/:id`;
83
+ this.router.get(path, applyMiddleware(async (req, res) => {
84
+ const method = 'GET';
85
+ try {
86
+ let item;
87
+ if (options.relatedModel && options.relatedMethods?.includes('GET')) {
88
+ const aggregateResult = await this.model.aggregate([
89
+ { $match: { _id: req.params.id } },
90
+ {
91
+ $lookup: {
92
+ from: options.relatedModel.collection.name,
93
+ localField: options.relatedField,
94
+ foreignField: '_id',
95
+ as: 'relatedData'
96
+ }
97
+ }
98
+ ]);
99
+ item = aggregateResult[0];
100
+ }
101
+ else {
102
+ item = await this.model.findById(req.params.id);
103
+ }
104
+ if (!item) {
105
+ return res.status(404).send();
106
+ }
107
+ onSuccess(res, method, item);
108
+ }
109
+ catch (error) {
110
+ onError(res, method, error);
111
+ }
112
+ }));
113
+ registerRoute('GET', path, ['id']);
114
+ }
115
+ // Update
116
+ if (methods.includes('PUT')) {
117
+ const path = `/${this.endpoint}/:id`;
118
+ this.router.put(path, applyMiddleware(async (req, res) => {
119
+ const method = 'PUT';
120
+ try {
121
+ const item = await this.model.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
122
+ if (!item) {
123
+ return res.status(404).send();
124
+ }
125
+ if (options.relatedModel && options.relatedMethods?.includes('PUT')) {
126
+ await options.relatedModel.updateMany({ [options.relatedField]: item._id }, req.body);
127
+ }
128
+ onSuccess(res, method, item);
129
+ }
130
+ catch (error) {
131
+ onError(res, method, error);
132
+ }
133
+ }));
134
+ registerRoute('PUT', path, ['id']);
135
+ }
136
+ // Delete multiple
137
+ if (methods.includes('DELETE')) {
138
+ const path = `/${this.endpoint}`;
139
+ this.router.delete(path, applyMiddleware(async (req, res) => {
140
+ const method = 'DELETE';
141
+ try {
142
+ const query = req.query.filter ? JSON.parse(req.query.filter) : {};
143
+ const deleteResult = await this.model.deleteMany(query);
144
+ if (deleteResult.deletedCount === 0) {
145
+ return res.status(404).send();
146
+ }
147
+ if (options.relatedModel && options.relatedMethods?.includes('DELETE')) {
148
+ await options.relatedModel.deleteMany({ [options.relatedField]: { $in: query } });
149
+ }
150
+ onSuccess(res, method, deleteResult);
151
+ }
152
+ catch (error) {
153
+ onError(res, method, error);
154
+ }
155
+ }));
156
+ registerRoute('DELETE', path, ['filter']);
157
+ }
158
+ // Delete one
159
+ if (methods.includes('DELETE')) {
160
+ const path = `/${this.endpoint}/:id`;
161
+ this.router.delete(path, applyMiddleware(async (req, res) => {
162
+ const method = 'DELETE';
163
+ try {
164
+ const item = await this.model.findByIdAndDelete(req.params.id);
165
+ if (!item) {
166
+ return res.status(404).send();
167
+ }
168
+ if (options.relatedModel && options.relatedMethods?.includes('DELETE')) {
169
+ await options.relatedModel.deleteMany({ [options.relatedField]: item._id });
170
+ }
171
+ onSuccess(res, method, item);
172
+ }
173
+ catch (error) {
174
+ onError(res, method, error);
175
+ }
176
+ }));
177
+ registerRoute('DELETE', path, ['id']);
178
+ }
179
+ // Aggregate
180
+ if (methods.includes('GET') && options.aggregatePipeline) {
181
+ const path = `/${this.endpoint}/aggregate`;
182
+ this.router.get(path, applyMiddleware(async (req, res) => {
183
+ const method = 'GET (Aggregate)';
184
+ try {
185
+ const pipeline = options.aggregatePipeline ?? [];
186
+ const results = await this.model.aggregate(pipeline);
187
+ onSuccess(res, method, results);
188
+ }
189
+ catch (error) {
190
+ onError(res, method, error);
191
+ }
192
+ }));
193
+ registerRoute('GET', path);
194
+ }
195
+ // Custom routes
196
+ if (options.customRoutes) {
197
+ options.customRoutes.forEach(route => {
198
+ const { method, path, handler } = route;
199
+ if (methods.includes(method.toUpperCase())) {
200
+ this.router[method](`/${this.endpoint}${path}`, applyMiddleware(handler));
201
+ registerRoute(method.toUpperCase(), `/${this.endpoint}${path}`);
202
+ }
203
+ });
204
+ }
205
+ }
206
+ getRouter() {
207
+ return this.router;
208
+ }
209
+ getRoutes() {
210
+ return this.routes;
211
+ }
212
+ }
213
+
214
+ module.exports = CrudController;
package/dist/index.mjs ADDED
@@ -0,0 +1,212 @@
1
+ import { Router } from 'express';
2
+
3
+ class CrudController {
4
+ constructor(model, endpoint, options = {}) {
5
+ this.model = model;
6
+ this.endpoint = endpoint;
7
+ this.router = Router();
8
+ this.routes = [];
9
+ this.configureRoutes(options);
10
+ }
11
+ configureRoutes(options) {
12
+ const { middleware = [], onSuccess = (res, method, result) => res.status(200).send(result), onError = (res, method, error) => res.status(400).send(error), methods = ['POST', 'GET', 'PUT', 'DELETE'] } = options;
13
+ const applyMiddleware = (routeHandler) => {
14
+ return [...middleware, routeHandler];
15
+ };
16
+ // Helper to register a route
17
+ const registerRoute = (method, path, params) => {
18
+ this.routes.push({ method, path, params });
19
+ };
20
+ // Create
21
+ if (methods.includes('POST')) {
22
+ const path = `/${this.endpoint}`;
23
+ this.router.post(path, applyMiddleware(async (req, res) => {
24
+ const method = 'POST';
25
+ try {
26
+ const result = await this.model.create(req.body);
27
+ if (options.relatedModel && options.relatedMethods?.includes('POST')) {
28
+ await options.relatedModel.create({ [options.relatedField]: result._id, ...req.body });
29
+ }
30
+ onSuccess(res, method, result);
31
+ }
32
+ catch (error) {
33
+ onError(res, method, error);
34
+ }
35
+ }));
36
+ registerRoute('POST', path);
37
+ }
38
+ // Read all
39
+ if (methods.includes('GET')) {
40
+ const path = `/${this.endpoint}`;
41
+ this.router.get(path, applyMiddleware(async (req, res) => {
42
+ const method = 'GET';
43
+ try {
44
+ const { filter, sort, page, limit } = req.query;
45
+ const query = filter ? JSON.parse(filter) : {};
46
+ const sortOrder = sort ? JSON.parse(sort) : {};
47
+ const pageNumber = parseInt(page, 10) || 1;
48
+ const pageSize = parseInt(limit, 10) || 10;
49
+ const skip = (pageNumber - 1) * pageSize;
50
+ let items;
51
+ if (options.relatedModel && options.relatedMethods?.includes('GET')) {
52
+ items = await this.model.aggregate([
53
+ { $match: query },
54
+ {
55
+ $lookup: {
56
+ from: options.relatedModel.collection.name,
57
+ localField: options.relatedField,
58
+ foreignField: '_id',
59
+ as: 'relatedData'
60
+ }
61
+ },
62
+ { $sort: sortOrder },
63
+ { $skip: skip },
64
+ { $limit: pageSize }
65
+ ]);
66
+ }
67
+ else {
68
+ items = await this.model.find(query).sort(sortOrder).skip(skip).limit(pageSize);
69
+ }
70
+ onSuccess(res, method, items);
71
+ }
72
+ catch (error) {
73
+ onError(res, method, error);
74
+ }
75
+ }));
76
+ registerRoute('GET', path, ['filter', 'sort', 'page', 'limit']);
77
+ }
78
+ // Read one
79
+ if (methods.includes('GET')) {
80
+ const path = `/${this.endpoint}/:id`;
81
+ this.router.get(path, applyMiddleware(async (req, res) => {
82
+ const method = 'GET';
83
+ try {
84
+ let item;
85
+ if (options.relatedModel && options.relatedMethods?.includes('GET')) {
86
+ const aggregateResult = await this.model.aggregate([
87
+ { $match: { _id: req.params.id } },
88
+ {
89
+ $lookup: {
90
+ from: options.relatedModel.collection.name,
91
+ localField: options.relatedField,
92
+ foreignField: '_id',
93
+ as: 'relatedData'
94
+ }
95
+ }
96
+ ]);
97
+ item = aggregateResult[0];
98
+ }
99
+ else {
100
+ item = await this.model.findById(req.params.id);
101
+ }
102
+ if (!item) {
103
+ return res.status(404).send();
104
+ }
105
+ onSuccess(res, method, item);
106
+ }
107
+ catch (error) {
108
+ onError(res, method, error);
109
+ }
110
+ }));
111
+ registerRoute('GET', path, ['id']);
112
+ }
113
+ // Update
114
+ if (methods.includes('PUT')) {
115
+ const path = `/${this.endpoint}/:id`;
116
+ this.router.put(path, applyMiddleware(async (req, res) => {
117
+ const method = 'PUT';
118
+ try {
119
+ const item = await this.model.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
120
+ if (!item) {
121
+ return res.status(404).send();
122
+ }
123
+ if (options.relatedModel && options.relatedMethods?.includes('PUT')) {
124
+ await options.relatedModel.updateMany({ [options.relatedField]: item._id }, req.body);
125
+ }
126
+ onSuccess(res, method, item);
127
+ }
128
+ catch (error) {
129
+ onError(res, method, error);
130
+ }
131
+ }));
132
+ registerRoute('PUT', path, ['id']);
133
+ }
134
+ // Delete multiple
135
+ if (methods.includes('DELETE')) {
136
+ const path = `/${this.endpoint}`;
137
+ this.router.delete(path, applyMiddleware(async (req, res) => {
138
+ const method = 'DELETE';
139
+ try {
140
+ const query = req.query.filter ? JSON.parse(req.query.filter) : {};
141
+ const deleteResult = await this.model.deleteMany(query);
142
+ if (deleteResult.deletedCount === 0) {
143
+ return res.status(404).send();
144
+ }
145
+ if (options.relatedModel && options.relatedMethods?.includes('DELETE')) {
146
+ await options.relatedModel.deleteMany({ [options.relatedField]: { $in: query } });
147
+ }
148
+ onSuccess(res, method, deleteResult);
149
+ }
150
+ catch (error) {
151
+ onError(res, method, error);
152
+ }
153
+ }));
154
+ registerRoute('DELETE', path, ['filter']);
155
+ }
156
+ // Delete one
157
+ if (methods.includes('DELETE')) {
158
+ const path = `/${this.endpoint}/:id`;
159
+ this.router.delete(path, applyMiddleware(async (req, res) => {
160
+ const method = 'DELETE';
161
+ try {
162
+ const item = await this.model.findByIdAndDelete(req.params.id);
163
+ if (!item) {
164
+ return res.status(404).send();
165
+ }
166
+ if (options.relatedModel && options.relatedMethods?.includes('DELETE')) {
167
+ await options.relatedModel.deleteMany({ [options.relatedField]: item._id });
168
+ }
169
+ onSuccess(res, method, item);
170
+ }
171
+ catch (error) {
172
+ onError(res, method, error);
173
+ }
174
+ }));
175
+ registerRoute('DELETE', path, ['id']);
176
+ }
177
+ // Aggregate
178
+ if (methods.includes('GET') && options.aggregatePipeline) {
179
+ const path = `/${this.endpoint}/aggregate`;
180
+ this.router.get(path, applyMiddleware(async (req, res) => {
181
+ const method = 'GET (Aggregate)';
182
+ try {
183
+ const pipeline = options.aggregatePipeline ?? [];
184
+ const results = await this.model.aggregate(pipeline);
185
+ onSuccess(res, method, results);
186
+ }
187
+ catch (error) {
188
+ onError(res, method, error);
189
+ }
190
+ }));
191
+ registerRoute('GET', path);
192
+ }
193
+ // Custom routes
194
+ if (options.customRoutes) {
195
+ options.customRoutes.forEach(route => {
196
+ const { method, path, handler } = route;
197
+ if (methods.includes(method.toUpperCase())) {
198
+ this.router[method](`/${this.endpoint}${path}`, applyMiddleware(handler));
199
+ registerRoute(method.toUpperCase(), `/${this.endpoint}${path}`);
200
+ }
201
+ });
202
+ }
203
+ }
204
+ getRouter() {
205
+ return this.router;
206
+ }
207
+ getRoutes() {
208
+ return this.routes;
209
+ }
210
+ }
211
+
212
+ export { CrudController as default };
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "crud-api-express",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ "import": "./dist/index.mjs",
10
+ "require": "./dist/index.cjs"
11
+ },
8
12
  "scripts": {
9
13
  "build": "npx rollup -c"
10
14
  },
@@ -15,7 +19,25 @@
15
19
  "mongoose",
16
20
  "typescript",
17
21
  "rest-api",
18
- "nodejs"
22
+ "nodejs",
23
+ "typeorm",
24
+ "nest",
25
+ "nestjs",
26
+ "rest",
27
+ "restfulapi",
28
+ "crud",
29
+ "crud-generator",
30
+ "httprequest",
31
+ "request-query",
32
+ "requestquery",
33
+ "getquery",
34
+ "query",
35
+ "query-string",
36
+ "querystring",
37
+ "query-builder",
38
+ "querybuilder",
39
+ "backend",
40
+ "bakend-api"
19
41
  ],
20
42
  "author": "",
21
43
  "license": "ISC",
@@ -26,7 +48,7 @@
26
48
  "typescript": "^5.4.5"
27
49
  },
28
50
  "devDependencies": {
29
- "@rollup/plugin-commonjs": "^26.0.1",
51
+ "@rollup/plugin-commonjs": "^26.0.3",
30
52
  "@rollup/plugin-typescript": "^11.1.6",
31
53
  "@types/express": "^4.17.21",
32
54
  "@types/mongoose": "^5.11.97",
package/rollup.config.js CHANGED
@@ -1,16 +1,23 @@
1
1
  import { defineConfig } from "rollup";
2
2
  import typescript from "@rollup/plugin-typescript";
3
-
4
-
5
-
3
+ import commonjs from "@rollup/plugin-commonjs";
6
4
 
7
5
  export default defineConfig({
8
- input: 'src/index.ts',
9
- output:{
10
- dir:'dist',
11
- format:'es',
12
- name:"crud-api-express"
13
- },
14
- external:['express', 'mongoose'],
15
- plugins:[typescript({tsconfig:'tsconfig.json'})]
16
- })
6
+ input: "src/index.ts",
7
+ output: [
8
+ {
9
+ file: "dist/index.cjs",
10
+ format: "cjs",
11
+ exports: "auto",
12
+ },
13
+ {
14
+ file: "dist/index.mjs",
15
+ format: "es",
16
+ },
17
+ ],
18
+ external: ["express", "mongoose"],
19
+ plugins: [
20
+ commonjs(),
21
+ typescript({ tsconfig: "tsconfig.json" }),
22
+ ],
23
+ });