response-kit 1.0.0 → 2.0.0
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 +557 -146
- package/docs/error-response.md +582 -101
- package/docs/getting-started.md +436 -38
- package/docs/pagination.md +542 -77
- package/docs/success-response.md +326 -61
- package/index.d.ts +122 -20
- package/package.json +67 -51
- package/src/core/config.js +94 -0
- package/src/helpers/error.js +104 -0
- package/src/helpers/pagination.js +41 -0
- package/src/helpers/success.js +52 -0
- package/src/helpers/validation.js +32 -0
- package/src/index.js +83 -6
- package/src/middleware/asyncHandler.js +14 -0
- package/src/middleware/response.js +69 -0
- package/src/types/index.js +71 -0
- package/src/utils/constants.js +39 -0
package/package.json
CHANGED
|
@@ -1,51 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "response-kit",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "./src/index.js",
|
|
6
|
-
"types": "./index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"require": "./src/index.js",
|
|
10
|
-
"import": "./src/index.js",
|
|
11
|
-
"types": "./index.d.ts"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"src",
|
|
16
|
-
"docs",
|
|
17
|
-
"index.d.ts",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"lint": "eslint .",
|
|
23
|
-
"format": "prettier --write ."
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"response
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "response-kit",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Production-grade API response utility for Node.js and Express.js with middleware support, global configuration, and async handlers",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./src/index.js",
|
|
10
|
+
"import": "./src/index.js",
|
|
11
|
+
"types": "./index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"docs",
|
|
17
|
+
"index.d.ts",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"format": "prettier --write .",
|
|
24
|
+
"test:ts": "tsc -p tsconfig.json"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"express",
|
|
28
|
+
"nodejs",
|
|
29
|
+
"api",
|
|
30
|
+
"response",
|
|
31
|
+
"response-helper",
|
|
32
|
+
"api-response",
|
|
33
|
+
"backend",
|
|
34
|
+
"middleware",
|
|
35
|
+
"async-handler",
|
|
36
|
+
"express-middleware",
|
|
37
|
+
"response-kit",
|
|
38
|
+
"error-handler"
|
|
39
|
+
],
|
|
40
|
+
"author": "Piyush Yadav",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"type": "commonjs",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/piyush72yaduvanshi/api-response-kit.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/piyush72yaduvanshi/api-response-kit/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/piyush72yaduvanshi/api-response-kit#readme",
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"express": ">=4.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"express": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/express": "^4.17.25",
|
|
61
|
+
"@types/node": "^20.14.5",
|
|
62
|
+
"express": "^4.21.2",
|
|
63
|
+
"jest": "^30.4.2",
|
|
64
|
+
"prettier": "^3.8.4",
|
|
65
|
+
"typescript": "^6.0.3"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
class Config {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.settings = {
|
|
4
|
+
successKey: 'success',
|
|
5
|
+
dataKey: 'data',
|
|
6
|
+
messageKey: 'message',
|
|
7
|
+
errorKey: 'errors',
|
|
8
|
+
includeTimestamp: false,
|
|
9
|
+
includeRequestId: false,
|
|
10
|
+
includeMeta: false,
|
|
11
|
+
timestampKey: 'timestamp',
|
|
12
|
+
requestIdKey: 'requestId',
|
|
13
|
+
metaKey: 'meta',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Configure global settings
|
|
19
|
+
* @param {Object} options - Configuration options
|
|
20
|
+
*/
|
|
21
|
+
configure(options = {}) {
|
|
22
|
+
this.settings = {
|
|
23
|
+
...this.settings,
|
|
24
|
+
...options,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get current configuration
|
|
30
|
+
* @returns {Object} Current settings
|
|
31
|
+
*/
|
|
32
|
+
getConfig() {
|
|
33
|
+
return { ...this.settings };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reset to default configuration
|
|
38
|
+
*/
|
|
39
|
+
reset() {
|
|
40
|
+
this.settings = {
|
|
41
|
+
successKey: 'success',
|
|
42
|
+
dataKey: 'data',
|
|
43
|
+
messageKey: 'message',
|
|
44
|
+
errorKey: 'errors',
|
|
45
|
+
includeTimestamp: false,
|
|
46
|
+
includeRequestId: false,
|
|
47
|
+
includeMeta: false,
|
|
48
|
+
timestampKey: 'timestamp',
|
|
49
|
+
requestIdKey: 'requestId',
|
|
50
|
+
metaKey: 'meta',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build response object based on configuration
|
|
56
|
+
* @param {Object} baseResponse - Base response object
|
|
57
|
+
* @param {Object} req - Express request object
|
|
58
|
+
* @returns {Object} Configured response object
|
|
59
|
+
*/
|
|
60
|
+
buildResponse(baseResponse, req = null) {
|
|
61
|
+
const response = { ...baseResponse };
|
|
62
|
+
|
|
63
|
+
if (this.settings.includeTimestamp) {
|
|
64
|
+
response[this.settings.timestampKey] = new Date().toISOString();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (this.settings.includeRequestId && req) {
|
|
68
|
+
const requestId = req.id || req.headers['x-request-id'] || this.generateRequestId();
|
|
69
|
+
response[this.settings.requestIdKey] = requestId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (this.settings.includeMeta && req) {
|
|
73
|
+
response[this.settings.metaKey] = {
|
|
74
|
+
method: req.method,
|
|
75
|
+
path: req.path,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate a simple request ID
|
|
84
|
+
* @returns {string} Generated request ID
|
|
85
|
+
*/
|
|
86
|
+
generateRequestId() {
|
|
87
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Singleton instance
|
|
92
|
+
const config = new Config();
|
|
93
|
+
|
|
94
|
+
module.exports = config;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const config = require('../core/config');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Send error response
|
|
5
|
+
* @param {Object} res - Express response object
|
|
6
|
+
* @param {number} statusCode - HTTP status code
|
|
7
|
+
* @param {string} message - Error message
|
|
8
|
+
* @param {*} errors - Error details
|
|
9
|
+
* @param {Object} req - Express request object (optional)
|
|
10
|
+
* @returns {Object} Express response
|
|
11
|
+
*/
|
|
12
|
+
const sendError = (
|
|
13
|
+
res,
|
|
14
|
+
statusCode,
|
|
15
|
+
message,
|
|
16
|
+
errors = null,
|
|
17
|
+
req = null
|
|
18
|
+
) => {
|
|
19
|
+
const settings = config.getConfig();
|
|
20
|
+
|
|
21
|
+
const baseResponse = {
|
|
22
|
+
[settings.successKey]: false,
|
|
23
|
+
[settings.messageKey]: message,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Only include errors if they exist
|
|
27
|
+
if (errors !== null) {
|
|
28
|
+
baseResponse[settings.errorKey] = errors;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const response = config.buildResponse(baseResponse, req);
|
|
32
|
+
|
|
33
|
+
return res.status(statusCode).json(response);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Send 400 Bad Request response
|
|
38
|
+
* @param {Object} res - Express response object
|
|
39
|
+
* @param {string} message - Error message
|
|
40
|
+
* @param {Object} req - Express request object (optional)
|
|
41
|
+
* @returns {Object} Express response
|
|
42
|
+
*/
|
|
43
|
+
const badRequest = (res, message = 'Bad Request', req = null) =>
|
|
44
|
+
sendError(res, 400, message, null, req);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Send 401 Unauthorized response
|
|
48
|
+
* @param {Object} res - Express response object
|
|
49
|
+
* @param {string} message - Error message
|
|
50
|
+
* @param {Object} req - Express request object (optional)
|
|
51
|
+
* @returns {Object} Express response
|
|
52
|
+
*/
|
|
53
|
+
const unauthorized = (res, message = 'Unauthorized', req = null) =>
|
|
54
|
+
sendError(res, 401, message, null, req);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Send 403 Forbidden response
|
|
58
|
+
* @param {Object} res - Express response object
|
|
59
|
+
* @param {string} message - Error message
|
|
60
|
+
* @param {Object} req - Express request object (optional)
|
|
61
|
+
* @returns {Object} Express response
|
|
62
|
+
*/
|
|
63
|
+
const forbidden = (res, message = 'Forbidden', req = null) =>
|
|
64
|
+
sendError(res, 403, message, null, req);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Send 404 Not Found response
|
|
68
|
+
* @param {Object} res - Express response object
|
|
69
|
+
* @param {string} message - Error message
|
|
70
|
+
* @param {Object} req - Express request object (optional)
|
|
71
|
+
* @returns {Object} Express response
|
|
72
|
+
*/
|
|
73
|
+
const notFound = (res, message = 'Not Found', req = null) =>
|
|
74
|
+
sendError(res, 404, message, null, req);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Send 409 Conflict response
|
|
78
|
+
* @param {Object} res - Express response object
|
|
79
|
+
* @param {string} message - Error message
|
|
80
|
+
* @param {Object} req - Express request object (optional)
|
|
81
|
+
* @returns {Object} Express response
|
|
82
|
+
*/
|
|
83
|
+
const conflict = (res, message = 'Conflict', req = null) =>
|
|
84
|
+
sendError(res, 409, message, null, req);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Send 500 Internal Server Error response
|
|
88
|
+
* @param {Object} res - Express response object
|
|
89
|
+
* @param {string} message - Error message
|
|
90
|
+
* @param {Object} req - Express request object (optional)
|
|
91
|
+
* @returns {Object} Express response
|
|
92
|
+
*/
|
|
93
|
+
const internalError = (res, message = 'Internal Server Error', req = null) =>
|
|
94
|
+
sendError(res, 500, message, null, req);
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
sendError,
|
|
98
|
+
badRequest,
|
|
99
|
+
unauthorized,
|
|
100
|
+
forbidden,
|
|
101
|
+
notFound,
|
|
102
|
+
conflict,
|
|
103
|
+
internalError,
|
|
104
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const config = require('../core/config');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Send paginated response
|
|
5
|
+
* @param {Object} res - Express response object
|
|
6
|
+
* @param {Array} data - Array of data items
|
|
7
|
+
* @param {number} page - Current page number
|
|
8
|
+
* @param {number} limit - Items per page
|
|
9
|
+
* @param {number} total - Total number of items
|
|
10
|
+
* @param {Object} req - Express request object (optional)
|
|
11
|
+
* @returns {Object} Express response
|
|
12
|
+
*/
|
|
13
|
+
const paginate = (
|
|
14
|
+
res,
|
|
15
|
+
data,
|
|
16
|
+
page,
|
|
17
|
+
limit,
|
|
18
|
+
total,
|
|
19
|
+
req = null
|
|
20
|
+
) => {
|
|
21
|
+
const settings = config.getConfig();
|
|
22
|
+
|
|
23
|
+
const baseResponse = {
|
|
24
|
+
[settings.successKey]: true,
|
|
25
|
+
[settings.dataKey]: data,
|
|
26
|
+
pagination: {
|
|
27
|
+
page: parseInt(page),
|
|
28
|
+
limit: parseInt(limit),
|
|
29
|
+
total: parseInt(total),
|
|
30
|
+
totalPages: Math.ceil(total / limit),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const response = config.buildResponse(baseResponse, req);
|
|
35
|
+
|
|
36
|
+
return res.status(200).json(response);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
paginate,
|
|
41
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const config = require('../core/config');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Send success response
|
|
5
|
+
* @param {Object} res - Express response object
|
|
6
|
+
* @param {*} data - Response data
|
|
7
|
+
* @param {string} message - Success message
|
|
8
|
+
* @param {number} statusCode - HTTP status code
|
|
9
|
+
* @param {Object} req - Express request object (optional)
|
|
10
|
+
* @returns {Object} Express response
|
|
11
|
+
*/
|
|
12
|
+
const success = (
|
|
13
|
+
res,
|
|
14
|
+
data = null,
|
|
15
|
+
message = 'Success',
|
|
16
|
+
statusCode = 200,
|
|
17
|
+
req = null
|
|
18
|
+
) => {
|
|
19
|
+
const settings = config.getConfig();
|
|
20
|
+
|
|
21
|
+
const baseResponse = {
|
|
22
|
+
[settings.successKey]: true,
|
|
23
|
+
[settings.messageKey]: message,
|
|
24
|
+
[settings.dataKey]: data,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const response = config.buildResponse(baseResponse, req);
|
|
28
|
+
|
|
29
|
+
return res.status(statusCode).json(response);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Send created response (201)
|
|
34
|
+
* @param {Object} res - Express response object
|
|
35
|
+
* @param {*} data - Response data
|
|
36
|
+
* @param {string} message - Success message
|
|
37
|
+
* @param {Object} req - Express request object (optional)
|
|
38
|
+
* @returns {Object} Express response
|
|
39
|
+
*/
|
|
40
|
+
const created = (
|
|
41
|
+
res,
|
|
42
|
+
data = null,
|
|
43
|
+
message = 'Created Successfully',
|
|
44
|
+
req = null
|
|
45
|
+
) => {
|
|
46
|
+
return success(res, data, message, 201, req);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
success,
|
|
51
|
+
created,
|
|
52
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const config = require('../core/config');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Send validation error response (422)
|
|
5
|
+
* @param {Object} res - Express response object
|
|
6
|
+
* @param {Object} errors - Validation errors
|
|
7
|
+
* @param {string} message - Error message
|
|
8
|
+
* @param {Object} req - Express request object (optional)
|
|
9
|
+
* @returns {Object} Express response
|
|
10
|
+
*/
|
|
11
|
+
const validationError = (
|
|
12
|
+
res,
|
|
13
|
+
errors = {},
|
|
14
|
+
message = 'Validation Failed',
|
|
15
|
+
req = null
|
|
16
|
+
) => {
|
|
17
|
+
const settings = config.getConfig();
|
|
18
|
+
|
|
19
|
+
const baseResponse = {
|
|
20
|
+
[settings.successKey]: false,
|
|
21
|
+
[settings.messageKey]: message,
|
|
22
|
+
[settings.errorKey]: errors,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const response = config.buildResponse(baseResponse, req);
|
|
26
|
+
|
|
27
|
+
return res.status(422).json(response);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
validationError,
|
|
32
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,83 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Response Kit v2.0.0
|
|
3
|
+
* Production-grade API response utility for Express.js
|
|
4
|
+
*
|
|
5
|
+
* Backward compatible with v1.x
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const config = require('./core/config');
|
|
9
|
+
const responseMiddleware = require('./middleware/response');
|
|
10
|
+
const asyncHandler = require('./middleware/asyncHandler');
|
|
11
|
+
|
|
12
|
+
// Import refactored helpers (v2 - with config support)
|
|
13
|
+
const { success, created } = require('./helpers/success');
|
|
14
|
+
const {
|
|
15
|
+
badRequest,
|
|
16
|
+
unauthorized,
|
|
17
|
+
forbidden,
|
|
18
|
+
notFound,
|
|
19
|
+
conflict,
|
|
20
|
+
internalError,
|
|
21
|
+
} = require('./helpers/error');
|
|
22
|
+
const { validationError } = require('./helpers/validation');
|
|
23
|
+
const { paginate } = require('./helpers/pagination');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Main response object
|
|
27
|
+
* Provides both v1 (backward compatible) and v2 (new) APIs
|
|
28
|
+
*/
|
|
29
|
+
const response = {
|
|
30
|
+
// V1 API - Backward compatible
|
|
31
|
+
// These maintain the original signature: fn(res, ...)
|
|
32
|
+
success,
|
|
33
|
+
created,
|
|
34
|
+
badRequest,
|
|
35
|
+
unauthorized,
|
|
36
|
+
forbidden,
|
|
37
|
+
notFound,
|
|
38
|
+
conflict,
|
|
39
|
+
internalError,
|
|
40
|
+
validationError,
|
|
41
|
+
paginate,
|
|
42
|
+
|
|
43
|
+
// V2 API - New features
|
|
44
|
+
/**
|
|
45
|
+
* Configure global response settings
|
|
46
|
+
* @param {Object} options - Configuration options
|
|
47
|
+
*/
|
|
48
|
+
configure: (options) => config.configure(options),
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get current configuration
|
|
52
|
+
* @returns {Object} Current configuration
|
|
53
|
+
*/
|
|
54
|
+
getConfig: () => config.getConfig(),
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Reset configuration to defaults
|
|
58
|
+
*/
|
|
59
|
+
resetConfig: () => config.reset(),
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Express middleware factory
|
|
63
|
+
* Attaches response helpers to res object
|
|
64
|
+
* Usage: app.use(response.middleware())
|
|
65
|
+
* @returns {Function} Express middleware
|
|
66
|
+
*/
|
|
67
|
+
middleware: responseMiddleware,
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Async handler wrapper
|
|
71
|
+
* Eliminates try-catch blocks in route handlers
|
|
72
|
+
* Usage: router.get('/path', response.asyncHandler(async (req, res) => {...}))
|
|
73
|
+
* @param {Function} fn - Async route handler
|
|
74
|
+
* @returns {Function} Wrapped handler
|
|
75
|
+
*/
|
|
76
|
+
asyncHandler,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// For CommonJS default export
|
|
80
|
+
module.exports = response;
|
|
81
|
+
|
|
82
|
+
// For ES modules compatibility
|
|
83
|
+
module.exports.default = response;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Wraps async route handlers to catch errors
|
|
4
|
+
* @param {Function} fn - Async route handler function
|
|
5
|
+
* @returns {Function} Express middleware function
|
|
6
|
+
*/
|
|
7
|
+
function asyncHandler(fn) {
|
|
8
|
+
return function (req, res, next) {
|
|
9
|
+
// Ensure fn returns a promise, then catch any errors
|
|
10
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = asyncHandler;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const config = require('../core/config');
|
|
2
|
+
const { success, created } = require('../helpers/success');
|
|
3
|
+
const {
|
|
4
|
+
badRequest,
|
|
5
|
+
unauthorized,
|
|
6
|
+
forbidden,
|
|
7
|
+
notFound,
|
|
8
|
+
conflict,
|
|
9
|
+
internalError,
|
|
10
|
+
} = require('../helpers/error');
|
|
11
|
+
const { validationError } = require('../helpers/validation');
|
|
12
|
+
const { paginate } = require('../helpers/pagination');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Response middleware factory
|
|
16
|
+
* Attaches all response helpers to Express res object
|
|
17
|
+
* @returns {Function} Express middleware
|
|
18
|
+
*/
|
|
19
|
+
function responseMiddleware() {
|
|
20
|
+
return function (req, res, next) {
|
|
21
|
+
// Success responses
|
|
22
|
+
res.success = function (data = null, message = 'Success', statusCode = 200) {
|
|
23
|
+
return success(res, data, message, statusCode, req);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
res.created = function (data = null, message = 'Created Successfully') {
|
|
27
|
+
return created(res, data, message, req);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Error responses
|
|
31
|
+
res.badRequest = function (message = 'Bad Request') {
|
|
32
|
+
return badRequest(res, message, req);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
res.unauthorized = function (message = 'Unauthorized') {
|
|
36
|
+
return unauthorized(res, message, req);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
res.forbidden = function (message = 'Forbidden') {
|
|
40
|
+
return forbidden(res, message, req);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
res.notFound = function (message = 'Not Found') {
|
|
44
|
+
return notFound(res, message, req);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
res.conflict = function (message = 'Conflict') {
|
|
48
|
+
return conflict(res, message, req);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
res.internalError = function (message = 'Internal Server Error') {
|
|
52
|
+
return internalError(res, message, req);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Validation error
|
|
56
|
+
res.validationError = function (errors = {}, message = 'Validation Failed') {
|
|
57
|
+
return validationError(res, errors, message, req);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Pagination
|
|
61
|
+
res.paginate = function (data, page, limit, total) {
|
|
62
|
+
return paginate(res, data, page, limit, total, req);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
next();
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = responseMiddleware;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate if value is a valid HTTP status code
|
|
3
|
+
* @param {number} statusCode - Status code to validate
|
|
4
|
+
* @returns {boolean} True if valid
|
|
5
|
+
*/
|
|
6
|
+
function isValidStatusCode(statusCode) {
|
|
7
|
+
return typeof statusCode === 'number' && statusCode >= 100 && statusCode < 600;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validate if value is a string
|
|
12
|
+
* @param {*} value - Value to validate
|
|
13
|
+
* @returns {boolean} True if string
|
|
14
|
+
*/
|
|
15
|
+
function isString(value) {
|
|
16
|
+
return typeof value === 'string';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate if value is an object
|
|
21
|
+
* @param {*} value - Value to validate
|
|
22
|
+
* @returns {boolean} True if object
|
|
23
|
+
*/
|
|
24
|
+
function isObject(value) {
|
|
25
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Validate if value is an array
|
|
30
|
+
* @param {*} value - Value to validate
|
|
31
|
+
* @returns {boolean} True if array
|
|
32
|
+
*/
|
|
33
|
+
function isArray(value) {
|
|
34
|
+
return Array.isArray(value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validate pagination parameters
|
|
39
|
+
* @param {number} page - Page number
|
|
40
|
+
* @param {number} limit - Items per page
|
|
41
|
+
* @param {number} total - Total items
|
|
42
|
+
* @returns {Object} Validation result
|
|
43
|
+
*/
|
|
44
|
+
function validatePaginationParams(page, limit, total) {
|
|
45
|
+
const errors = [];
|
|
46
|
+
|
|
47
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
48
|
+
errors.push('Page must be a positive integer');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
52
|
+
errors.push('Limit must be a positive integer');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!Number.isInteger(total) || total < 0) {
|
|
56
|
+
errors.push('Total must be a non-negative integer');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
valid: errors.length === 0,
|
|
61
|
+
errors,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
isValidStatusCode,
|
|
67
|
+
isString,
|
|
68
|
+
isObject,
|
|
69
|
+
isArray,
|
|
70
|
+
validatePaginationParams,
|
|
71
|
+
};
|