@igxjs/node-components 1.0.7 → 1.0.9
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 +68 -510
- package/components/jwt.js +10 -10
- package/docs/README.md +54 -0
- package/docs/flex-router.md +167 -0
- package/docs/http-handlers.md +302 -0
- package/docs/jwt-manager.md +124 -0
- package/docs/redis-manager.md +210 -0
- package/docs/session-manager.md +160 -0
- package/index.d.ts +4 -3
- package/package.json +1 -1
- package/tests/jwt.test.js +345 -0
package/components/jwt.js
CHANGED
|
@@ -27,7 +27,7 @@ export class JwtManager {
|
|
|
27
27
|
/**
|
|
28
28
|
* Generate JWT token for user session
|
|
29
29
|
* @param {import('jose').JWTPayload} data User data payload
|
|
30
|
-
* @param {string}
|
|
30
|
+
* @param {string} secret Secret key or password for encryption
|
|
31
31
|
* @param {Object} [options] Per-call configuration overrides
|
|
32
32
|
* @param {string} [options.algorithm] Override default algorithm
|
|
33
33
|
* @param {string} [options.encryption] Override default encryption method
|
|
@@ -38,7 +38,7 @@ export class JwtManager {
|
|
|
38
38
|
* @param {string} [options.subject] Override default subject claim
|
|
39
39
|
* @returns {Promise<string>} Returns encrypted JWT token
|
|
40
40
|
*/
|
|
41
|
-
async encrypt(data,
|
|
41
|
+
async encrypt(data, secret, options = {}) {
|
|
42
42
|
const algorithm = options.algorithm || this.algorithm;
|
|
43
43
|
const encryption = options.encryption || this.encryption;
|
|
44
44
|
const expirationTime = options.expirationTime || this.expirationTime;
|
|
@@ -47,9 +47,9 @@ export class JwtManager {
|
|
|
47
47
|
const audience = options.audience || this.audience;
|
|
48
48
|
const subject = options.subject || this.subject;
|
|
49
49
|
|
|
50
|
-
const
|
|
50
|
+
const secretHash = await crypto.subtle.digest(
|
|
51
51
|
secretHashAlgorithm,
|
|
52
|
-
new TextEncoder().encode(
|
|
52
|
+
new TextEncoder().encode(secret)
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
const jwt = new EncryptJWT(data)
|
|
@@ -65,13 +65,13 @@ export class JwtManager {
|
|
|
65
65
|
if (audience) jwt.setAudience(audience);
|
|
66
66
|
if (subject) jwt.setSubject(subject);
|
|
67
67
|
|
|
68
|
-
return await jwt.encrypt(new Uint8Array(
|
|
68
|
+
return await jwt.encrypt(new Uint8Array(secretHash));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Decrypt JWT token for user session
|
|
73
73
|
* @param {string} token JWT token to decrypt
|
|
74
|
-
* @param {string}
|
|
74
|
+
* @param {string} secret Secret key or password for decryption
|
|
75
75
|
* @param {Object} [options] Per-call configuration overrides
|
|
76
76
|
* @param {number} [options.clockTolerance] Override default clock tolerance
|
|
77
77
|
* @param {string} [options.secretHashAlgorithm] Override default hash algorithm
|
|
@@ -80,16 +80,16 @@ export class JwtManager {
|
|
|
80
80
|
* @param {string} [options.subject] Expected subject claim for validation
|
|
81
81
|
* @returns {Promise<import('jose').JWTDecryptResult<import('jose').EncryptJWT>>} Returns decrypted JWT token
|
|
82
82
|
*/
|
|
83
|
-
async decrypt(token,
|
|
83
|
+
async decrypt(token, secret, options = {}) {
|
|
84
84
|
const clockTolerance = options.clockTolerance ?? this.clockTolerance;
|
|
85
85
|
const secretHashAlgorithm = options.secretHashAlgorithm || this.secretHashAlgorithm;
|
|
86
86
|
const issuer = options.issuer || this.issuer;
|
|
87
87
|
const audience = options.audience || this.audience;
|
|
88
88
|
const subject = options.subject || this.subject;
|
|
89
89
|
|
|
90
|
-
const
|
|
90
|
+
const secretHash = await crypto.subtle.digest(
|
|
91
91
|
secretHashAlgorithm,
|
|
92
|
-
new TextEncoder().encode(
|
|
92
|
+
new TextEncoder().encode(secret)
|
|
93
93
|
);
|
|
94
94
|
|
|
95
95
|
const decryptOptions = { clockTolerance };
|
|
@@ -99,6 +99,6 @@ export class JwtManager {
|
|
|
99
99
|
if (audience) decryptOptions.audience = audience;
|
|
100
100
|
if (subject) decryptOptions.subject = subject;
|
|
101
101
|
|
|
102
|
-
return await jwtDecrypt(token, new Uint8Array(
|
|
102
|
+
return await jwtDecrypt(token, new Uint8Array(secretHash), decryptOptions);
|
|
103
103
|
}
|
|
104
104
|
}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Node Components Documentation
|
|
2
|
+
|
|
3
|
+
Detailed documentation for `@igxjs/node-components` - shared components for Express.js applications.
|
|
4
|
+
|
|
5
|
+
## 📚 Component Documentation
|
|
6
|
+
|
|
7
|
+
### Core Modules
|
|
8
|
+
|
|
9
|
+
- **[SessionManager](./session-manager.md)** - SSO session management with Redis and memory storage
|
|
10
|
+
- Configuration options and singleton pattern
|
|
11
|
+
- Complete setup and usage examples
|
|
12
|
+
- API reference for all methods
|
|
13
|
+
|
|
14
|
+
- **[FlexRouter](./flex-router.md)** - Flexible routing utility for Express.js
|
|
15
|
+
- Context path and middleware management
|
|
16
|
+
- API versioning and route organization
|
|
17
|
+
- Advanced usage patterns
|
|
18
|
+
|
|
19
|
+
- **[RedisManager](./redis-manager.md)** - Redis connection management
|
|
20
|
+
- TLS/SSL support
|
|
21
|
+
- Connection monitoring and error handling
|
|
22
|
+
- Direct Redis operations
|
|
23
|
+
|
|
24
|
+
- **[JWT Manager](./jwt-manager.md)** - JWT encryption and decryption
|
|
25
|
+
- Secure token-based authentication
|
|
26
|
+
- Express.js integration patterns
|
|
27
|
+
- Refresh token implementation
|
|
28
|
+
|
|
29
|
+
- **[HTTP Handlers](./http-handlers.md)** - Standardized error handling
|
|
30
|
+
- Custom error classes and middleware
|
|
31
|
+
- HTTP status codes and messages
|
|
32
|
+
- Axios error handling and validation helpers
|
|
33
|
+
|
|
34
|
+
## 🚀 Quick Links
|
|
35
|
+
|
|
36
|
+
- [Main README](../README.md) - Package overview and installation
|
|
37
|
+
- [GitHub Repository](https://github.com/igxjs/node-components)
|
|
38
|
+
|
|
39
|
+
## 💡 Getting Help
|
|
40
|
+
|
|
41
|
+
If you need help:
|
|
42
|
+
1. Check the relevant component documentation above
|
|
43
|
+
2. Review the examples in each guide
|
|
44
|
+
3. Look at the type definitions in `index.d.ts`
|
|
45
|
+
4. Open an issue on GitHub
|
|
46
|
+
|
|
47
|
+
## 📖 Documentation Structure
|
|
48
|
+
|
|
49
|
+
Each component documentation includes:
|
|
50
|
+
- Overview of features
|
|
51
|
+
- Configuration options
|
|
52
|
+
- Basic and advanced usage examples
|
|
53
|
+
- Complete API reference
|
|
54
|
+
- Related documentation links
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# FlexRouter
|
|
2
|
+
|
|
3
|
+
A flexible routing utility for Express.js that allows mounting routers with custom context paths and middleware handlers.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
FlexRouter provides a convenient way to organize and mount Express routers with predefined context paths and optional middleware. This is particularly useful for:
|
|
8
|
+
- API versioning (e.g., `/api/v1`, `/api/v2`)
|
|
9
|
+
- Separating public and protected routes
|
|
10
|
+
- Applying middleware to specific route groups
|
|
11
|
+
- Managing complex routing hierarchies
|
|
12
|
+
|
|
13
|
+
## Usage Example
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { Router } from 'express';
|
|
17
|
+
import { FlexRouter } from '@igxjs/node-components';
|
|
18
|
+
// Assuming you have an authenticate middleware
|
|
19
|
+
// import { authenticate } from './middlewares/auth.js';
|
|
20
|
+
|
|
21
|
+
// Create routers
|
|
22
|
+
const publicRouter = Router();
|
|
23
|
+
const privateRouter = Router();
|
|
24
|
+
|
|
25
|
+
publicRouter.get('/health', (req, res) => {
|
|
26
|
+
res.send('OK');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
privateRouter.get('/users', (req, res) => {
|
|
30
|
+
res.json({ users: [] });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Define flex routers with context paths and optional middleware
|
|
34
|
+
export const routers = [
|
|
35
|
+
new FlexRouter('/api/v1/public', publicRouter),
|
|
36
|
+
new FlexRouter('/api/v1/protected', privateRouter, [authenticate]), // with middleware
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
// Mount all routers to your Express app
|
|
40
|
+
const app = express();
|
|
41
|
+
const basePath = '';
|
|
42
|
+
|
|
43
|
+
routers.forEach(router => {
|
|
44
|
+
router.mount(app, basePath);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Routes will be available at:
|
|
48
|
+
// - /api/v1/public/health
|
|
49
|
+
// - /api/v1/protected/users (with authenticate middleware)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Advanced Usage
|
|
53
|
+
|
|
54
|
+
### Multiple Middleware
|
|
55
|
+
|
|
56
|
+
You can apply multiple middleware functions to a FlexRouter:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { rateLimiter } from './middlewares/rate-limiter.js';
|
|
60
|
+
import { logger } from './middlewares/logger.js';
|
|
61
|
+
import { authenticate } from './middlewares/auth.js';
|
|
62
|
+
|
|
63
|
+
const apiRouter = Router();
|
|
64
|
+
|
|
65
|
+
apiRouter.get('/data', (req, res) => {
|
|
66
|
+
res.json({ [] });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Apply multiple middleware in order
|
|
70
|
+
const protectedApi = new FlexRouter(
|
|
71
|
+
'/api/v1',
|
|
72
|
+
apiRouter,
|
|
73
|
+
[logger, rateLimiter, authenticate] // Applied in this order
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
protectedApi.mount(app, '');
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Using Base Paths
|
|
80
|
+
|
|
81
|
+
You can add a base path when mounting routers, useful for multi-tenant applications:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const tenantRouter = Router();
|
|
85
|
+
|
|
86
|
+
tenantRouter.get('/dashboard', (req, res) => {
|
|
87
|
+
res.json({ tenant: req.params.tenantId });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const flexRouter = new FlexRouter('/api', tenantRouter);
|
|
91
|
+
|
|
92
|
+
// Mount with tenant-specific base path
|
|
93
|
+
flexRouter.mount(app, '/tenant/:tenantId');
|
|
94
|
+
|
|
95
|
+
// Route will be available at: /tenant/:tenantId/api/dashboard
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Organizing Routes by Feature
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// features/users/routes.js
|
|
102
|
+
const usersRouter = Router();
|
|
103
|
+
usersRouter.get('/', getAllUsers);
|
|
104
|
+
usersRouter.post('/', createUser);
|
|
105
|
+
export const usersFlexRouter = new FlexRouter('/users', usersRouter);
|
|
106
|
+
|
|
107
|
+
// features/products/routes.js
|
|
108
|
+
const productsRouter = Router();
|
|
109
|
+
productsRouter.get('/', getAllProducts);
|
|
110
|
+
export const productsFlexRouter = new FlexRouter('/products', productsRouter);
|
|
111
|
+
|
|
112
|
+
// app.js
|
|
113
|
+
import { usersFlexRouter } from './features/users/routes.js';
|
|
114
|
+
import { productsFlexRouter } from './features/products/routes.js';
|
|
115
|
+
|
|
116
|
+
const apiRouters = [usersFlexRouter, productsFlexRouter];
|
|
117
|
+
|
|
118
|
+
apiRouters.forEach(router => router.mount(app, '/api/v1'));
|
|
119
|
+
|
|
120
|
+
// Routes available:
|
|
121
|
+
// - /api/v1/users
|
|
122
|
+
// - /api/v1/products
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## API
|
|
126
|
+
|
|
127
|
+
### Constructor
|
|
128
|
+
|
|
129
|
+
**`new FlexRouter(context, router, handlers?)`**
|
|
130
|
+
|
|
131
|
+
Creates a new FlexRouter instance.
|
|
132
|
+
|
|
133
|
+
**Parameters:**
|
|
134
|
+
- `context` (string) - The context path for the router (e.g., `/api/v1`)
|
|
135
|
+
- `router` (Router) - Express Router instance containing your route definitions
|
|
136
|
+
- `handlers` (Array, optional) - Array of middleware handler functions to apply to all routes in this router
|
|
137
|
+
|
|
138
|
+
**Returns:** FlexRouter instance
|
|
139
|
+
|
|
140
|
+
### Methods
|
|
141
|
+
|
|
142
|
+
**`mount(app, basePath)`**
|
|
143
|
+
|
|
144
|
+
Mounts the router to an Express application with the specified base path.
|
|
145
|
+
|
|
146
|
+
**Parameters:**
|
|
147
|
+
- `app` (Express) - Express application instance
|
|
148
|
+
- `basePath` (string) - Base path to prepend to the context path
|
|
149
|
+
|
|
150
|
+
**Example:**
|
|
151
|
+
```javascript
|
|
152
|
+
const flexRouter = new FlexRouter('/api', router);
|
|
153
|
+
flexRouter.mount(app, '/v1'); // Mounts at /v1/api
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Best Practices
|
|
157
|
+
|
|
158
|
+
1. **Group Related Routes**: Use FlexRouter to group related routes together
|
|
159
|
+
2. **Apply Middleware Strategically**: Apply middleware at the FlexRouter level for route groups that share the same requirements
|
|
160
|
+
3. **Consistent Naming**: Use consistent naming conventions for context paths (e.g., all lowercase, kebab-case)
|
|
161
|
+
4. **Version Your APIs**: Use FlexRouter to manage different API versions easily
|
|
162
|
+
5. **Keep Routers Focused**: Each router should handle a specific feature or resource type
|
|
163
|
+
|
|
164
|
+
## Related Documentation
|
|
165
|
+
|
|
166
|
+
- [SessionManager](./session-manager.md) - For authentication middleware usage
|
|
167
|
+
- [Back to main documentation](../README.md)
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# HTTP Handlers
|
|
2
|
+
|
|
3
|
+
Custom error handling utilities with standardized HTTP status codes and error responses for Express.js applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The HTTP Handlers module provides:
|
|
8
|
+
- Standardized error handling middleware
|
|
9
|
+
- Custom error classes
|
|
10
|
+
- HTTP status codes and messages constants
|
|
11
|
+
- 404 handler for unmatched routes
|
|
12
|
+
- Utility functions for error formatting
|
|
13
|
+
- Axios error handling helpers
|
|
14
|
+
|
|
15
|
+
## Available Exports
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import {
|
|
19
|
+
httpCodes, // HTTP status code constants
|
|
20
|
+
httpMessages, // HTTP status message constants
|
|
21
|
+
httpErrorHandler, // Error handling middleware
|
|
22
|
+
httpNotFoundHandler, // 404 handler middleware
|
|
23
|
+
CustomError, // Custom error class
|
|
24
|
+
httpHelper, // Utility functions
|
|
25
|
+
httpError // Error factory function
|
|
26
|
+
} from '@igxjs/node-components';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import express from 'express';
|
|
33
|
+
import {
|
|
34
|
+
httpCodes,
|
|
35
|
+
httpErrorHandler,
|
|
36
|
+
httpNotFoundHandler,
|
|
37
|
+
httpError
|
|
38
|
+
} from '@igxjs/node-components';
|
|
39
|
+
|
|
40
|
+
const app = express();
|
|
41
|
+
|
|
42
|
+
// Your routes
|
|
43
|
+
app.get('/api/data', async (req, res, next) => {
|
|
44
|
+
try {
|
|
45
|
+
const data = await fetchData();
|
|
46
|
+
res.json(data);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
next(httpError(httpCodes.SYSTEM_FAILURE, 'Failed to fetch data', error));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Add 404 handler before error handler
|
|
53
|
+
app.use(httpNotFoundHandler);
|
|
54
|
+
|
|
55
|
+
// Add error handler as the last middleware
|
|
56
|
+
app.use(httpErrorHandler);
|
|
57
|
+
|
|
58
|
+
app.listen(3000);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## HTTP Status Codes
|
|
62
|
+
|
|
63
|
+
The `httpCodes` object provides constants for common HTTP status codes:
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
import { httpCodes } from '@igxjs/node-components';
|
|
67
|
+
|
|
68
|
+
// Success codes
|
|
69
|
+
httpCodes.OK // 200
|
|
70
|
+
httpCodes.CREATED // 201
|
|
71
|
+
httpCodes.NO_CONTENT // 204
|
|
72
|
+
|
|
73
|
+
// Client error codes
|
|
74
|
+
httpCodes.BAD_REQUEST // 400
|
|
75
|
+
httpCodes.UNAUTHORIZED // 401
|
|
76
|
+
httpCodes.FORBIDDEN // 403
|
|
77
|
+
httpCodes.NOT_FOUND // 404
|
|
78
|
+
httpCodes.NOT_ACCEPTABLE // 406
|
|
79
|
+
httpCodes.CONFLICT // 409
|
|
80
|
+
httpCodes.LOCKED // 423
|
|
81
|
+
|
|
82
|
+
// Server error codes
|
|
83
|
+
httpCodes.SYSTEM_FAILURE // 500
|
|
84
|
+
httpCodes.NOT_IMPLEMENTED // 501
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## HTTP Status Messages
|
|
88
|
+
|
|
89
|
+
Corresponding status messages are available via `httpMessages`:
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
import { httpMessages } from '@igxjs/node-components';
|
|
93
|
+
|
|
94
|
+
httpMessages.OK // 'OK'
|
|
95
|
+
httpMessages.BAD_REQUEST // 'Bad Request'
|
|
96
|
+
httpMessages.UNAUTHORIZED // 'Unauthorized'
|
|
97
|
+
// ... etc.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## CustomError Class
|
|
101
|
+
|
|
102
|
+
Create custom errors with specific HTTP status codes:
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
import { CustomError, httpCodes } from '@igxjs/node-components';
|
|
106
|
+
|
|
107
|
+
// Constructor: new CustomError(code, message, error?, data?)
|
|
108
|
+
throw new CustomError(
|
|
109
|
+
httpCodes.BAD_REQUEST,
|
|
110
|
+
'Email is required',
|
|
111
|
+
null,
|
|
112
|
+
{ field: 'email' }
|
|
113
|
+
);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Properties:**
|
|
117
|
+
- `code` (number) - HTTP status code
|
|
118
|
+
- `message` (string) - Error message
|
|
119
|
+
- `error` (object, optional) - Original error object
|
|
120
|
+
- `data` (object, optional) - Additional error data
|
|
121
|
+
|
|
122
|
+
## httpError Function
|
|
123
|
+
|
|
124
|
+
Convenience function to create CustomError instances:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { httpError, httpCodes } from '@igxjs/node-components';
|
|
128
|
+
|
|
129
|
+
// Same as: new CustomError(code, message, error, data)
|
|
130
|
+
throw httpError(
|
|
131
|
+
httpCodes.UNAUTHORIZED,
|
|
132
|
+
'Invalid credentials',
|
|
133
|
+
originalError,
|
|
134
|
+
{ attempted: username }
|
|
135
|
+
);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Middleware
|
|
139
|
+
|
|
140
|
+
### httpErrorHandler
|
|
141
|
+
|
|
142
|
+
Express error handling middleware that processes CustomError and other errors:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
import { httpErrorHandler } from '@igxjs/node-components';
|
|
146
|
+
|
|
147
|
+
// Add as the last middleware
|
|
148
|
+
app.use(httpErrorHandler);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Features:**
|
|
152
|
+
- Automatically handles `CustomError` instances
|
|
153
|
+
- Sets appropriate HTTP status codes
|
|
154
|
+
- Adds CORS headers
|
|
155
|
+
- Logs error details to console
|
|
156
|
+
- Returns standardized JSON error responses
|
|
157
|
+
|
|
158
|
+
**Response Format:**
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"error": {
|
|
162
|
+
"code": 400,
|
|
163
|
+
"message": "Email is required",
|
|
164
|
+
"data": { "field": "email" }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### httpNotFoundHandler
|
|
170
|
+
|
|
171
|
+
Middleware that catches all unmatched routes and returns 404:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
import { httpNotFoundHandler } from '@igxjs/node-components';
|
|
175
|
+
|
|
176
|
+
// Add before error handler
|
|
177
|
+
app.use(httpNotFoundHandler);
|
|
178
|
+
app.use(httpErrorHandler);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## httpHelper Utilities
|
|
182
|
+
|
|
183
|
+
### `handleAxiosError(error, defaultMessage?)`
|
|
184
|
+
|
|
185
|
+
Analyze and convert Axios/HTTP errors to CustomError:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
import axios from 'axios';
|
|
189
|
+
import { httpHelper } from '@igxjs/node-components';
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const response = await axios.get('https://api.example.com/data');
|
|
193
|
+
return response.data;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// Converts Axios error to CustomError with extracted status and message
|
|
196
|
+
throw httpHelper.handleAxiosError(error, 'API request failed');
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### `format(str, ...args)`
|
|
201
|
+
|
|
202
|
+
Format strings with placeholders:
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
import { httpHelper } from '@igxjs/node-components';
|
|
206
|
+
|
|
207
|
+
const message = httpHelper.format(
|
|
208
|
+
'User {0} not found in {1}',
|
|
209
|
+
'john@example.com',
|
|
210
|
+
'database'
|
|
211
|
+
);
|
|
212
|
+
// Result: 'User john@example.com not found in database'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `toZodMessage(error)`
|
|
216
|
+
|
|
217
|
+
Generate friendly Zod validation error messages:
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
import { z } from 'zod';
|
|
221
|
+
import { httpHelper, httpError, httpCodes } from '@igxjs/node-components';
|
|
222
|
+
|
|
223
|
+
const userSchema = z.object({
|
|
224
|
+
email: z.string().email(),
|
|
225
|
+
age: z.number().min(18)
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
app.post('/api/users', (req, res, next) => {
|
|
229
|
+
try {
|
|
230
|
+
const validated = userSchema.parse(req.body);
|
|
231
|
+
// Process validated data
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error instanceof z.ZodError) {
|
|
234
|
+
const message = httpHelper.toZodMessage(error);
|
|
235
|
+
throw httpError(httpCodes.BAD_REQUEST, message, error);
|
|
236
|
+
}
|
|
237
|
+
next(error);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Complete Example
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
import express from 'express';
|
|
246
|
+
import {
|
|
247
|
+
httpCodes,
|
|
248
|
+
httpMessages,
|
|
249
|
+
httpError,
|
|
250
|
+
httpErrorHandler,
|
|
251
|
+
httpNotFoundHandler,
|
|
252
|
+
CustomError
|
|
253
|
+
} from '@igxjs/node-components';
|
|
254
|
+
|
|
255
|
+
const app = express();
|
|
256
|
+
app.use(express.json());
|
|
257
|
+
|
|
258
|
+
// Routes
|
|
259
|
+
app.get('/api/health', (req, res) => {
|
|
260
|
+
res.json({ status: httpMessages.OK });
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
app.post('/api/login', async (req, res, next) => {
|
|
264
|
+
try {
|
|
265
|
+
const { username, password } = req.body;
|
|
266
|
+
|
|
267
|
+
if (!username || !password) {
|
|
268
|
+
throw httpError(
|
|
269
|
+
httpCodes.BAD_REQUEST,
|
|
270
|
+
'Username and password are required'
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const user = await authenticate(username, password);
|
|
275
|
+
|
|
276
|
+
if (!user) {
|
|
277
|
+
throw new CustomError(
|
|
278
|
+
httpCodes.UNAUTHORIZED,
|
|
279
|
+
'Invalid credentials'
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
res.json({ user });
|
|
284
|
+
} catch (error) {
|
|
285
|
+
next(error);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// 404 handler
|
|
290
|
+
app.use(httpNotFoundHandler);
|
|
291
|
+
|
|
292
|
+
// Error handler (must be last)
|
|
293
|
+
app.use(httpErrorHandler);
|
|
294
|
+
|
|
295
|
+
app.listen(3000);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Related Documentation
|
|
299
|
+
|
|
300
|
+
- [JWT Manager](./jwt-manager.md) - For token-based authentication
|
|
301
|
+
- [SessionManager](./session-manager.md) - For session-based authentication
|
|
302
|
+
- [Back to main documentation](../README.md)
|