aetherjs-router 1.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.
@@ -0,0 +1,796 @@
1
+ // examples/basic-router.js - Comprehensive example demonstrating all router features
2
+ import { createAetherRouteFactory } from '../aether-adapter.js';
3
+
4
+ // Create router factory with enhanced features enabled
5
+ const routerFactory = createAetherRouteFactory({
6
+ prefix: '/api',
7
+ cacheSize: 2000,
8
+ parseQuery: true, // Enable query parameter pattern matching
9
+ autoParseQuery: true, // Automatically parse query parameters
10
+ enableVersioning: true // Enable versioning support
11
+ });
12
+
13
+ // ============================================
14
+ // 1. BASIC ROUTE DEFINITIONS
15
+ // ============================================
16
+
17
+ // Add global middleware for logging
18
+ routerFactory.use(async (ctx, next) => {
19
+ console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.url}`);
20
+ const startTime = Date.now();
21
+ await next();
22
+ const duration = Date.now() - startTime;
23
+ console.log(`Request completed in ${duration}ms`);
24
+ });
25
+
26
+ // Basic health check endpoint
27
+ routerFactory.get('/health', (ctx) => {
28
+ ctx.setStatus(200);
29
+ ctx.json({
30
+ status: 'ok',
31
+ timestamp: Date.now(),
32
+ version: '1.0.0'
33
+ });
34
+ });
35
+
36
+ // ============================================
37
+ // 2. QUERY PARAMETER SUPPORT EXAMPLES
38
+ // ============================================
39
+
40
+ // Enable automatic query parameter parsing
41
+ routerFactory.use((ctx, next) => {
42
+ if (ctx.url && ctx.url.includes('?')) {
43
+ const [path, queryString] = ctx.url.split('?');
44
+ ctx.path = path;
45
+ ctx.query = Object.fromEntries(new URLSearchParams(queryString));
46
+ ctx.originalUrl = ctx.url;
47
+ } else {
48
+ ctx.query = {};
49
+ }
50
+ return next();
51
+ });
52
+
53
+ // Route with query parameters in pattern
54
+ routerFactory.get('/search?q=:query&page=:page?&limit=:limit?', (ctx) => {
55
+ const { query, page = '1', limit = '10' } = ctx.params;
56
+
57
+ ctx.setStatus(200);
58
+ ctx.json({
59
+ query,
60
+ page: parseInt(page),
61
+ limit: parseInt(limit),
62
+ results: [
63
+ { id: 1, title: `Result for: ${query}` },
64
+ { id: 2, title: `Another result for: ${query}` }
65
+ ],
66
+ total: 100,
67
+ currentPage: parseInt(page)
68
+ });
69
+ });
70
+
71
+ // Route with mixed path and query parameters
72
+ routerFactory.get('/users/:id?fields=:fields?&expand=:expand?', (ctx) => {
73
+ const { id, fields = 'id,name,email', expand = '' } = ctx.params;
74
+
75
+ ctx.setStatus(200);
76
+ ctx.json({
77
+ user: {
78
+ id,
79
+ name: `User ${id}`,
80
+ email: `user${id}@example.com`,
81
+ fields: fields.split(','),
82
+ expand: expand.split(',').filter(Boolean)
83
+ }
84
+ });
85
+ });
86
+
87
+ // Advanced query parameter example with validation
88
+ routerFactory.get('/products?category=:category&minPrice=:minPrice?&maxPrice=:maxPrice?&sort=:sort?', (ctx) => {
89
+ const { category, minPrice = '0', maxPrice = '1000000', sort = 'name' } = ctx.params;
90
+
91
+ // Validate parameters
92
+ const validSortFields = ['name', 'price', 'rating', 'date'];
93
+ if (!validSortFields.includes(sort)) {
94
+ ctx.setStatus(400);
95
+ ctx.json({ error: 'Invalid sort field' });
96
+ return;
97
+ }
98
+
99
+ ctx.setStatus(200);
100
+ ctx.json({
101
+ category,
102
+ filters: {
103
+ minPrice: parseFloat(minPrice),
104
+ maxPrice: parseFloat(maxPrice),
105
+ sort
106
+ },
107
+ products: [
108
+ { id: 1, name: 'Product A', price: 99.99, category },
109
+ { id: 2, name: 'Product B', price: 149.99, category }
110
+ ]
111
+ });
112
+ });
113
+
114
+ // ============================================
115
+ // 3. VERSIONING EXAMPLES
116
+ // ============================================
117
+
118
+ // Version 1 API routes
119
+ routerFactory.group('/v1', (v1) => {
120
+ // Add version-specific middleware
121
+ v1.use((ctx, next) => {
122
+ ctx.apiVersion = 'v1';
123
+ ctx.deprecated = false;
124
+ return next();
125
+ });
126
+
127
+ // Simple user endpoints for v1
128
+ v1.get('/users', (ctx) => {
129
+ ctx.setStatus(200);
130
+ ctx.json({
131
+ version: ctx.apiVersion,
132
+ users: [
133
+ { id: 1, name: 'Alice', email: 'alice@example.com' },
134
+ { id: 2, name: 'Bob', email: 'bob@example.com' }
135
+ ]
136
+ });
137
+ });
138
+
139
+ v1.get('/users/:id', (ctx) => {
140
+ ctx.setStatus(200);
141
+ ctx.json({
142
+ version: ctx.apiVersion,
143
+ user: {
144
+ id: ctx.params.id,
145
+ name: `User ${ctx.params.id}`,
146
+ email: `user${ctx.params.id}@example.com`
147
+ }
148
+ });
149
+ });
150
+
151
+ // Products with query parameters in v1
152
+ v1.get('/products?category=:category&page=:page?', (ctx) => {
153
+ ctx.setStatus(200);
154
+ ctx.json({
155
+ version: ctx.apiVersion,
156
+ category: ctx.params.category,
157
+ page: ctx.params.page || '1',
158
+ products: []
159
+ });
160
+ });
161
+ });
162
+
163
+ // Version 2 API routes with enhanced features
164
+ routerFactory.group('/v2', (v2) => {
165
+ // Add version-specific middleware
166
+ v2.use((ctx, next) => {
167
+ ctx.apiVersion = 'v2';
168
+ ctx.features = ['enhanced-security', 'rate-limiting', 'caching'];
169
+ return next();
170
+ });
171
+
172
+ // Enhanced user endpoints for v2
173
+ v2.get('/users', (ctx) => {
174
+ const { page = '1', limit = '20', sort = 'name' } = ctx.query;
175
+
176
+ ctx.setStatus(200);
177
+ ctx.json({
178
+ version: ctx.apiVersion,
179
+ features: ctx.features,
180
+ pagination: {
181
+ page: parseInt(page),
182
+ limit: parseInt(limit),
183
+ sort
184
+ },
185
+ users: [
186
+ {
187
+ id: 1,
188
+ name: 'Alice',
189
+ email: 'alice@example.com',
190
+ metadata: { createdAt: '2024-01-01', updatedAt: '2024-01-15' }
191
+ },
192
+ {
193
+ id: 2,
194
+ name: 'Bob',
195
+ email: 'bob@example.com',
196
+ metadata: { createdAt: '2024-01-02', updatedAt: '2024-01-16' }
197
+ }
198
+ ]
199
+ });
200
+ });
201
+
202
+ // Enhanced user detail with query parameters
203
+ v2.get('/users/:id?include=:include?&fields=:fields?', (ctx) => {
204
+ const { id, include = '', fields = '' } = ctx.params;
205
+
206
+ const userData = {
207
+ id,
208
+ name: `User ${id}`,
209
+ email: `user${id}@example.com`,
210
+ profile: {
211
+ bio: `Bio for user ${id}`,
212
+ avatar: `https://example.com/avatars/${id}.jpg`
213
+ }
214
+ };
215
+
216
+ // Handle include parameter
217
+ const includes = include.split(',').filter(Boolean);
218
+ if (includes.includes('posts')) {
219
+ userData.posts = [
220
+ { id: 101, title: 'First Post', content: 'Content here' },
221
+ { id: 102, title: 'Second Post', content: 'More content' }
222
+ ];
223
+ }
224
+
225
+ if (includes.includes('comments')) {
226
+ userData.comments = [
227
+ { id: 201, postId: 101, content: 'Great post!' }
228
+ ];
229
+ }
230
+
231
+ // Handle fields parameter
232
+ const requestedFields = fields.split(',').filter(Boolean);
233
+ if (requestedFields.length > 0) {
234
+ const filteredData = {};
235
+ requestedFields.forEach(field => {
236
+ if (userData[field] !== undefined) {
237
+ filteredData[field] = userData[field];
238
+ }
239
+ });
240
+ ctx.setStatus(200);
241
+ ctx.json({
242
+ version: ctx.apiVersion,
243
+ user: filteredData
244
+ });
245
+ } else {
246
+ ctx.setStatus(200);
247
+ ctx.json({
248
+ version: ctx.apiVersion,
249
+ user: userData
250
+ });
251
+ }
252
+ });
253
+
254
+ // Products with advanced filtering in v2
255
+ v2.get('/products?category=:category&minPrice=:minPrice?&maxPrice=:maxPrice?&sort=:sort?&page=:page?', (ctx) => {
256
+ const { category, minPrice = '0', maxPrice = '1000000', sort = 'name', page = '1' } = ctx.params;
257
+
258
+ ctx.setStatus(200);
259
+ ctx.json({
260
+ version: ctx.apiVersion,
261
+ filters: {
262
+ category,
263
+ priceRange: {
264
+ min: parseFloat(minPrice),
265
+ max: parseFloat(maxPrice)
266
+ },
267
+ sort,
268
+ page: parseInt(page)
269
+ },
270
+ products: [
271
+ {
272
+ id: 1,
273
+ name: 'Premium Product A',
274
+ price: 199.99,
275
+ category,
276
+ rating: 4.5,
277
+ tags: ['premium', 'featured']
278
+ },
279
+ {
280
+ id: 2,
281
+ name: 'Standard Product B',
282
+ price: 99.99,
283
+ category,
284
+ rating: 4.0,
285
+ tags: ['standard']
286
+ }
287
+ ],
288
+ metadata: {
289
+ total: 50,
290
+ page: parseInt(page),
291
+ pageSize: 20,
292
+ hasMore: parseInt(page) < 3
293
+ }
294
+ });
295
+ });
296
+ });
297
+
298
+ // ============================================
299
+ // 4. NESTED GROUPING EXAMPLES
300
+ // ============================================
301
+
302
+ // Admin routes with nested grouping
303
+ routerFactory.group('/admin', (admin) => {
304
+ // Admin authentication middleware
305
+ admin.use(async (ctx, next) => {
306
+ const token = ctx.headers['x-admin-token'];
307
+ if (!token || token !== 'admin-secret-token') {
308
+ ctx.setStatus(401);
309
+ ctx.json({
310
+ error: 'Admin access required',
311
+ message: 'Valid x-admin-token header is required'
312
+ });
313
+ return;
314
+ }
315
+ ctx.isAdmin = true;
316
+ await next();
317
+ });
318
+
319
+ // Admin dashboard
320
+ admin.get('/dashboard?view=:view?', (ctx) => {
321
+ const view = ctx.params.view || 'overview';
322
+
323
+ ctx.setStatus(200);
324
+ ctx.json({
325
+ view,
326
+ stats: {
327
+ totalUsers: 1500,
328
+ activeUsers: 1250,
329
+ revenue: 50000,
330
+ growth: 15.5
331
+ },
332
+ recentActivity: [
333
+ { id: 1, action: 'user.created', timestamp: '2024-01-15T10:30:00Z' },
334
+ { id: 2, action: 'order.completed', timestamp: '2024-01-15T10:25:00Z' }
335
+ ]
336
+ });
337
+ });
338
+
339
+ // Nested grouping for user management
340
+ admin.group('/users', (users) => {
341
+ // User list with query parameters
342
+ users.get('?status=:status?&role=:role?&page=:page?', (ctx) => {
343
+ const { status = 'active', role = 'all', page = '1' } = ctx.params;
344
+
345
+ ctx.setStatus(200);
346
+ ctx.json({
347
+ filters: { status, role, page: parseInt(page) },
348
+ users: [
349
+ { id: 1, name: 'Admin User', email: 'admin@example.com', role: 'admin', status: 'active' },
350
+ { id: 2, name: 'Moderator', email: 'mod@example.com', role: 'moderator', status: 'active' }
351
+ ],
352
+ pagination: {
353
+ total: 100,
354
+ page: parseInt(page),
355
+ pageSize: 20
356
+ }
357
+ });
358
+ });
359
+
360
+ // User detail with query parameters
361
+ users.get('/:id?include=:include?', (ctx) => {
362
+ const { id, include = '' } = ctx.params;
363
+ const includes = include.split(',').filter(Boolean);
364
+
365
+ const userDetail = {
366
+ id,
367
+ name: `Admin User ${id}`,
368
+ email: `admin${id}@example.com`,
369
+ role: 'admin',
370
+ status: 'active',
371
+ createdAt: '2024-01-01T00:00:00Z',
372
+ lastLogin: '2024-01-15T10:00:00Z'
373
+ };
374
+
375
+ if (includes.includes('permissions')) {
376
+ userDetail.permissions = ['read', 'write', 'delete', 'manage'];
377
+ }
378
+
379
+ if (includes.includes('activity')) {
380
+ userDetail.recentActivity = [
381
+ { action: 'login', timestamp: '2024-01-15T10:00:00Z' },
382
+ { action: 'settings.updated', timestamp: '2024-01-14T15:30:00Z' }
383
+ ];
384
+ }
385
+
386
+ ctx.setStatus(200);
387
+ ctx.json(userDetail);
388
+ });
389
+
390
+ // Create user
391
+ users.post('/', async (ctx) => {
392
+ const userData = ctx.body;
393
+
394
+ ctx.setStatus(201);
395
+ ctx.json({
396
+ message: 'User created successfully',
397
+ user: {
398
+ id: Date.now(),
399
+ ...userData,
400
+ createdAt: new Date().toISOString(),
401
+ createdBy: 'admin'
402
+ }
403
+ });
404
+ });
405
+
406
+ // Update user
407
+ users.put('/:id', async (ctx) => {
408
+ const { id } = ctx.params;
409
+ const updateData = ctx.body;
410
+
411
+ ctx.setStatus(200);
412
+ ctx.json({
413
+ message: 'User updated successfully',
414
+ user: {
415
+ id,
416
+ ...updateData,
417
+ updatedAt: new Date().toISOString(),
418
+ updatedBy: 'admin'
419
+ }
420
+ });
421
+ });
422
+
423
+ // Delete user
424
+ users.delete('/:id', (ctx) => {
425
+ const { id } = ctx.params;
426
+
427
+ ctx.setStatus(200);
428
+ ctx.json({
429
+ message: `User ${id} deleted successfully`,
430
+ deletedAt: new Date().toISOString()
431
+ });
432
+ });
433
+ });
434
+
435
+ // Nested grouping for product management
436
+ admin.group('/products', (products) => {
437
+ // Product list with advanced query parameters
438
+ products.get('?status=:status?&category=:category?&sort=:sort?&order=:order?', (ctx) => {
439
+ const {
440
+ status = 'active',
441
+ category = 'all',
442
+ sort = 'createdAt',
443
+ order = 'desc'
444
+ } = ctx.params;
445
+
446
+ ctx.setStatus(200);
447
+ ctx.json({
448
+ filters: { status, category, sort, order },
449
+ products: [
450
+ {
451
+ id: 1,
452
+ name: 'Premium Product',
453
+ category: 'electronics',
454
+ status: 'active',
455
+ price: 299.99,
456
+ stock: 50,
457
+ createdAt: '2024-01-10T00:00:00Z'
458
+ }
459
+ ],
460
+ total: 1
461
+ });
462
+ });
463
+
464
+ // Create product
465
+ products.post('/', async (ctx) => {
466
+ const productData = ctx.body;
467
+
468
+ ctx.setStatus(201);
469
+ ctx.json({
470
+ message: 'Product created successfully',
471
+ product: {
472
+ id: Date.now(),
473
+ ...productData,
474
+ createdAt: new Date().toISOString(),
475
+ createdBy: 'admin'
476
+ }
477
+ });
478
+ });
479
+ });
480
+ });
481
+
482
+ // ============================================
483
+ // 5. RESTFUL RESOURCE EXAMPLES
484
+ // ============================================
485
+
486
+ // Articles resource with query parameter support
487
+ routerFactory.group('/articles', (articles) => {
488
+ // GET /api/articles?page=:page&limit=:limit&category=:category?
489
+ articles.get('?page=:page?&limit=:limit?&category=:category?', (ctx) => {
490
+ const { page = '1', limit = '10', category = 'all' } = ctx.params;
491
+
492
+ ctx.setStatus(200);
493
+ ctx.json({
494
+ articles: [
495
+ { id: 1, title: 'Article 1', category, author: 'Author 1' },
496
+ { id: 2, title: 'Article 2', category, author: 'Author 2' }
497
+ ],
498
+ pagination: {
499
+ page: parseInt(page),
500
+ limit: parseInt(limit),
501
+ total: 100,
502
+ totalPages: 10
503
+ },
504
+ filters: { category }
505
+ });
506
+ });
507
+
508
+ // POST /api/articles
509
+ articles.post('/', async (ctx) => {
510
+ const articleData = ctx.body;
511
+
512
+ ctx.setStatus(201);
513
+ ctx.json({
514
+ message: 'Article created successfully',
515
+ article: {
516
+ id: Date.now(),
517
+ ...articleData,
518
+ createdAt: new Date().toISOString(),
519
+ slug: articleData.title.toLowerCase().replace(/[^a-z0-9]+/g, '-')
520
+ }
521
+ });
522
+ });
523
+
524
+ // GET /api/articles/:id?include=:include?
525
+ articles.get('/:id?include=:include?', (ctx) => {
526
+ const { id, include = '' } = ctx.params;
527
+ const includes = include.split(',').filter(Boolean);
528
+
529
+ const article = {
530
+ id,
531
+ title: `Article ${id}`,
532
+ content: `Content for article ${id}`,
533
+ author: 'John Doe',
534
+ publishedAt: '2024-01-15T10:00:00Z',
535
+ tags: ['technology', 'programming']
536
+ };
537
+
538
+ if (includes.includes('comments')) {
539
+ article.comments = [
540
+ { id: 1, user: 'Alice', comment: 'Great article!' },
541
+ { id: 2, user: 'Bob', comment: 'Very informative' }
542
+ ];
543
+ }
544
+
545
+ if (includes.includes('stats')) {
546
+ article.stats = {
547
+ views: 1500,
548
+ likes: 120,
549
+ shares: 45
550
+ };
551
+ }
552
+
553
+ ctx.setStatus(200);
554
+ ctx.json(article);
555
+ });
556
+
557
+ // PUT /api/articles/:id
558
+ articles.put('/:id', async (ctx) => {
559
+ const { id } = ctx.params;
560
+ const updateData = ctx.body;
561
+
562
+ ctx.setStatus(200);
563
+ ctx.json({
564
+ message: 'Article updated successfully',
565
+ article: {
566
+ id,
567
+ ...updateData,
568
+ updatedAt: new Date().toISOString()
569
+ }
570
+ });
571
+ });
572
+
573
+ // DELETE /api/articles/:id
574
+ articles.delete('/:id', (ctx) => {
575
+ const { id } = ctx.params;
576
+
577
+ ctx.setStatus(200);
578
+ ctx.json({
579
+ message: `Article ${id} deleted successfully`,
580
+ deletedAt: new Date().toISOString()
581
+ });
582
+ });
583
+
584
+ // Nested routes for article comments
585
+ articles.group('/:articleId/comments', (comments) => {
586
+ // GET /api/articles/:articleId/comments?page=:page?
587
+ comments.get('?page=:page?', (ctx) => {
588
+ const { articleId, page = '1' } = ctx.params;
589
+
590
+ ctx.setStatus(200);
591
+ ctx.json({
592
+ articleId,
593
+ comments: [
594
+ { id: 1, text: 'Great article!', author: 'Alice' },
595
+ { id: 2, text: 'Very helpful', author: 'Bob' }
596
+ ],
597
+ page: parseInt(page)
598
+ });
599
+ });
600
+
601
+ // POST /api/articles/:articleId/comments
602
+ comments.post('/', async (ctx) => {
603
+ const { articleId } = ctx.params;
604
+ const commentData = ctx.body;
605
+
606
+ ctx.setStatus(201);
607
+ ctx.json({
608
+ message: 'Comment added successfully',
609
+ comment: {
610
+ id: Date.now(),
611
+ articleId,
612
+ ...commentData,
613
+ createdAt: new Date().toISOString()
614
+ }
615
+ });
616
+ });
617
+ });
618
+ });
619
+
620
+ // ============================================
621
+ // 6. ERROR HANDLING AND MIDDLEWARE EXAMPLES
622
+ // ============================================
623
+
624
+ // Error handling middleware
625
+ routerFactory.use(async (ctx, next) => {
626
+ try {
627
+ await next();
628
+ } catch (error) {
629
+ console.error('Route error:', error);
630
+ ctx.setStatus(500);
631
+ ctx.json({
632
+ error: 'Internal Server Error',
633
+ message: error.message,
634
+ timestamp: new Date().toISOString()
635
+ });
636
+ }
637
+ });
638
+
639
+ // 404 handler
640
+ routerFactory.use((ctx) => {
641
+ ctx.setStatus(404);
642
+ ctx.json({
643
+ error: 'Not Found',
644
+ message: `Route ${ctx.method} ${ctx.url} not found`,
645
+ timestamp: new Date().toISOString(),
646
+ availableRoutes: routerFactory.getRoutes().map(r => `${r.method} ${r.path}`)
647
+ });
648
+ });
649
+
650
+ // ============================================
651
+ // 7. UTILITY FUNCTIONS AND TESTING
652
+ // ============================================
653
+
654
+ // Get router middleware for AetherJS pipeline
655
+ const routerMiddleware = routerFactory.middleware();
656
+
657
+ // Create a simple HTTP server for testing all features
658
+ import http from 'http';
659
+
660
+ const server = http.createServer(async (req, res) => {
661
+ const ctx = {
662
+ method: req.method,
663
+ url: req.url,
664
+ headers: req.headers,
665
+ body: null,
666
+ setStatus: (code) => { res.statusCode = code; },
667
+ setHeader: (key, value) => { res.setHeader(key, value); },
668
+ json: (data) => {
669
+ res.setHeader('Content-Type', 'application/json');
670
+ res.end(JSON.stringify(data));
671
+ }
672
+ };
673
+
674
+ // Parse request body for POST, PUT, PATCH requests
675
+ if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
676
+ const body = [];
677
+ req.on('data', (chunk) => {
678
+ body.push(chunk);
679
+ });
680
+
681
+ await new Promise((resolve) => {
682
+ req.on('end', () => {
683
+ try {
684
+ ctx.body = body.length > 0 ? JSON.parse(Buffer.concat(body).toString()) : null;
685
+ } catch (error) {
686
+ ctx.body = null;
687
+ }
688
+ resolve();
689
+ });
690
+ });
691
+ }
692
+
693
+ try {
694
+ await routerMiddleware(ctx, () => {
695
+ // If no route matches, the 404 handler will catch it
696
+ });
697
+ } catch (error) {
698
+ console.error('Router error:', error);
699
+ ctx.setStatus(500);
700
+ ctx.json({
701
+ error: 'Internal Server Error',
702
+ message: error.message
703
+ });
704
+ }
705
+ });
706
+
707
+ // Start the server
708
+ const PORT = 3003;
709
+ server.listen(PORT, () => {
710
+ console.log(`๐Ÿš€ Enhanced router test server running on http://localhost:${PORT}`);
711
+ console.log('๐Ÿ“Š Available routes:');
712
+
713
+ const routes = routerFactory.getRoutes();
714
+ routes.forEach(route => {
715
+ console.log(` ${route.method.padEnd(7)} ${route.path}`);
716
+ if (route.hasQueryParams) {
717
+ console.log(` Query params: ${route.queryParamNames.join(', ')}`);
718
+ }
719
+ if (route.pathParamNames.length > 0) {
720
+ console.log(` Path params: ${route.pathParamNames.join(', ')}`);
721
+ }
722
+ });
723
+
724
+ console.log('\n๐ŸŽฏ Test endpoints:');
725
+ console.log(' Basic:');
726
+ console.log(' GET /api/health');
727
+ console.log(' GET /api/v1/users');
728
+ console.log(' GET /api/v2/users?page=1&limit=20');
729
+ console.log('\n Query Parameters:');
730
+ console.log(' GET /api/search?q=test&page=2&limit=20');
731
+ console.log(' GET /api/users/123?fields=name,email&expand=posts');
732
+ console.log(' GET /api/products?category=electronics&minPrice=100&maxPrice=1000&sort=price');
733
+ console.log('\n Versioning:');
734
+ console.log(' GET /api/v1/users/123');
735
+ console.log(' GET /api/v2/users/123?include=posts,comments&fields=name,email');
736
+ console.log('\n Admin Routes:');
737
+ console.log(' GET /api/admin/dashboard?view=detailed');
738
+ console.log(' GET /api/admin/users?status=active&role=admin&page=1');
739
+ console.log('\n RESTful Resources:');
740
+ console.log(' GET /api/articles?page=1&limit=10&category=technology');
741
+ console.log(' GET /api/articles/456?include=comments,stats');
742
+ console.log(' GET /api/articles/789/comments?page=1');
743
+
744
+ console.log('\n๐Ÿ“ˆ Router Statistics:');
745
+ const stats = routerFactory.getStats();
746
+ console.log(` Total routes: ${stats.totalRoutes}`);
747
+ console.log(` Routes with query params: ${stats.routesWithQueryParams}`);
748
+ console.log(` Cache size: ${stats.cacheSize}`);
749
+ console.log(` Cache hit rate: ${stats.cacheHitRate.toFixed(2)}%`);
750
+ console.log(` Available versions: ${stats.versions.join(', ')}`);
751
+ });
752
+
753
+ // Export router middleware for use in other modules
754
+ export default routerMiddleware;
755
+
756
+ // Export router factory for programmatic access
757
+ export { routerFactory };
758
+
759
+ // Example usage function
760
+ export function testRouterFeatures() {
761
+ console.log('\n๐Ÿงช Testing router features...');
762
+
763
+ // Test basic route matching
764
+ const testRoutes = [
765
+ { method: 'GET', path: '/api/health' },
766
+ { method: 'GET', path: '/api/v1/users' },
767
+ { method: 'GET', path: '/api/v2/users?page=2&limit=30' },
768
+ { method: 'GET', path: '/api/search?q=router&page=1' },
769
+ { method: 'GET', path: '/api/admin/dashboard?view=stats' },
770
+ { method: 'GET', path: '/api/articles/123?include=comments' }
771
+ ];
772
+
773
+ testRoutes.forEach(test => {
774
+ const match = routerFactory.match(test.method, test.path);
775
+ if (match) {
776
+ console.log(`โœ“ Route matched: ${test.method} ${test.path}`);
777
+ console.log(` Params: ${JSON.stringify(match.params)}`);
778
+ if (match.query) {
779
+ console.log(` Query: ${JSON.stringify(match.query)}`);
780
+ }
781
+ } else {
782
+ console.log(`โœ— No match for: ${test.method} ${test.path}`);
783
+ }
784
+ });
785
+
786
+ // Display all routes
787
+ console.log('\n๐Ÿ“‹ All registered routes:');
788
+ routerFactory.getRoutes().forEach((route, index) => {
789
+ console.log(`${index + 1}. ${route.method} ${route.path}`);
790
+ });
791
+ }
792
+
793
+ // Run tests if this file is executed directly
794
+ if (import.meta.url === `file://${process.argv[1]}`) {
795
+ testRouterFeatures();
796
+ }