API Reference

Middleware API Reference

Complete reference for MoroJS middleware system. Learn about creating, composing, and managing middleware with intelligent ordering.

Global Middleware

Global middleware runs on every request. MoroJS automatically orders middleware for optimal performance and security.

app.use() - Global Middleware (Actual Implementation)
1import { createApp } from '@morojs/moro';
2
3const app = await createApp();
4
5// Simple middleware function
6app.use((req, res, next) => {
7  console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
8  next();
9});
10
11// Example from enterprise-app
12app.use((req, res, next) => {
13  console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
14  next();
15});
16
17// Middleware is simpler in actual implementation
18app.use((req, res, next) => {
19  // Add request ID for tracking
20  req.requestId = Date.now().toString();
21  next();
22});

MoroJS automatically orders middleware based on type and dependencies:

Intelligent Ordering

  1. 1Security middleware (CORS, Helmet)
  2. 2Request parsing (body parser, compression)
  3. 3Authentication middleware
  4. 4Rate limiting middleware
  5. 5Custom business logic middleware
  6. 6Error handling middleware

Route-Specific Middleware

Route Middleware Configuration
1// Single middleware
2app.get('/protected')
3  .use(authMiddleware)
4  .handler((context) => ({ message: 'Protected resource' })));
5
6// Multiple middleware with ordering
7app.post('/api/users')
8  .body(CreateUserSchema)
9  .use(validateApiKey,
10    rateLimitMiddleware({ max: 10, window: '1m' }),
11    requireAuth,
12    requireRole('admin'))
13  .handler(createUserHandler));
14
15// Conditional middleware
16app.get('/data/:id')
17  .use((context, next) => {
18      if (context.params.id === 'public') {
19        return next(); // Skip auth for public data
20      }
21      return authMiddleware(context, next);
22    })
23  .handler(getDataHandler));

Creating Custom Middleware

Basic Middleware Pattern
1// Basic middleware function
2const loggingMiddleware = async (context, next) => {
3  const start = Date.now();
4  
5  console.log(`[${new Date().toISOString()}] ${context.request.method} ${context.request.url}`);
6  
7  await next();
8  
9  const duration = Date.now() - start;
10  console.log(`Request completed in ${duration}ms`);
11};
12
13// Middleware with configuration
14const rateLimitMiddleware = (options = {}) => {
15  const { max = 100, window = '15m' } = options;
16  
17  return async (context, next) => {
18    const key = `rate_limit:${context.ip}`;
19    const current = await cache.get(key) || 0;
20    
21    if (current >= max) {
22      return context.status(429).json({ 
23        error: 'Rate limit exceeded',
24        retryAfter: window
25      });
26    }
27    
28    await cache.set(key, current + 1, { ttl: window });
29    await next();
30  };
31};
Advanced Middleware Patterns
1// Error handling middleware
2const errorHandlerMiddleware = async (context, next) => {
3  try {
4    await next();
5  } catch (error) {
6    console.error('Request error:', error);
7    
8    if (error.name === 'ValidationError') {
9      return context.status(400).json({
10        error: 'Validation failed',
11        details: error.details
12      });
13    }
14    
15    return context.status(500).json({
16      error: 'Internal server error'
17    });
18  }
19};
20
21// Authentication middleware
22const authMiddleware = async (context, next) => {
23  const token = context.headers.authorization?.replace('Bearer ', '');
24  
25  if (!token) {
26    return context.status(401).json({ error: 'Authentication required' });
27  }
28  
29  try {
30    const user = await verifyJWT(token);
31    context.user = user; // Add to context
32    await next();
33  } catch (error) {
34    return context.status(401).json({ error: 'Invalid token' });
35  }
36};
37
38// CORS middleware
39const corsMiddleware = (options = {}) => {
40  const {
41    origin = '*',
42    methods = ['GET', 'POST', 'PUT', 'DELETE'],
43    headers = ['Content-Type', 'Authorization']
44  } = options;
45  
46  return async (context, next) => {
47    context.response.headers.set('Access-Control-Allow-Origin', origin);
48    context.response.headers.set('Access-Control-Allow-Methods', methods.join(', '));
49    context.response.headers.set('Access-Control-Allow-Headers', headers.join(', '));
50    
51    if (context.request.method === 'OPTIONS') {
52      return context.status(200).text('');
53    }
54    
55    await next();
56  };
57};

