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)typescript
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
- 1Security middleware (CORS, Helmet)
- 2Request parsing (body parser, compression)
- 3Authentication middleware
- 4Rate limiting middleware
- 5Custom business logic middleware
- 6Error handling middleware
Route-Specific Middleware
Route Middleware Configurationtypescript
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 Patterntypescript
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 Patternstypescript
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 Propertiestypescript
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 Examplestypescript
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 Middlewaretypescript
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.