Intelligent Routing

MoroJS features an intelligent routing system that automatically optimizes middleware ordering, provides type-safe validation, and enhances performance through smart route compilation.

What is Intelligent Routing?

Traditional frameworks require you to manually order middleware and handle route compilation. MoroJS's intelligent routing system automatically:

  • Optimizes middleware order based on dependencies and performance characteristics
  • Compiles routes at startup for maximum runtime performance
  • Provides type safety throughout the entire request pipeline
  • Enables intelligent caching and rate limiting per route

Basic Route Definition

Simple Routes

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp();
4
5// Simple GET route
6app.get('/', () => {
7  return { message: 'Hello World' };
8});
9
10// Route with parameters
11app.get('/users/:id', ({ params }) => {
12  return { userId: params.id };
13});
14
15// Multiple HTTP methods
16app.post('/users', ({ body }) => {
17  // Create user logic
18  return { success: true };
19});
20
21app.put('/users/:id', ({ params, body }) => {
22  // Update user logic
23  return { userId: params.id, updated: true };
24});

Automatic Type Inference

MoroJS automatically infers parameter types from your route patterns. The params.idin the example above is automatically typed as string.

Advanced Route Configuration

Route with Full Configuration

typescript

1import { createApp } from '@morojs/moro';
2import { z } from 'zod';
3
4const app = createApp();
5
6// Define schemas
7const CreateUserSchema = z.object({
8  name: z.string().min(1).max(100),
9  email: z.string().email(),
10  age: z.number().min(18).max(120)
11});
12
13const UserParamsSchema = z.object({
14  id: z.string().uuid()
15});
16
17// Advanced route configuration
18app.post('/users', {
19  // Request validation
20  body: CreateUserSchema,
21  
22  // Response schema (for documentation)
23  response: z.object({
24    id: z.string().uuid(),
25    name: z.string(),
26    email: z.string(),
27    createdAt: z.string()
28  }),
29  
30  // Route-specific middleware
31  middleware: [
32    // Authentication middleware
33    async ({ headers }) => {
34      if (!headers.authorization) {
35        throw new Error('Unauthorized');
36      }
37    },
38    
39    // Rate limiting
40    { rateLimit: { max: 10, window: '1m' } }
41  ],
42  
43  // Main handler
44  handler: async ({ body }) => {
45    // body is now fully typed and validated
46    const user = await createUser(body);
47    return {
48      id: user.id,
49      name: user.name,
50      email: user.email,
51      createdAt: user.createdAt
52    };
53  }
54});

Intelligent Middleware Ordering

MoroJS automatically orders middleware based on dependencies. Authentication runs before rate limiting, validation happens early, and caching is optimally placed for maximum efficiency.

Route Patterns

Supported Route Patterns

typescript

1// Static routes
2app.get('/api/health', handler);
3
4// Named parameters
5app.get('/users/:id', handler);
6app.get('/users/:id/posts/:postId', handler);
7
8// Optional parameters
9app.get('/posts/:id?', handler);
10
11// Wildcard routes
12app.get('/files/*', handler);
13
14// Query parameters (automatically parsed)
15app.get('/search', ({ query }) => {
16  // query.q, query.limit, etc. are automatically available
17  return { results: search(query.q, query.limit) };
18});
19
20// Route groups with common prefix
21app.group('/api/v1', (group) => {
22  group.get('/users', getUsersHandler);
23  group.post('/users', createUserHandler);
24  group.get('/users/:id', getUserHandler);
25});

Intelligent Middleware System

Middleware Types and Ordering

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp();
4
5// Global middleware (applied to all routes)
6app.use(async ({ request, response }, next) => {
7  console.log(`${request.method} ${request.url}`);
8  await next();
9});
10
11// Route with multiple middleware types
12app.get('/protected-data', {
13  middleware: [
14    // 1. Authentication (runs first)
15    async ({ headers }) => {
16      const token = headers.authorization?.replace('Bearer ', '');
17      if (!token) throw new Error('No token provided');
18      return { user: await verifyToken(token) };
19    },
20    
21    // 2. Authorization (runs after auth)
22    async ({ context }) => {
23      if (!context.user.hasPermission('read:data')) {
24        throw new Error('Insufficient permissions');
25      }
26    },
27    
28    // 3. Caching (runs after auth/authz)
29    { cache: { ttl: '5m', key: (ctx) => `data:${ctx.user.id}` } },
30    
31    // 4. Rate limiting (optimally placed)
32    { rateLimit: { max: 100, window: '1h', key: (ctx) => ctx.user.id } }
33  ],
34  
35  handler: async ({ context }) => {
36    // All middleware has run, context is fully populated
37    return await getProtectedData(context.user);
38  }
39});

Automatic Ordering

  • 1Request parsing
  • 2Authentication
  • 3Authorization
  • 4Validation
  • 5Rate limiting
  • 6Caching
  • 7Handler execution

Performance Benefits

  • No manual ordering needed
  • Optimal execution path
  • Early exit on failures
  • Compile-time optimization
  • Type-safe context passing

Route Compilation & Performance

Route Compilation Process

At application startup, MoroJS analyzes all your routes and creates an optimized execution plan:

  • Builds optimal middleware chains
  • Pre-compiles route matchers
  • Generates type-safe handlers
  • Optimizes for common patterns

Route Compilation Example

typescript

1// Development: Route definition
2app.get('/users/:id', {
3  params: z.object({ id: z.string().uuid() }),
4  handler: ({ params }) => getUserById(params.id)
5});
6
7// Runtime: Compiled to optimized function
8const compiledRoute = {
9  method: 'GET',
10  pattern: /^/users/([0-9a-f-]{36})$/,
11  paramNames: ['id'],
12  middlewareChain: [
13    validateParams,
14    executeHandler
15  ],
16  handler: (ctx) => {
17    // Pre-validated, type-safe execution
18    return getUserById(ctx.params.id);
19  }
20};

Best Practices

Do

  • • Use descriptive route patterns
  • • Define validation schemas
  • • Group related routes together
  • • Leverage automatic middleware ordering
  • • Use type-safe parameter extraction
  • • Define response schemas for documentation

Don't

  • • Manually order middleware unnecessarily
  • • Skip input validation
  • • Use overly complex route patterns
  • • Ignore TypeScript warnings
  • • Mix business logic in middleware
  • • Forget to handle errors properly

Next Steps