vanta-api 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/README.md +76 -7
- package/index.js +6 -0
- package/package.json +3 -3
- package/src/api-features.js +17 -7
- package/src/catchAsync.js +6 -0
package/README.md
CHANGED
|
@@ -258,25 +258,73 @@ These configurations are applied automatically in methods such as `filter()`, `p
|
|
|
258
258
|
|
|
259
259
|
## Error Handling Middleware
|
|
260
260
|
|
|
261
|
-
|
|
261
|
+
Vanta-API provides a centralized error handling system featuring three components:
|
|
262
|
+
|
|
263
|
+
### 1. handleError
|
|
264
|
+
|
|
265
|
+
**Purpose:**
|
|
266
|
+
A custom error class that extends the native JavaScript `Error`.
|
|
267
|
+
It adds:
|
|
268
|
+
- **`statusCode`:** HTTP status code.
|
|
269
|
+
- **`status`:** Determines if the error is a `"fail"` (client error) or `"error"` (server error).
|
|
270
|
+
- **`isOperational`:** Flags if the error is an expected operational error.
|
|
271
|
+
- **Stack Trace:** Captures the call stack for easier debugging.
|
|
272
|
+
|
|
273
|
+
**Usage Example in an Async Function:**
|
|
274
|
+
|
|
275
|
+
Inside an asynchronous function wrapped by **catchAsync**, you can use:
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
// Inside your async route handler
|
|
279
|
+
if (someConditionFails) {
|
|
280
|
+
return next(new handleError("Custom error message", 400));
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 2. catchAsync
|
|
285
|
+
|
|
286
|
+
**Purpose:**
|
|
287
|
+
A helper function that wraps asynchronous route handlers.
|
|
288
|
+
It automatically catches any thrown errors and forwards them via `next()`, avoiding repetitive try/catch blocks.
|
|
289
|
+
|
|
290
|
+
**Usage Example:**
|
|
262
291
|
|
|
263
292
|
```javascript
|
|
264
|
-
|
|
293
|
+
app.get("/example", catchAsync(async (req, res, next) => {
|
|
294
|
+
// Your async logic here
|
|
295
|
+
// If an error occurs, use handleError as shown above
|
|
296
|
+
res.status(200).json({ data: "Success" });
|
|
297
|
+
}));
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### 3. catchError
|
|
301
|
+
|
|
302
|
+
**Purpose:**
|
|
303
|
+
An Express middleware that catches any error passed along (either from synchronous or asynchronous routes).
|
|
304
|
+
It sets the appropriate HTTP status and returns a JSON response containing the error’s status and message.
|
|
305
|
+
|
|
306
|
+
**Usage Example:**
|
|
265
307
|
|
|
266
|
-
|
|
267
|
-
//
|
|
308
|
+
```javascript
|
|
309
|
+
// At the end of your middleware stack:
|
|
310
|
+
app.use(catchError);
|
|
268
311
|
```
|
|
269
312
|
|
|
270
|
-
|
|
313
|
+
---
|
|
314
|
+
|
|
271
315
|
|
|
272
316
|
---
|
|
273
317
|
|
|
274
318
|
## Full Examples
|
|
275
319
|
|
|
276
320
|
### Example 1: Basic Query
|
|
321
|
+
To import the package along with the error handling components, use:
|
|
322
|
+
|
|
323
|
+
```javascript
|
|
324
|
+
import ApiFeatures, { handleError, catchAsync, catchError } from "vanta-api";
|
|
325
|
+
```
|
|
277
326
|
|
|
278
327
|
```javascript
|
|
279
|
-
import ApiFeatures from "./api-features.js";
|
|
280
328
|
import Product from "./models/product.js";
|
|
281
329
|
|
|
282
330
|
// URL: /api/products?status=active&price[gte]=100&sort=-price,createdAt&fields=name,price,category&page=1&limit=10&populate=category,brand
|
|
@@ -362,9 +410,30 @@ console.log(result);
|
|
|
362
410
|
Integrated advanced logging using winston and centralized error handling with a custom error class and middleware.
|
|
363
411
|
- **Performance Optimizations:**
|
|
364
412
|
Supports aggregation cursor for large datasets and optimizes aggregation pipelines for efficient resource usage.
|
|
413
|
+
|
|
414
|
+
- **ApiFeatures:**
|
|
415
|
+
Provides advanced query capabilities such as filtering, sorting, pagination, and document population for your MongoDB data.
|
|
416
|
+
|
|
417
|
+
- **Error Handling Components:**
|
|
418
|
+
- **handleError:**
|
|
419
|
+
Throw consistent, structured errors with custom messages and status codes.
|
|
420
|
+
- **catchAsync:**
|
|
421
|
+
Wrap asynchronous route handlers to automatically propagate errors.
|
|
422
|
+
- **catchError:**
|
|
423
|
+
Centralized middleware to catch and respond to errors uniformly.
|
|
424
|
+
|
|
425
|
+
- **Importing:**
|
|
426
|
+
Use the following statement to access all features:
|
|
427
|
+
|
|
428
|
+
```javascript
|
|
429
|
+
import ApiFeatures, { handleError, catchAsync, catchError } from "vanta-api";
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
By following these guidelines, you can integrate and use Vanta-API for advanced, secure query handling and robust error management in your Node.js/Express projects.
|
|
365
433
|
|
|
366
434
|
---
|
|
367
435
|
|
|
368
436
|
VantaApi provides a complete solution for integrating powerful, secure, and customizable query capabilities into any Node.js/MongoDB project.
|
|
369
437
|
|
|
370
|
-
---
|
|
438
|
+
---
|
|
439
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import ApiFeatures from "./src/api-features.js";
|
|
2
|
+
import catchError from "./src/errorHandler.js";
|
|
3
|
+
import HandleERROR from "./src/handleError.js";
|
|
4
|
+
import catchAsync from "./src/catchAsync.js";
|
|
5
|
+
export {catchError,HandleERROR,catchAsync}
|
|
6
|
+
export default ApiFeatures
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanta-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Advanced API features and security configuration for Node.js/MongoDB.",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"postinstall": "node bin/create-security-config.js",
|
|
8
8
|
"test": "jest",
|
|
9
|
-
"start": "node
|
|
9
|
+
"start": "node index.js"
|
|
10
10
|
},
|
|
11
11
|
"keywords": [
|
|
12
12
|
"api",
|
package/src/api-features.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// api-features.js
|
|
2
1
|
import mongoose from "mongoose";
|
|
3
2
|
import winston from "winston";
|
|
4
3
|
import { securityConfig } from "./config.js";
|
|
@@ -170,8 +169,6 @@ export class ApiFeatures {
|
|
|
170
169
|
});
|
|
171
170
|
});
|
|
172
171
|
|
|
173
|
-
// پشتیبانی از nested populate: در صورت نیاز، منطق تو در تو را میتوانید اینجا اضافه کنید.
|
|
174
|
-
|
|
175
172
|
return this;
|
|
176
173
|
}
|
|
177
174
|
|
|
@@ -184,11 +181,9 @@ export class ApiFeatures {
|
|
|
184
181
|
|
|
185
182
|
async execute(options = {}) {
|
|
186
183
|
try {
|
|
187
|
-
// انتخاب حالت cursor در مواقع پردازش دادههای حجیم
|
|
188
184
|
if (options.useCursor === true) {
|
|
189
185
|
this.useCursor = true;
|
|
190
186
|
}
|
|
191
|
-
// اجرای موازی pipelineهای شمارش و داده
|
|
192
187
|
const [countResult, dataResult] = await Promise.all([
|
|
193
188
|
this.Model.aggregate([...this.countPipeline, { $count: "total" }]),
|
|
194
189
|
(this.useCursor
|
|
@@ -258,7 +253,22 @@ export class ApiFeatures {
|
|
|
258
253
|
|
|
259
254
|
#sanitizeNestedObjects(obj) {
|
|
260
255
|
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
261
|
-
|
|
256
|
+
// Handle ObjectId fields with nested operators
|
|
257
|
+
if (key.endsWith("Id") && typeof value === "object" && !Array.isArray(value)) {
|
|
258
|
+
const sanitizedObj = {};
|
|
259
|
+
for (const [op, val] of Object.entries(value)) {
|
|
260
|
+
if (["$eq", "$ne", "$gt", "$gte", "$lt", "$lte"].includes(op) && mongoose.isValidObjectId(val)) {
|
|
261
|
+
sanitizedObj[op] = new mongoose.Types.ObjectId(val);
|
|
262
|
+
} else if (["$in", "$nin"].includes(op) && Array.isArray(val)) {
|
|
263
|
+
sanitizedObj[op] = val
|
|
264
|
+
.filter(v => mongoose.isValidObjectId(v))
|
|
265
|
+
.map(v => new mongoose.Types.ObjectId(v));
|
|
266
|
+
} else {
|
|
267
|
+
sanitizedObj[op] = val;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
acc[key] = sanitizedObj;
|
|
271
|
+
} else if (typeof value === "object" && !Array.isArray(value)) {
|
|
262
272
|
acc[key] = this.#sanitizeNestedObjects(value);
|
|
263
273
|
} else {
|
|
264
274
|
acc[key] = this.#sanitizeValue(key, value);
|
|
@@ -274,7 +284,7 @@ export class ApiFeatures {
|
|
|
274
284
|
if (typeof value === "string") {
|
|
275
285
|
if (value === "true") return true;
|
|
276
286
|
if (value === "false") return false;
|
|
277
|
-
if (/^\d+$/.test(value)) return parseInt(value);
|
|
287
|
+
if (/^\d+$/.test(value)) return parseInt(value, 10);
|
|
278
288
|
}
|
|
279
289
|
return value;
|
|
280
290
|
}
|