Middleware Context

Context Object Properties
1interface MiddlewareContext {
2  // HTTP primitives
3  request: Request;
4  response: Response;
5  
6  // Parsed request data
7  params: Record<string, string>;
8  query: Record<string, string>;
9  headers: Record<string, string>;
10  body: any;
11  
12  // Request metadata
13  ip: string;
14  userAgent: string;
15  method: string;
16  url: string;
17  
18  // Shared context (for middleware communication)
19  context: Record<string, any>;
20  
21  // Response helpers
22  json(data: any): Response;
23  text(data: string): Response;
24  status(code: number): ResponseBuilder;
25  redirect(url: string, status?: number): Response;
26  
27  // Utilities
28  set(key: string, value: any): void;
29  get(key: string): any;
30}
Context Usage Examples
1// Sharing data between middleware
2const dataMiddleware = async (context, next) => {
3  context.set('startTime', Date.now());
4  context.set('requestId', generateId());
5  await next();
6};
7
8const loggingMiddleware = async (context, next) => {
9  const requestId = context.get('requestId');
10  console.log(`[${requestId}] Processing request`);
11  await next();
12  
13  const duration = Date.now() - context.get('startTime');
14  console.log(`[${requestId}] Completed in ${duration}ms`);
15};
16
17// Modifying request/response
18const transformMiddleware = async (context, next) => {
19  // Transform request body
20  if (context.body) {
21    context.body = transformRequestData(context.body);
22  }
23  
24  await next();
25  
26  // Transform response (if needed)
27  // Note: Response transformation is handled differently
28};

Built-in Middleware

Available Built-in Middleware
1import { createApp, middleware } from '@morojs/moro';
2
3const app = await createApp();
4
5// CORS
6app.use(middleware.cors({
7  origin: ['https://example.com'],
8  credentials: true,
9  methods: ['GET', 'POST', 'PUT', 'DELETE']
10}));
11
12// Rate limiting
13app.use(middleware.rateLimit({
14  windowMs: 15 * 60 * 1000,
15  max: 100
16}));
17
18// Security headers
19app.use(middleware.helmet({
20  contentSecurityPolicy: { defaultSrc: ["'self'"], styleSrc: ["'self'"] },
21  xFrameOptions: 'DENY',
22  strictTransportSecurity: { maxAge: 31536000, includeSubDomains: true }
23}));
24
25// Response compression
26app.use(middleware.compression({
27  threshold: 1024,
28  level: 6,
29  filter: (req, res) => !req.path.startsWith('/stream')
30}));

middleware.*

  • validation() - Schema validation
  • cors() - Cross-Origin Resource Sharing
  • helmet() - Security headers
  • rateLimit() - Request rate limiting
  • csrf() / csp() - CSRF and CSP protection
  • auth() - Authentication
  • session() / cookie() - Session and cookies
  • compression() - Response compression
  • staticFiles() - Static file serving
  • upload() - File uploads
  • cache() / cdn() - Caching and CDN
  • bodySize() / range() - Body limits, range requests
  • sse() / graphql() / template()
  • http2.push() - HTTP/2 server push

Observability

  • requestLogger() - Request logging
  • performanceMonitor() - Performance timing
  • errorTracker() - Error tracking (4-arg error handler)
  • prometheus() - Prometheus scrape endpoint
  • cloudWatch() - CloudWatch Embedded Metric Format

Every entry is a factory

Call it — with options, or bare for defaults — and it returns middleware. Passing one uncalled, as app.use(middleware.helmet), throws at registration rather than silently doing nothing.

Body parsing is automatic. json() and urlencoded() are root exports kept for Express compatibility.

Next Steps