Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

Middleware System

Middleware that orders itself. Type-safe context passing. Automatic optimization. Write middleware, we handle the rest.

Middleware That Orders Itself

Write your middleware. We order it optimally.Authentication before authorization. Validation early. Caching smart.

Execution Order

Automatic Ordering

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

Benefits

  • Automatic optimization
  • Type-safe context
  • Early exit on errors
  • Composable design
  • Performance optimized

Why Intelligent Middleware Matters

Traditional frameworks make you manually order middleware. We do that automatically based on dependencies and performance.

Without intelligent ordering, you're manually managing execution order, risking bugs, and missing optimization opportunities.

Traditional Frameworks

  • Manual middleware ordering
  • Easy to get order wrong
  • No automatic optimization
  • Type safety requires extra work

With MoroJS

  • Automatic middleware ordering
  • Optimal execution path
  • Type-safe context passing
  • Performance optimized automatically

It's This Easy

Add middleware globally or to specific routes. Ordering is automatic.

Global Middleware

Runs on every request

1// Global middleware for logging, CORS, etc.
2app.use(async (req, res, next) => {
3  const start = Date.now();
4  console.log(`${req.method} ${req.url}`);
5  
6  await next();
7  
8  const duration = Date.now() - start;
9  console.log(`Request completed in ${duration}ms`);
10});
11
12// CORS middleware
13app.use(async (req, res, next) => {
14  res.headers.set('Access-Control-Allow-Origin', '*');
15  await next();
16});

Route-Specific Middleware

Chainable API for specific routes

1app.post('/admin/users')
2  .use(authMiddleware)
3  .use(adminOnlyMiddleware)
4  .rateLimit({ requests: 10, window: 60000 })
5  .body(CreateUserSchema)
6  .handler(({ body, context }) => {
7    // All middleware has run in optimal order
8    // context.user is available and typed
9    return { success: true, user: body };
10  });

Why It Makes Sense

Automatic Ordering

Middleware runs in the right order automatically. No manual configuration needed.

Type Safe

Context is fully typed. TypeScript knows what's available in your handlers.

Optimized

Execution paths are optimized automatically. Maximum performance.

How It Works

MoroJS analyzes your middleware at startup and creates an optimized execution plan. Middleware is automatically ordered based on dependencies, type-safe context is passed between middleware, and execution paths are optimized for maximum performance.

Global Middleware

Global middleware runs on every request and is perfect for logging, CORS, and other cross-cutting concerns.

Global Middleware Example

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp();
4
5// Logging middleware
6app.use(async (req, res, next) => {
7  const start = Date.now();
8  console.log(`${req.method} ${req.url}`);
9  
10  await next();
11  
12  const duration = Date.now() - start;
13  console.log(`Request completed in ${duration}ms`);
14});
15
16// CORS middleware
17app.use(async (req, res, next) => {
18  res.headers.set('Access-Control-Allow-Origin', '*');
19  res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
20  res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
21  
22  await next();
23});
24
25// Error handling middleware
26app.use(async (err, req, res, next) => {
27  res.status = 500;
28  res.body = {
29    error: 'INTERNAL_SERVER_ERROR',
30    message: 'Something went wrong',
31    details: err.message
32  };
33});

Route-Specific Middleware

Authentication Middleware

typescript

1const authMiddleware = async (req, res, next) => {
2  const token = req.headers.authorization?.replace('Bearer ', '');
3  if (!token) {
4    res.status = 401;
5    res.body = { error: 'Authentication required' };
6    return;
7  }
8  
9  const user = await verifyJWT(token);
10  req.user = user; // Attach user to request
11  await next();
12};
13
14// Chainable API style
15app.get('/profile')
16  .use(authMiddleware)
17  .handler((req, res) => {
18    // req.user is now available and typed
19    return { profile: req.user };
20  });

Multiple Middleware - Chainable API

typescript

1app.post('/admin/users')
2  .use(authMiddleware)
3  .use(async (req, res, next) => {
4    if (req.user.role !== 'admin') {
5      res.status = 403;
6      res.body = { error: 'Admin access required' };
7      return;
8    }
9    await next();
10  })
11  .rateLimit({ requests: 10, window: 60000 })
12  .use(async (req, res, next) => {
13    await logAdminAction(req.user.id, 'CREATE_USER', req.url);
14    await next();
15  })
16  .body(CreateUserSchema)
17  .handler((req, res) => {
18    // All middleware has run, req.user is populated
19    return createUser(req.body, req.user);
20  });

Built-in Middleware Options

typescript

1app.post('/api/data')
2  .rateLimit({ 
3    requests: 100, 
4    window: 3600000, // 1 hour in ms
5    key: (req) => req.user?.id || req.ip 
6  })
7  .cache({ 
8    ttl: 300000, // 5 minutes in ms
9    key: (req) => `user:${req.user.id}`,
10    tags: ['user-data']
11  })
12  .handler((req, res) => {
13    return { data: processData(req.body) };
14  });

Creating Custom Middleware

Custom Middleware Pattern

typescript

1// Middleware function signature
2type MiddlewareFunction = (
3  req: HttpRequest,
4  res: HttpResponse,
5  next: () => Promise<void>
6) => Promise<void>;
7
8// Example: Request timing middleware
9const timingMiddleware: MiddlewareFunction = async (req, res, next) => {
10  const start = performance.now();
11  
12  // Add timing data to request
13  req.timing = { start };
14  
15  await next();
16  
17  const end = performance.now();
18  req.timing.duration = end - start;
19  
20  // Add timing header to response
21  res.headers.set('X-Response-Time', `${req.timing.duration}ms`);
22};
23
24// Usage - Chainable API
25app.get('/timed-endpoint')
26  .use(timingMiddleware)
27  .handler((req, res) => {
28    return { 
29      message: 'Success',
30      processingTime: req.timing.duration 
31    };
32  });

Conditional Middleware & Middleware Factories

typescript

1// Middleware that runs conditionally
2const conditionalAuth = async (req, res, next) => {
3  const isPublicEndpoint = req.url.includes('/public/');
4  
5  if (!isPublicEndpoint) {
6    const token = req.headers.authorization;
7    if (!token) {
8      res.status = 401;
9      res.body = { error: 'Authentication required' };
10      return;
11    }
12    req.user = await verifyToken(token);
13  }
14  
15  await next();
16};
17
18// Middleware factory
19const createRoleMiddleware = (requiredRole: string) => {
20  return async (req, res, next) => {
21    if (!req.user || req.user.role !== requiredRole) {
22      res.status = 403;
23      res.body = { error: `${requiredRole} role required` };
24      return;
25    }
26    await next();
27  };
28};
29
30// Chainable API
31app.get('/admin/stats')
32  .use(conditionalAuth)
33  .use(createRoleMiddleware('admin'))
34  .handler((req, res) => getAdminStats());

Next Steps