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 CHANGED
@@ -1,26 +1,30 @@
1
- ![npm](https://img.shields.io/npm/v/api-response-kit)
2
- ![downloads](https://img.shields.io/npm/dm/api-response-kit)
3
- ![license](https://img.shields.io/npm/l/api-response-kit)
1
+ ![npm](https://img.shields.io/npm/v/response-kit)
2
+ ![downloads](https://img.shields.io/npm/dm/response-kit)
3
+ ![license](https://img.shields.io/npm/l/response-kit)
4
+ ![build](https://img.shields.io/badge/build-passing-brightgreen)
4
5
 
5
- # Response Kit
6
+ # Response Kit v2.0 🚀
6
7
 
7
- A lightweight, developer-friendly utility for standardized API responses in Express.js and Node.js applications.
8
+ A production-grade, lightweight API response utility for **Express.js** and **Node.js** applications.
8
9
 
9
- Stop writing repetitive response code in every project.
10
+ Version 2 brings **middleware support**, **global configuration**, **async handlers**, and a **scalable architecture** while maintaining **100% backward compatibility** with v1.
10
11
 
11
- ## Features
12
+ ---
13
+
14
+ ## ✨ Why Response Kit?
12
15
 
13
- * Standard Success Responses
14
- * Standard Error Responses
15
- * Validation Error Handling
16
- * Pagination Support
17
- * TypeScript Support
18
- * ESM + CommonJS Support
19
- * Lightweight & Zero Dependencies
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
- ### CommonJS
37
+ ### Method 1: Using Middleware (Recommended - v2)
34
38
 
35
39
  ```js
36
- const response = require("response-kit");
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
- ### ESM
61
+ ### Method 2: Direct Function Calls (v1 - Still Supported)
40
62
 
41
63
  ```js
42
- import response from "response-kit";
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
- ## Basic Usage
79
+ ## 🔧 Configuration
80
+
81
+ ### Global Configuration
48
82
 
49
- ### Success Response
83
+ Configure once, apply everywhere:
50
84
 
51
85
  ```js
52
- app.get("/user", (req, res) => {
53
- const user = {
54
- id: 1,
55
- name: "John Doe",
56
- email: "john@example.com"
57
- };
58
-
59
- response.success(
60
- res,
61
- user,
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
- Output
99
+ **Example Response with Configuration:**
68
100
 
69
101
  ```json
70
102
  {
71
103
  "success": true,
72
- "message": "User fetched successfully",
104
+ "message": "User created successfully",
73
105
  "data": {
74
106
  "id": 1,
75
- "name": "John Doe",
76
- "email": "john@example.com"
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
- ### Created Response
137
+ ## 🎭 Middleware Usage
138
+
139
+ ### Basic Setup
84
140
 
85
141
  ```js
86
- app.post("/user", (req, res) => {
87
- const user = {
88
- id: 1,
89
- name: "John Doe"
90
- };
91
-
92
- response.created(
93
- res,
94
- user,
95
- "User created successfully"
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
- Status Code
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
- ```text
103
- 201 Created
228
+ app.listen(3000);
104
229
  ```
105
230
 
106
231
  ---
107
232
 
108
- ## Error Responses
233
+ ## 📖 API Reference
234
+
235
+ ### Success Responses
109
236
 
110
- ### Bad Request
237
+ #### `success(data, message, statusCode)`
238
+
239
+ Send a successful response.
111
240
 
112
241
  ```js
113
- response.badRequest(
114
- res,
115
- "Invalid Request"
242
+ res.success(
243
+ { id: 1, name: 'John' },
244
+ 'User fetched successfully',
245
+ 200
116
246
  );
117
247
  ```
118
248
 
119
- Output
120
-
249
+ **Response:**
121
250
  ```json
122
251
  {
123
- "success": false,
124
- "message": "Invalid Request",
125
- "errors": null
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
- ### Unauthorized
260
+ Send a 201 Created response.
132
261
 
133
262
  ```js
134
- response.unauthorized(
135
- res,
136
- "Invalid Token"
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
- ### Forbidden
273
+ ### Error Responses
274
+
275
+ #### `badRequest(message)`
276
+
277
+ Send a 400 Bad Request response.
143
278
 
144
279
  ```js
145
- response.forbidden(
146
- res,
147
- "Access Denied"
148
- );
280
+ res.badRequest('Invalid input data');
149
281
  ```
150
282
 
151
- ---
283
+ **Status Code:** `400`
152
284
 
153
- ### Not Found
285
+ #### `unauthorized(message)`
286
+
287
+ Send a 401 Unauthorized response.
154
288
 
155
289
  ```js
156
- response.notFound(
157
- res,
158
- "User Not Found"
159
- );
290
+ res.unauthorized('Invalid credentials');
160
291
  ```
161
292
 
162
- ---
293
+ **Status Code:** `401`
163
294
 
164
- ### Conflict
295
+ #### `forbidden(message)`
296
+
297
+ Send a 403 Forbidden response.
165
298
 
166
299
  ```js
167
- response.conflict(
168
- res,
169
- "Email Already Exists"
170
- );
300
+ res.forbidden('Access denied');
171
301
  ```
172
302
 
173
- ---
303
+ **Status Code:** `403`
174
304
 
175
- ### Internal Server Error
305
+ #### `notFound(message)`
306
+
307
+ Send a 404 Not Found response.
176
308
 
177
309
  ```js
178
- response.internalError(
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
- ## Validation Error
315
+ #### `conflict(message)`
316
+
317
+ Send a 409 Conflict response.
187
318
 
188
319
  ```js
189
- response.validationError(
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
- Output
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 Failed",
354
+ "message": "Validation failed",
204
355
  "errors": {
205
356
  "email": "Email is required",
206
- "password": "Password is required"
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
- ## Pagination
366
+ ### Pagination
367
+
368
+ #### `paginate(data, page, limit, total)`
369
+
370
+ Send a paginated response.
214
371
 
215
372
  ```js
216
- response.paginate(
217
- res,
218
- users,
219
- 1,
220
- 10,
221
- 100
222
- );
373
+ res.paginate(users, 1, 10, 100);
223
374
  ```
224
375
 
225
- Output
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
- ## API Reference
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
- ## TypeScript
396
+ All v1 APIs work exactly as before. You can upgrade and adopt v2 features gradually.
260
397
 
261
- Type definitions are included.
398
+ ### Step 1: Update Package
262
399
 
263
- ```ts
264
- import response from "response-kit";
400
+ ```bash
401
+ npm install response-kit@latest
402
+ ```
265
403
 
266
- response.success(res, user);
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
- No additional setup required.
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
- Check examples folder for complete working examples.
478
+ ### Example 1: RESTful User API
276
479
 
277
- ```bash
278
- examples/
279
- ├── commonjs-example.js
280
- └── esm-example.js
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
- ## License
643
+ ## 📚 Documentation
286
644
 
287
- MIT
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
- ## Author
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
- Piyush Yadav
704
+ **Built with ❤️ by developers, for developers.**