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/README.md
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
4
5
|
|
|
5
|
-
# Response Kit
|
|
6
|
+
# Response Kit v2.0 🚀
|
|
6
7
|
|
|
7
|
-
A
|
|
8
|
+
A production-grade, lightweight API response utility for **Express.js** and **Node.js** applications.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Version 2 brings **middleware support**, **global configuration**, **async handlers**, and a **scalable architecture** while maintaining **100% backward compatibility** with v1.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ✨ Why Response Kit?
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
✅ **Standardized API responses** across your entire application
|
|
17
|
+
✅ **Express middleware** for cleaner route handlers
|
|
18
|
+
✅ **Global configuration** - customize once, apply everywhere
|
|
19
|
+
✅ **Async handler** - eliminate repetitive try-catch blocks
|
|
20
|
+
✅ **TypeScript support** with comprehensive type definitions
|
|
21
|
+
✅ **Zero dependencies** - lightweight and fast
|
|
22
|
+
✅ **Production-ready** - follows SOLID principles and clean architecture
|
|
23
|
+
✅ **Backward compatible** - upgrade from v1 without breaking changes
|
|
20
24
|
|
|
21
25
|
---
|
|
22
26
|
|
|
23
|
-
## Installation
|
|
27
|
+
## 📦 Installation
|
|
24
28
|
|
|
25
29
|
```bash
|
|
26
30
|
npm install response-kit
|
|
@@ -28,206 +32,352 @@ npm install response-kit
|
|
|
28
32
|
|
|
29
33
|
---
|
|
30
34
|
|
|
31
|
-
## Quick Start
|
|
35
|
+
## 🎯 Quick Start
|
|
32
36
|
|
|
33
|
-
###
|
|
37
|
+
### Method 1: Using Middleware (Recommended - v2)
|
|
34
38
|
|
|
35
39
|
```js
|
|
36
|
-
const
|
|
40
|
+
const express = require('express');
|
|
41
|
+
const response = require('response-kit');
|
|
42
|
+
|
|
43
|
+
const app = express();
|
|
44
|
+
|
|
45
|
+
// Attach response helpers to res object
|
|
46
|
+
app.use(response.middleware());
|
|
47
|
+
|
|
48
|
+
app.get('/user/:id', async (req, res) => {
|
|
49
|
+
const user = await getUserById(req.params.id);
|
|
50
|
+
|
|
51
|
+
if (!user) {
|
|
52
|
+
return res.notFound('User not found');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return res.success(user, 'User fetched successfully');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
app.listen(3000);
|
|
37
59
|
```
|
|
38
60
|
|
|
39
|
-
###
|
|
61
|
+
### Method 2: Direct Function Calls (v1 - Still Supported)
|
|
40
62
|
|
|
41
63
|
```js
|
|
42
|
-
|
|
64
|
+
const response = require('response-kit');
|
|
65
|
+
|
|
66
|
+
app.get('/user/:id', async (req, res) => {
|
|
67
|
+
const user = await getUserById(req.params.id);
|
|
68
|
+
|
|
69
|
+
if (!user) {
|
|
70
|
+
return response.notFound(res, 'User not found');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return response.success(res, user, 'User fetched successfully');
|
|
74
|
+
});
|
|
43
75
|
```
|
|
44
76
|
|
|
45
77
|
---
|
|
46
78
|
|
|
47
|
-
##
|
|
79
|
+
## 🔧 Configuration
|
|
80
|
+
|
|
81
|
+
### Global Configuration
|
|
48
82
|
|
|
49
|
-
|
|
83
|
+
Configure once, apply everywhere:
|
|
50
84
|
|
|
51
85
|
```js
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"User fetched successfully"
|
|
63
|
-
);
|
|
86
|
+
const response = require('response-kit');
|
|
87
|
+
|
|
88
|
+
response.configure({
|
|
89
|
+
successKey: 'success', // Key for success status
|
|
90
|
+
dataKey: 'data', // Key for response data
|
|
91
|
+
messageKey: 'message', // Key for messages
|
|
92
|
+
errorKey: 'errors', // Key for error details
|
|
93
|
+
includeTimestamp: true, // Add timestamp to responses
|
|
94
|
+
includeRequestId: true, // Add request ID to responses
|
|
95
|
+
includeMeta: false, // Add request metadata
|
|
64
96
|
});
|
|
65
97
|
```
|
|
66
98
|
|
|
67
|
-
|
|
99
|
+
**Example Response with Configuration:**
|
|
68
100
|
|
|
69
101
|
```json
|
|
70
102
|
{
|
|
71
103
|
"success": true,
|
|
72
|
-
"message": "User
|
|
104
|
+
"message": "User created successfully",
|
|
73
105
|
"data": {
|
|
74
106
|
"id": 1,
|
|
75
|
-
"name": "John Doe"
|
|
76
|
-
|
|
77
|
-
|
|
107
|
+
"name": "John Doe"
|
|
108
|
+
},
|
|
109
|
+
"timestamp": "2024-01-15T10:30:00.000Z",
|
|
110
|
+
"requestId": "1705315800000-a1b2c3d4e"
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Custom Keys Example
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
response.configure({
|
|
118
|
+
successKey: 'status',
|
|
119
|
+
dataKey: 'result',
|
|
120
|
+
messageKey: 'msg',
|
|
121
|
+
errorKey: 'validationErrors',
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Output:**
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"status": true,
|
|
130
|
+
"msg": "Success",
|
|
131
|
+
"result": { "id": 1 }
|
|
78
132
|
}
|
|
79
133
|
```
|
|
80
134
|
|
|
81
135
|
---
|
|
82
136
|
|
|
83
|
-
|
|
137
|
+
## 🎭 Middleware Usage
|
|
138
|
+
|
|
139
|
+
### Basic Setup
|
|
84
140
|
|
|
85
141
|
```js
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
);
|
|
142
|
+
const express = require('express');
|
|
143
|
+
const response = require('response-kit');
|
|
144
|
+
|
|
145
|
+
const app = express();
|
|
146
|
+
|
|
147
|
+
// Apply middleware globally
|
|
148
|
+
app.use(response.middleware());
|
|
149
|
+
|
|
150
|
+
// Now all routes have access to response helpers via res object
|
|
151
|
+
app.get('/users', (req, res) => {
|
|
152
|
+
res.success(users, 'Users fetched successfully');
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Available Methods on `res` Object
|
|
157
|
+
|
|
158
|
+
After applying middleware, the following methods are available:
|
|
159
|
+
|
|
160
|
+
- `res.success(data, message, statusCode)`
|
|
161
|
+
- `res.created(data, message)`
|
|
162
|
+
- `res.badRequest(message)`
|
|
163
|
+
- `res.unauthorized(message)`
|
|
164
|
+
- `res.forbidden(message)`
|
|
165
|
+
- `res.notFound(message)`
|
|
166
|
+
- `res.conflict(message)`
|
|
167
|
+
- `res.internalError(message)`
|
|
168
|
+
- `res.validationError(errors, message)`
|
|
169
|
+
- `res.paginate(data, page, limit, total)`
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🔄 Async Handler
|
|
174
|
+
|
|
175
|
+
Eliminate repetitive try-catch blocks in your route handlers.
|
|
176
|
+
|
|
177
|
+
### Without Async Handler ❌
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
app.get('/users/:id', async (req, res) => {
|
|
181
|
+
try {
|
|
182
|
+
const user = await User.findById(req.params.id);
|
|
183
|
+
return res.success(user);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
return res.internalError(error.message);
|
|
186
|
+
}
|
|
97
187
|
});
|
|
98
188
|
```
|
|
99
189
|
|
|
100
|
-
|
|
190
|
+
### With Async Handler ✅
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
app.get('/users/:id', response.asyncHandler(async (req, res) => {
|
|
194
|
+
const user = await User.findById(req.params.id);
|
|
195
|
+
return res.success(user);
|
|
196
|
+
}));
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Any errors thrown inside the handler are automatically caught and passed to Express error handling middleware.
|
|
200
|
+
|
|
201
|
+
### Complete Example with Error Handler
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
const express = require('express');
|
|
205
|
+
const response = require('response-kit');
|
|
206
|
+
|
|
207
|
+
const app = express();
|
|
208
|
+
|
|
209
|
+
app.use(response.middleware());
|
|
210
|
+
|
|
211
|
+
// Routes with async handler
|
|
212
|
+
app.get('/users/:id', response.asyncHandler(async (req, res) => {
|
|
213
|
+
const user = await User.findById(req.params.id);
|
|
214
|
+
|
|
215
|
+
if (!user) {
|
|
216
|
+
return res.notFound('User not found');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return res.success(user);
|
|
220
|
+
}));
|
|
221
|
+
|
|
222
|
+
// Global error handler
|
|
223
|
+
app.use((err, req, res, next) => {
|
|
224
|
+
console.error(err.stack);
|
|
225
|
+
res.internalError(err.message || 'Something went wrong');
|
|
226
|
+
});
|
|
101
227
|
|
|
102
|
-
|
|
103
|
-
201 Created
|
|
228
|
+
app.listen(3000);
|
|
104
229
|
```
|
|
105
230
|
|
|
106
231
|
---
|
|
107
232
|
|
|
108
|
-
##
|
|
233
|
+
## 📖 API Reference
|
|
234
|
+
|
|
235
|
+
### Success Responses
|
|
109
236
|
|
|
110
|
-
|
|
237
|
+
#### `success(data, message, statusCode)`
|
|
238
|
+
|
|
239
|
+
Send a successful response.
|
|
111
240
|
|
|
112
241
|
```js
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
242
|
+
res.success(
|
|
243
|
+
{ id: 1, name: 'John' },
|
|
244
|
+
'User fetched successfully',
|
|
245
|
+
200
|
|
116
246
|
);
|
|
117
247
|
```
|
|
118
248
|
|
|
119
|
-
|
|
120
|
-
|
|
249
|
+
**Response:**
|
|
121
250
|
```json
|
|
122
251
|
{
|
|
123
|
-
"success":
|
|
124
|
-
"message": "
|
|
125
|
-
"
|
|
252
|
+
"success": true,
|
|
253
|
+
"message": "User fetched successfully",
|
|
254
|
+
"data": { "id": 1, "name": "John" }
|
|
126
255
|
}
|
|
127
256
|
```
|
|
128
257
|
|
|
129
|
-
|
|
258
|
+
#### `created(data, message)`
|
|
130
259
|
|
|
131
|
-
|
|
260
|
+
Send a 201 Created response.
|
|
132
261
|
|
|
133
262
|
```js
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
263
|
+
res.created(
|
|
264
|
+
{ id: 1, name: 'John' },
|
|
265
|
+
'User created successfully'
|
|
137
266
|
);
|
|
138
267
|
```
|
|
139
268
|
|
|
269
|
+
**Status Code:** `201`
|
|
270
|
+
|
|
140
271
|
---
|
|
141
272
|
|
|
142
|
-
###
|
|
273
|
+
### Error Responses
|
|
274
|
+
|
|
275
|
+
#### `badRequest(message)`
|
|
276
|
+
|
|
277
|
+
Send a 400 Bad Request response.
|
|
143
278
|
|
|
144
279
|
```js
|
|
145
|
-
|
|
146
|
-
res,
|
|
147
|
-
"Access Denied"
|
|
148
|
-
);
|
|
280
|
+
res.badRequest('Invalid input data');
|
|
149
281
|
```
|
|
150
282
|
|
|
151
|
-
|
|
283
|
+
**Status Code:** `400`
|
|
152
284
|
|
|
153
|
-
|
|
285
|
+
#### `unauthorized(message)`
|
|
286
|
+
|
|
287
|
+
Send a 401 Unauthorized response.
|
|
154
288
|
|
|
155
289
|
```js
|
|
156
|
-
|
|
157
|
-
res,
|
|
158
|
-
"User Not Found"
|
|
159
|
-
);
|
|
290
|
+
res.unauthorized('Invalid credentials');
|
|
160
291
|
```
|
|
161
292
|
|
|
162
|
-
|
|
293
|
+
**Status Code:** `401`
|
|
163
294
|
|
|
164
|
-
|
|
295
|
+
#### `forbidden(message)`
|
|
296
|
+
|
|
297
|
+
Send a 403 Forbidden response.
|
|
165
298
|
|
|
166
299
|
```js
|
|
167
|
-
|
|
168
|
-
res,
|
|
169
|
-
"Email Already Exists"
|
|
170
|
-
);
|
|
300
|
+
res.forbidden('Access denied');
|
|
171
301
|
```
|
|
172
302
|
|
|
173
|
-
|
|
303
|
+
**Status Code:** `403`
|
|
174
304
|
|
|
175
|
-
|
|
305
|
+
#### `notFound(message)`
|
|
306
|
+
|
|
307
|
+
Send a 404 Not Found response.
|
|
176
308
|
|
|
177
309
|
```js
|
|
178
|
-
|
|
179
|
-
res,
|
|
180
|
-
"Something Went Wrong"
|
|
181
|
-
);
|
|
310
|
+
res.notFound('User not found');
|
|
182
311
|
```
|
|
183
312
|
|
|
184
|
-
|
|
313
|
+
**Status Code:** `404`
|
|
185
314
|
|
|
186
|
-
|
|
315
|
+
#### `conflict(message)`
|
|
316
|
+
|
|
317
|
+
Send a 409 Conflict response.
|
|
187
318
|
|
|
188
319
|
```js
|
|
189
|
-
|
|
190
|
-
res,
|
|
191
|
-
{
|
|
192
|
-
email: "Email is required",
|
|
193
|
-
password: "Password is required"
|
|
194
|
-
}
|
|
195
|
-
);
|
|
320
|
+
res.conflict('Email already exists');
|
|
196
321
|
```
|
|
197
322
|
|
|
198
|
-
|
|
323
|
+
**Status Code:** `409`
|
|
324
|
+
|
|
325
|
+
#### `internalError(message)`
|
|
326
|
+
|
|
327
|
+
Send a 500 Internal Server Error response.
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
res.internalError('Database connection failed');
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Status Code:** `500`
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
### Validation Errors
|
|
338
|
+
|
|
339
|
+
#### `validationError(errors, message)`
|
|
199
340
|
|
|
341
|
+
Send a 422 Unprocessable Entity response with validation errors.
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
res.validationError({
|
|
345
|
+
email: 'Email is required',
|
|
346
|
+
password: 'Password must be at least 8 characters'
|
|
347
|
+
}, 'Validation failed');
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Response:**
|
|
200
351
|
```json
|
|
201
352
|
{
|
|
202
353
|
"success": false,
|
|
203
|
-
"message": "Validation
|
|
354
|
+
"message": "Validation failed",
|
|
204
355
|
"errors": {
|
|
205
356
|
"email": "Email is required",
|
|
206
|
-
"password": "Password
|
|
357
|
+
"password": "Password must be at least 8 characters"
|
|
207
358
|
}
|
|
208
359
|
}
|
|
209
360
|
```
|
|
210
361
|
|
|
362
|
+
**Status Code:** `422`
|
|
363
|
+
|
|
211
364
|
---
|
|
212
365
|
|
|
213
|
-
|
|
366
|
+
### Pagination
|
|
367
|
+
|
|
368
|
+
#### `paginate(data, page, limit, total)`
|
|
369
|
+
|
|
370
|
+
Send a paginated response.
|
|
214
371
|
|
|
215
372
|
```js
|
|
216
|
-
|
|
217
|
-
res,
|
|
218
|
-
users,
|
|
219
|
-
1,
|
|
220
|
-
10,
|
|
221
|
-
100
|
|
222
|
-
);
|
|
373
|
+
res.paginate(users, 1, 10, 100);
|
|
223
374
|
```
|
|
224
375
|
|
|
225
|
-
|
|
226
|
-
|
|
376
|
+
**Response:**
|
|
227
377
|
```json
|
|
228
378
|
{
|
|
229
379
|
"success": true,
|
|
230
|
-
"data": [],
|
|
380
|
+
"data": [...],
|
|
231
381
|
"pagination": {
|
|
232
382
|
"page": 1,
|
|
233
383
|
"limit": 10,
|
|
@@ -239,55 +389,316 @@ Output
|
|
|
239
389
|
|
|
240
390
|
---
|
|
241
391
|
|
|
242
|
-
##
|
|
243
|
-
|
|
244
|
-
| Method | Description |
|
|
245
|
-
| ----------------- | ------------------------- |
|
|
246
|
-
| success() | Send success response |
|
|
247
|
-
| created() | Send 201 created response |
|
|
248
|
-
| badRequest() | Send 400 response |
|
|
249
|
-
| unauthorized() | Send 401 response |
|
|
250
|
-
| forbidden() | Send 403 response |
|
|
251
|
-
| notFound() | Send 404 response |
|
|
252
|
-
| conflict() | Send 409 response |
|
|
253
|
-
| internalError() | Send 500 response |
|
|
254
|
-
| validationError() | Send validation errors |
|
|
255
|
-
| paginate() | Send paginated response |
|
|
392
|
+
## 🔄 Migration Guide (v1 to v2)
|
|
256
393
|
|
|
257
|
-
|
|
394
|
+
### Good News: Zero Breaking Changes! 🎉
|
|
258
395
|
|
|
259
|
-
|
|
396
|
+
All v1 APIs work exactly as before. You can upgrade and adopt v2 features gradually.
|
|
260
397
|
|
|
261
|
-
|
|
398
|
+
### Step 1: Update Package
|
|
262
399
|
|
|
263
|
-
```
|
|
264
|
-
|
|
400
|
+
```bash
|
|
401
|
+
npm install response-kit@latest
|
|
402
|
+
```
|
|
265
403
|
|
|
266
|
-
|
|
404
|
+
### Step 2: Keep Using v1 API (Optional)
|
|
405
|
+
|
|
406
|
+
```js
|
|
407
|
+
// This still works perfectly
|
|
408
|
+
response.success(res, data, message);
|
|
409
|
+
response.notFound(res, 'Not found');
|
|
267
410
|
```
|
|
268
411
|
|
|
269
|
-
|
|
412
|
+
### Step 3: Gradually Adopt v2 Features
|
|
413
|
+
|
|
414
|
+
#### Add Middleware
|
|
415
|
+
|
|
416
|
+
```js
|
|
417
|
+
app.use(response.middleware());
|
|
418
|
+
|
|
419
|
+
// Now you can use
|
|
420
|
+
res.success(data, message);
|
|
421
|
+
res.notFound('Not found');
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
#### Add Configuration
|
|
425
|
+
|
|
426
|
+
```js
|
|
427
|
+
response.configure({
|
|
428
|
+
includeTimestamp: true,
|
|
429
|
+
includeRequestId: true,
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
#### Use Async Handler
|
|
434
|
+
|
|
435
|
+
```js
|
|
436
|
+
app.get('/users', response.asyncHandler(async (req, res) => {
|
|
437
|
+
const users = await User.find();
|
|
438
|
+
res.success(users);
|
|
439
|
+
}));
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Migration Examples
|
|
443
|
+
|
|
444
|
+
#### Before (v1):
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
app.get('/users/:id', async (req, res) => {
|
|
448
|
+
try {
|
|
449
|
+
const user = await User.findById(req.params.id);
|
|
450
|
+
if (!user) {
|
|
451
|
+
return response.notFound(res, 'User not found');
|
|
452
|
+
}
|
|
453
|
+
return response.success(res, user);
|
|
454
|
+
} catch (error) {
|
|
455
|
+
return response.internalError(res, error.message);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### After (v2):
|
|
461
|
+
|
|
462
|
+
```js
|
|
463
|
+
app.use(response.middleware());
|
|
464
|
+
|
|
465
|
+
app.get('/users/:id', response.asyncHandler(async (req, res) => {
|
|
466
|
+
const user = await User.findById(req.params.id);
|
|
467
|
+
if (!user) {
|
|
468
|
+
return res.notFound('User not found');
|
|
469
|
+
}
|
|
470
|
+
return res.success(user);
|
|
471
|
+
}));
|
|
472
|
+
```
|
|
270
473
|
|
|
271
474
|
---
|
|
272
475
|
|
|
273
|
-
## Examples
|
|
476
|
+
## 💡 Complete Examples
|
|
274
477
|
|
|
275
|
-
|
|
478
|
+
### Example 1: RESTful User API
|
|
276
479
|
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
480
|
+
```js
|
|
481
|
+
const express = require('express');
|
|
482
|
+
const response = require('response-kit');
|
|
483
|
+
|
|
484
|
+
const app = express();
|
|
485
|
+
app.use(express.json());
|
|
486
|
+
app.use(response.middleware());
|
|
487
|
+
|
|
488
|
+
// Configure globally
|
|
489
|
+
response.configure({
|
|
490
|
+
includeTimestamp: true,
|
|
491
|
+
includeRequestId: true,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Get all users with pagination
|
|
495
|
+
app.get('/users', response.asyncHandler(async (req, res) => {
|
|
496
|
+
const page = parseInt(req.query.page) || 1;
|
|
497
|
+
const limit = parseInt(req.query.limit) || 10;
|
|
498
|
+
|
|
499
|
+
const users = await User.find()
|
|
500
|
+
.skip((page - 1) * limit)
|
|
501
|
+
.limit(limit);
|
|
502
|
+
|
|
503
|
+
const total = await User.countDocuments();
|
|
504
|
+
|
|
505
|
+
return res.paginate(users, page, limit, total);
|
|
506
|
+
}));
|
|
507
|
+
|
|
508
|
+
// Get user by ID
|
|
509
|
+
app.get('/users/:id', response.asyncHandler(async (req, res) => {
|
|
510
|
+
const user = await User.findById(req.params.id);
|
|
511
|
+
|
|
512
|
+
if (!user) {
|
|
513
|
+
return res.notFound('User not found');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return res.success(user, 'User fetched successfully');
|
|
517
|
+
}));
|
|
518
|
+
|
|
519
|
+
// Create new user
|
|
520
|
+
app.post('/users', response.asyncHandler(async (req, res) => {
|
|
521
|
+
const { email, name, password } = req.body;
|
|
522
|
+
|
|
523
|
+
// Validation
|
|
524
|
+
if (!email || !name || !password) {
|
|
525
|
+
return res.validationError({
|
|
526
|
+
email: !email ? 'Email is required' : undefined,
|
|
527
|
+
name: !name ? 'Name is required' : undefined,
|
|
528
|
+
password: !password ? 'Password is required' : undefined,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Check if user exists
|
|
533
|
+
const existingUser = await User.findOne({ email });
|
|
534
|
+
if (existingUser) {
|
|
535
|
+
return res.conflict('User with this email already exists');
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Create user
|
|
539
|
+
const user = await User.create({ email, name, password });
|
|
540
|
+
|
|
541
|
+
return res.created(user, 'User created successfully');
|
|
542
|
+
}));
|
|
543
|
+
|
|
544
|
+
// Update user
|
|
545
|
+
app.put('/users/:id', response.asyncHandler(async (req, res) => {
|
|
546
|
+
const user = await User.findByIdAndUpdate(
|
|
547
|
+
req.params.id,
|
|
548
|
+
req.body,
|
|
549
|
+
{ new: true }
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
if (!user) {
|
|
553
|
+
return res.notFound('User not found');
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return res.success(user, 'User updated successfully');
|
|
557
|
+
}));
|
|
558
|
+
|
|
559
|
+
// Delete user
|
|
560
|
+
app.delete('/users/:id', response.asyncHandler(async (req, res) => {
|
|
561
|
+
const user = await User.findByIdAndDelete(req.params.id);
|
|
562
|
+
|
|
563
|
+
if (!user) {
|
|
564
|
+
return res.notFound('User not found');
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return res.success(null, 'User deleted successfully');
|
|
568
|
+
}));
|
|
569
|
+
|
|
570
|
+
// Global error handler
|
|
571
|
+
app.use((err, req, res, next) => {
|
|
572
|
+
console.error(err.stack);
|
|
573
|
+
res.internalError(err.message || 'Internal server error');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
app.listen(3000, () => {
|
|
577
|
+
console.log('Server running on port 3000');
|
|
578
|
+
});
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Example 2: Authentication API
|
|
582
|
+
|
|
583
|
+
```js
|
|
584
|
+
const express = require('express');
|
|
585
|
+
const response = require('response-kit');
|
|
586
|
+
const jwt = require('jsonwebtoken');
|
|
587
|
+
|
|
588
|
+
const app = express();
|
|
589
|
+
app.use(express.json());
|
|
590
|
+
app.use(response.middleware());
|
|
591
|
+
|
|
592
|
+
// Login
|
|
593
|
+
app.post('/auth/login', response.asyncHandler(async (req, res) => {
|
|
594
|
+
const { email, password } = req.body;
|
|
595
|
+
|
|
596
|
+
if (!email || !password) {
|
|
597
|
+
return res.badRequest('Email and password are required');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const user = await User.findOne({ email });
|
|
601
|
+
|
|
602
|
+
if (!user || !await user.comparePassword(password)) {
|
|
603
|
+
return res.unauthorized('Invalid credentials');
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
|
|
607
|
+
|
|
608
|
+
return res.success({ token, user }, 'Login successful');
|
|
609
|
+
}));
|
|
610
|
+
|
|
611
|
+
// Protected route
|
|
612
|
+
app.get('/profile', authenticateToken, response.asyncHandler(async (req, res) => {
|
|
613
|
+
const user = await User.findById(req.user.id);
|
|
614
|
+
|
|
615
|
+
if (!user) {
|
|
616
|
+
return res.notFound('User not found');
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return res.success(user);
|
|
620
|
+
}));
|
|
621
|
+
|
|
622
|
+
// Middleware
|
|
623
|
+
function authenticateToken(req, res, next) {
|
|
624
|
+
const token = req.headers['authorization']?.split(' ')[1];
|
|
625
|
+
|
|
626
|
+
if (!token) {
|
|
627
|
+
return res.unauthorized('Access token required');
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
req.user = jwt.verify(token, process.env.JWT_SECRET);
|
|
632
|
+
next();
|
|
633
|
+
} catch (error) {
|
|
634
|
+
return res.forbidden('Invalid or expired token');
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
app.listen(3000);
|
|
281
639
|
```
|
|
282
640
|
|
|
283
641
|
---
|
|
284
642
|
|
|
285
|
-
##
|
|
643
|
+
## 📚 Documentation
|
|
286
644
|
|
|
287
|
-
|
|
645
|
+
- [Getting Started](./docs/getting-started.md)
|
|
646
|
+
- [Success Responses](./docs/success-response.md)
|
|
647
|
+
- [Error Responses](./docs/error-response.md)
|
|
648
|
+
- [Pagination](./docs/pagination.md)
|
|
288
649
|
|
|
289
650
|
---
|
|
290
651
|
|
|
291
|
-
##
|
|
652
|
+
## 🤝 Contributing
|
|
653
|
+
|
|
654
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## 📝 Changelog
|
|
659
|
+
|
|
660
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release notes.
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## 📄 License
|
|
665
|
+
|
|
666
|
+
MIT © [Piyush Yadav](https://github.com/piyush72yaduvanshi)
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## 🌟 Features Summary
|
|
671
|
+
|
|
672
|
+
| Feature | v1 | v2 |
|
|
673
|
+
|---------|----|----|
|
|
674
|
+
| Success/Error responses | ✅ | ✅ |
|
|
675
|
+
| Pagination | ✅ | ✅ |
|
|
676
|
+
| TypeScript support | ✅ | ✅ |
|
|
677
|
+
| Express middleware | ❌ | ✅ |
|
|
678
|
+
| Global configuration | ❌ | ✅ |
|
|
679
|
+
| Async handler | ❌ | ✅ |
|
|
680
|
+
| Request ID tracking | ❌ | ✅ |
|
|
681
|
+
| Timestamp support | ❌ | ✅ |
|
|
682
|
+
| Custom response keys | ❌ | ✅ |
|
|
683
|
+
| Backward compatible | - | ✅ |
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## 🚀 Why Upgrade to v2?
|
|
688
|
+
|
|
689
|
+
1. **Cleaner Code**: Middleware reduces boilerplate
|
|
690
|
+
2. **Flexible Configuration**: Customize response structure globally
|
|
691
|
+
3. **Better Error Handling**: Async handler eliminates try-catch blocks
|
|
692
|
+
4. **Production Features**: Request IDs, timestamps, metadata
|
|
693
|
+
5. **Modern Architecture**: SOLID principles, scalable structure
|
|
694
|
+
6. **Zero Risk**: 100% backward compatible with v1
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## ⭐ Show Your Support
|
|
699
|
+
|
|
700
|
+
If you find this package helpful, please give it a star on [GitHub](https://github.com/piyush72yaduvanshi/api-response-kit)!
|
|
701
|
+
|
|
702
|
+
---
|
|
292
703
|
|
|
293
|
-
|
|
704
|
+
**Built with ❤️ by developers, for developers.**
|