navis.js 5.0.0 → 5.2.1
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 +23 -2
- package/examples/v5.1-features-demo.js +192 -0
- package/examples/v5.2-features-demo.js +153 -0
- package/package.json +1 -1
- package/src/core/versioning.js +124 -0
- package/src/db/db-pool.js +195 -0
- package/src/docs/swagger.js +188 -0
- package/src/index.js +30 -0
- package/src/middleware/upload.js +151 -0
- package/src/sse/server-sent-events.js +171 -0
- package/src/testing/test-helper.js +167 -0
- package/src/websocket/websocket-server.js +301 -0
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ navis metrics
|
|
|
129
129
|
- ✅ **Rate limiting** - In-memory rate limiting with configurable windows
|
|
130
130
|
- ✅ **Enhanced error handling** - Custom error classes and error handler middleware
|
|
131
131
|
|
|
132
|
-
### v5
|
|
132
|
+
### v5
|
|
133
133
|
|
|
134
134
|
- ✅ **Caching layer** - In-memory cache with TTL and Redis adapter
|
|
135
135
|
- ✅ **CORS support** - Cross-Origin Resource Sharing middleware
|
|
@@ -138,6 +138,19 @@ navis metrics
|
|
|
138
138
|
- ✅ **Health checks** - Liveness and readiness probes
|
|
139
139
|
- ✅ **Graceful shutdown** - Clean shutdown handling
|
|
140
140
|
|
|
141
|
+
### v5.1 (Current)
|
|
142
|
+
|
|
143
|
+
- ✅ **OpenAPI/Swagger** - Auto-generate API documentation
|
|
144
|
+
- ✅ **API versioning** - URL-based and header-based versioning
|
|
145
|
+
- ✅ **File upload** - Multipart form data handling
|
|
146
|
+
- ✅ **Testing utilities** - Test helpers for applications
|
|
147
|
+
|
|
148
|
+
### v5.2 (Current)
|
|
149
|
+
|
|
150
|
+
- ✅ **WebSocket support** - Real-time bidirectional communication
|
|
151
|
+
- ✅ **Server-Sent Events** - One-way real-time streaming
|
|
152
|
+
- ✅ **Database integration** - Connection pooling for PostgreSQL, MySQL, MongoDB
|
|
153
|
+
|
|
141
154
|
## API Reference
|
|
142
155
|
|
|
143
156
|
### NavisApp
|
|
@@ -342,15 +355,23 @@ Advanced features: async messaging (SQS/Kafka/NATS), observability, enhanced CLI
|
|
|
342
355
|
### v4 ✅
|
|
343
356
|
Production-ready: advanced routing, validation, authentication, rate limiting, error handling
|
|
344
357
|
|
|
345
|
-
### v5 ✅
|
|
358
|
+
### v5 ✅
|
|
346
359
|
Enterprise-grade: caching, CORS, security headers, compression, health checks, graceful shutdown
|
|
347
360
|
|
|
361
|
+
### v5.1 ✅ (Current)
|
|
362
|
+
Developer experience: OpenAPI/Swagger, API versioning, file upload, testing utilities
|
|
363
|
+
|
|
364
|
+
### v5.2 ✅ (Current)
|
|
365
|
+
Real-time features: WebSocket, Server-Sent Events, database integration
|
|
366
|
+
|
|
348
367
|
## Documentation
|
|
349
368
|
|
|
350
369
|
- [V2 Features Guide](./V2_FEATURES.md) - Complete v2 features documentation
|
|
351
370
|
- [V3 Features Guide](./V3_FEATURES.md) - Complete v3 features documentation
|
|
352
371
|
- [V4 Features Guide](./V4_FEATURES.md) - Complete v4 features documentation
|
|
353
372
|
- [V5 Features Guide](./V5_FEATURES.md) - Complete v5 features documentation
|
|
373
|
+
- [V5.1 Features Guide](./V5.1_FEATURES.md) - Complete v5.1 features documentation
|
|
374
|
+
- [V5.2 Features Guide](./V5.2_FEATURES.md) - Complete v5.2 features documentation
|
|
354
375
|
- [Lambda Optimization Guide](./LAMBDA_OPTIMIZATION.md) - Lambda cold start optimization guide (v3.1)
|
|
355
376
|
- [Verification Guide v2](./VERIFY_V2.md) - How to verify v2 features
|
|
356
377
|
- [Verification Guide v3](./VERIFY_V3.md) - How to verify v3 features
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navis.js v5.1 Features Demo
|
|
3
|
+
* Demonstrates OpenAPI/Swagger, API versioning, file upload, and testing utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
NavisApp,
|
|
8
|
+
response,
|
|
9
|
+
swagger,
|
|
10
|
+
createVersionManager,
|
|
11
|
+
headerVersioning,
|
|
12
|
+
upload,
|
|
13
|
+
testApp,
|
|
14
|
+
} = require('../src/index');
|
|
15
|
+
|
|
16
|
+
const app = new NavisApp();
|
|
17
|
+
|
|
18
|
+
// ============================================
|
|
19
|
+
// OpenAPI/Swagger Documentation
|
|
20
|
+
// ============================================
|
|
21
|
+
const swaggerMiddleware = swagger({
|
|
22
|
+
title: 'Navis.js API',
|
|
23
|
+
version: '5.1.0',
|
|
24
|
+
description: 'API documentation for Navis.js',
|
|
25
|
+
path: '/swagger.json',
|
|
26
|
+
uiPath: '/docs',
|
|
27
|
+
servers: [{ url: 'http://localhost:3000', description: 'Development server' }],
|
|
28
|
+
tags: [
|
|
29
|
+
{ name: 'users', description: 'User operations' },
|
|
30
|
+
{ name: 'posts', description: 'Post operations' },
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
app.use(swaggerMiddleware.middleware);
|
|
35
|
+
|
|
36
|
+
// Add routes to Swagger
|
|
37
|
+
swaggerMiddleware.generator.addRoute('GET', '/users/:id', {
|
|
38
|
+
summary: 'Get user by ID',
|
|
39
|
+
description: 'Retrieve a user by their ID',
|
|
40
|
+
tags: ['users'],
|
|
41
|
+
parameters: [
|
|
42
|
+
{
|
|
43
|
+
name: 'id',
|
|
44
|
+
in: 'path',
|
|
45
|
+
required: true,
|
|
46
|
+
schema: { type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
responses: {
|
|
50
|
+
'200': {
|
|
51
|
+
description: 'User found',
|
|
52
|
+
content: {
|
|
53
|
+
'application/json': {
|
|
54
|
+
schema: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
id: { type: 'string' },
|
|
58
|
+
name: { type: 'string' },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
'404': { description: 'User not found' },
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ============================================
|
|
69
|
+
// API Versioning
|
|
70
|
+
// ============================================
|
|
71
|
+
const versionManager = createVersionManager();
|
|
72
|
+
|
|
73
|
+
// Version 1
|
|
74
|
+
const v1 = versionManager.version('v1');
|
|
75
|
+
v1.get('/users/:id', (req, res) => {
|
|
76
|
+
response.success(res, {
|
|
77
|
+
version: 'v1',
|
|
78
|
+
userId: req.params.id,
|
|
79
|
+
format: 'legacy',
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Version 2
|
|
84
|
+
const v2 = versionManager.version('v2');
|
|
85
|
+
v2.get('/users/:id', (req, res) => {
|
|
86
|
+
response.success(res, {
|
|
87
|
+
version: 'v2',
|
|
88
|
+
userId: req.params.id,
|
|
89
|
+
format: 'modern',
|
|
90
|
+
metadata: { source: 'v2-api' },
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Register versioned routes
|
|
95
|
+
v1.get('/users/:id', (req, res) => {
|
|
96
|
+
response.success(res, { version: 'v1', userId: req.params.id });
|
|
97
|
+
});
|
|
98
|
+
v2.get('/users/:id', (req, res) => {
|
|
99
|
+
response.success(res, { version: 'v2', userId: req.params.id });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Apply versioned routes to app
|
|
103
|
+
for (const version of versionManager.getVersions()) {
|
|
104
|
+
const routes = versionManager.getRoutes(version);
|
|
105
|
+
for (const method in routes) {
|
|
106
|
+
for (const route of routes[method]) {
|
|
107
|
+
app[method.toLowerCase()](route.path, route.handler);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Header-based versioning
|
|
113
|
+
app.use(headerVersioning({
|
|
114
|
+
header: 'X-API-Version',
|
|
115
|
+
defaultVersion: 'v1',
|
|
116
|
+
}));
|
|
117
|
+
|
|
118
|
+
// ============================================
|
|
119
|
+
// File Upload
|
|
120
|
+
// ============================================
|
|
121
|
+
app.post('/upload', upload({
|
|
122
|
+
dest: './uploads',
|
|
123
|
+
limits: {
|
|
124
|
+
fileSize: 5 * 1024 * 1024, // 5MB
|
|
125
|
+
files: 5,
|
|
126
|
+
},
|
|
127
|
+
fileFilter: (file) => {
|
|
128
|
+
// Allow images and PDFs
|
|
129
|
+
return file.mimetype.startsWith('image/') || file.mimetype === 'application/pdf';
|
|
130
|
+
},
|
|
131
|
+
}), (req, res) => {
|
|
132
|
+
response.success(res, {
|
|
133
|
+
message: 'Files uploaded',
|
|
134
|
+
files: req.files || [],
|
|
135
|
+
fields: req.body,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ============================================
|
|
140
|
+
// Routes
|
|
141
|
+
// ============================================
|
|
142
|
+
app.get('/', (req, res) => {
|
|
143
|
+
response.success(res, {
|
|
144
|
+
message: 'Navis.js v5.1 Features Demo',
|
|
145
|
+
features: [
|
|
146
|
+
'OpenAPI/Swagger Documentation',
|
|
147
|
+
'API Versioning',
|
|
148
|
+
'File Upload',
|
|
149
|
+
'Testing Utilities',
|
|
150
|
+
],
|
|
151
|
+
endpoints: {
|
|
152
|
+
swagger: '/swagger.json',
|
|
153
|
+
docs: '/docs',
|
|
154
|
+
v1: '/v1/users/:id',
|
|
155
|
+
v2: '/v2/users/:id',
|
|
156
|
+
upload: 'POST /upload',
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
app.get('/users/:id', (req, res) => {
|
|
162
|
+
response.success(res, {
|
|
163
|
+
userId: req.params.id,
|
|
164
|
+
version: req.apiVersion || 'default',
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// ============================================
|
|
169
|
+
// Start Server
|
|
170
|
+
// ============================================
|
|
171
|
+
const PORT = 3000;
|
|
172
|
+
app.listen(PORT, () => {
|
|
173
|
+
console.log(`\n🚀 Navis.js v5.1 Features Demo Server`);
|
|
174
|
+
console.log(`📡 Listening on http://localhost:${PORT}\n`);
|
|
175
|
+
console.log('Available endpoints:');
|
|
176
|
+
console.log(' GET /');
|
|
177
|
+
console.log(' GET /swagger.json (OpenAPI spec)');
|
|
178
|
+
console.log(' GET /docs (Swagger UI)');
|
|
179
|
+
console.log(' GET /v1/users/:id (API v1)');
|
|
180
|
+
console.log(' GET /v2/users/:id (API v2)');
|
|
181
|
+
console.log(' GET /users/:id (with X-API-Version header)');
|
|
182
|
+
console.log(' POST /upload (file upload)');
|
|
183
|
+
console.log('\n💡 Test with:');
|
|
184
|
+
console.log(' curl http://localhost:3000/');
|
|
185
|
+
console.log(' curl http://localhost:3000/v1/users/123');
|
|
186
|
+
console.log(' curl http://localhost:3000/v2/users/123');
|
|
187
|
+
console.log(' curl -H "X-API-Version: v2" http://localhost:3000/users/123');
|
|
188
|
+
console.log(' curl http://localhost:3000/swagger.json');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
module.exports = app;
|
|
192
|
+
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navis.js v5.2 Features Demo
|
|
3
|
+
* Demonstrates WebSocket, Server-Sent Events, and database integration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
NavisApp,
|
|
8
|
+
response,
|
|
9
|
+
WebSocketServer,
|
|
10
|
+
sse,
|
|
11
|
+
createPool,
|
|
12
|
+
} = require('../src/index');
|
|
13
|
+
|
|
14
|
+
const app = new NavisApp();
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// Server-Sent Events (SSE)
|
|
18
|
+
// ============================================
|
|
19
|
+
app.get('/events', sse(), (req, res) => {
|
|
20
|
+
// Send initial event
|
|
21
|
+
res.sse.send({ message: 'Connected to SSE stream' }, 'connection');
|
|
22
|
+
|
|
23
|
+
// Send periodic updates
|
|
24
|
+
let count = 0;
|
|
25
|
+
const interval = setInterval(() => {
|
|
26
|
+
count++;
|
|
27
|
+
res.sse.send({
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
count,
|
|
30
|
+
data: `Event ${count}`,
|
|
31
|
+
}, 'update');
|
|
32
|
+
|
|
33
|
+
// Close after 10 events
|
|
34
|
+
if (count >= 10) {
|
|
35
|
+
clearInterval(interval);
|
|
36
|
+
res.sse.send({ message: 'Stream ended' }, 'close');
|
|
37
|
+
setTimeout(() => res.sse.close(), 1000);
|
|
38
|
+
}
|
|
39
|
+
}, 1000);
|
|
40
|
+
|
|
41
|
+
// Cleanup on disconnect
|
|
42
|
+
req.on('close', () => {
|
|
43
|
+
clearInterval(interval);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// ============================================
|
|
48
|
+
// Database Integration (Example)
|
|
49
|
+
// ============================================
|
|
50
|
+
// Note: Requires database packages (pg, mysql2, or mongodb)
|
|
51
|
+
let dbPool = null;
|
|
52
|
+
|
|
53
|
+
// Initialize database pool (commented out - requires actual DB)
|
|
54
|
+
// dbPool = createPool({
|
|
55
|
+
// type: 'postgres',
|
|
56
|
+
// connectionString: process.env.DATABASE_URL,
|
|
57
|
+
// });
|
|
58
|
+
|
|
59
|
+
// Example route using database
|
|
60
|
+
app.get('/db-example', async (req, res) => {
|
|
61
|
+
if (!dbPool) {
|
|
62
|
+
response.success(res, {
|
|
63
|
+
message: 'Database not configured',
|
|
64
|
+
note: 'Set DATABASE_URL and install database package (pg, mysql2, or mongodb)',
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
// Example query
|
|
71
|
+
const result = await dbPool.query('SELECT NOW() as current_time');
|
|
72
|
+
response.success(res, result);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
response.error(res, error.message, 500);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// Routes
|
|
80
|
+
// ============================================
|
|
81
|
+
app.get('/', (req, res) => {
|
|
82
|
+
response.success(res, {
|
|
83
|
+
message: 'Navis.js v5.2 Features Demo',
|
|
84
|
+
features: [
|
|
85
|
+
'WebSocket Support',
|
|
86
|
+
'Server-Sent Events (SSE)',
|
|
87
|
+
'Database Integration',
|
|
88
|
+
],
|
|
89
|
+
endpoints: {
|
|
90
|
+
sse: 'GET /events (SSE stream)',
|
|
91
|
+
websocket: 'WS /ws (WebSocket)',
|
|
92
|
+
db: 'GET /db-example',
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ============================================
|
|
98
|
+
// Start Server
|
|
99
|
+
// ============================================
|
|
100
|
+
const PORT = 3000;
|
|
101
|
+
const server = app.listen(PORT, () => {
|
|
102
|
+
console.log(`\n🚀 Navis.js v5.2 Features Demo Server`);
|
|
103
|
+
console.log(`📡 Listening on http://localhost:${PORT}\n`);
|
|
104
|
+
console.log('Available endpoints:');
|
|
105
|
+
console.log(' GET /');
|
|
106
|
+
console.log(' GET /events (SSE stream)');
|
|
107
|
+
console.log(' WS /ws (WebSocket)');
|
|
108
|
+
console.log(' GET /db-example');
|
|
109
|
+
console.log('\n💡 Test with:');
|
|
110
|
+
console.log(' curl http://localhost:3000/');
|
|
111
|
+
console.log(' curl -N http://localhost:3000/events');
|
|
112
|
+
console.log(' wscat -c ws://localhost:3000/ws');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// WebSocket Server
|
|
117
|
+
// ============================================
|
|
118
|
+
const wsServer = new WebSocketServer({
|
|
119
|
+
path: '/ws',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
wsServer.attach(server);
|
|
123
|
+
|
|
124
|
+
wsServer.onConnection((client) => {
|
|
125
|
+
console.log(`WebSocket client connected: ${client.id}`);
|
|
126
|
+
client.send({ type: 'welcome', message: 'Connected to WebSocket server' });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
wsServer.on('*', (message, client) => {
|
|
130
|
+
console.log(`Message from ${client.id}:`, message);
|
|
131
|
+
|
|
132
|
+
// Echo message back
|
|
133
|
+
client.send({
|
|
134
|
+
type: 'echo',
|
|
135
|
+
original: message,
|
|
136
|
+
timestamp: new Date().toISOString(),
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
wsServer.onDisconnection((client) => {
|
|
141
|
+
console.log(`WebSocket client disconnected: ${client.id}`);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Cleanup on shutdown
|
|
145
|
+
process.on('SIGTERM', async () => {
|
|
146
|
+
if (dbPool) {
|
|
147
|
+
await dbPool.close();
|
|
148
|
+
}
|
|
149
|
+
process.exit(0);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
module.exports = app;
|
|
153
|
+
|
package/package.json
CHANGED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Versioning
|
|
3
|
+
* v5.1: URL-based and header-based API versioning
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class VersionManager {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.versions = new Map();
|
|
9
|
+
this.defaultVersion = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a version router
|
|
14
|
+
* @param {string} version - Version identifier (e.g., 'v1', 'v2')
|
|
15
|
+
* @returns {Object} - Version router with route methods
|
|
16
|
+
*/
|
|
17
|
+
version(version) {
|
|
18
|
+
if (!this.versions.has(version)) {
|
|
19
|
+
const router = {
|
|
20
|
+
version,
|
|
21
|
+
routes: {
|
|
22
|
+
GET: [],
|
|
23
|
+
POST: [],
|
|
24
|
+
PUT: [],
|
|
25
|
+
DELETE: [],
|
|
26
|
+
PATCH: [],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
this.versions.set(version, router);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const router = this.versions.get(version);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
get: (path, handler) => this._register(router, 'GET', path, handler),
|
|
36
|
+
post: (path, handler) => this._register(router, 'POST', path, handler),
|
|
37
|
+
put: (path, handler) => this._register(router, 'PUT', path, handler),
|
|
38
|
+
delete: (path, handler) => this._register(router, 'DELETE', path, handler),
|
|
39
|
+
patch: (path, handler) => this._register(router, 'PATCH', path, handler),
|
|
40
|
+
use: (middleware) => {
|
|
41
|
+
if (!router.middlewares) {
|
|
42
|
+
router.middlewares = [];
|
|
43
|
+
}
|
|
44
|
+
router.middlewares.push(middleware);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Register a route for a version
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
_register(router, method, path, handler) {
|
|
54
|
+
const versionedPath = `/${router.version}${path}`;
|
|
55
|
+
router.routes[method].push({
|
|
56
|
+
path: versionedPath,
|
|
57
|
+
originalPath: path,
|
|
58
|
+
handler,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Set default version
|
|
64
|
+
* @param {string} version - Default version
|
|
65
|
+
*/
|
|
66
|
+
setDefaultVersion(version) {
|
|
67
|
+
this.defaultVersion = version;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get routes for a version
|
|
72
|
+
* @param {string} version - Version identifier
|
|
73
|
+
* @returns {Object} - Routes for the version
|
|
74
|
+
*/
|
|
75
|
+
getRoutes(version) {
|
|
76
|
+
const router = this.versions.get(version);
|
|
77
|
+
return router ? router.routes : null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get all versions
|
|
82
|
+
* @returns {Array} - Array of version identifiers
|
|
83
|
+
*/
|
|
84
|
+
getVersions() {
|
|
85
|
+
return Array.from(this.versions.keys());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Create version manager
|
|
91
|
+
* @returns {VersionManager} - Version manager instance
|
|
92
|
+
*/
|
|
93
|
+
function createVersionManager() {
|
|
94
|
+
return new VersionManager();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Header-based versioning middleware
|
|
99
|
+
* @param {Object} options - Versioning options
|
|
100
|
+
* @returns {Function} - Middleware function
|
|
101
|
+
*/
|
|
102
|
+
function headerVersioning(options = {}) {
|
|
103
|
+
const {
|
|
104
|
+
header = 'X-API-Version',
|
|
105
|
+
defaultVersion = null,
|
|
106
|
+
} = options;
|
|
107
|
+
|
|
108
|
+
return async (req, res, next) => {
|
|
109
|
+
const version = req.headers[header] || req.headers[header.toLowerCase()] || defaultVersion;
|
|
110
|
+
|
|
111
|
+
if (version) {
|
|
112
|
+
req.apiVersion = version;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
next();
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
VersionManager,
|
|
121
|
+
createVersionManager,
|
|
122
|
+
headerVersioning,
|
|
123
|
+
};
|
|
124
|
+
|