This middleware system provides a flexible and powerful way to compose
middleware functions that are fully compatible with Deno.serve handlers.
- 🔄 Full Deno.serve compatibility - Works seamlessly with standard Deno HTTP handlers
- 🛠️ Flexible composition - Multiple ways to compose middleware (functional and fluent)
- 🔧 Built-in middleware - Common middleware like CORS, logging, auth, rate limiting
- 🚨 Error handling - Configurable error handling and recovery
- 📊 Request context - Share data between middleware and handlers
- ⚡ Type-safe - Full TypeScript support with proper typing
import{createMiddlewareChain,logger,cors,rateLimit,timeout}from"jsr:@snaapi/middleware";// Your application handlerfunctionmyHandler(req: Request): Response{returnnewResponse("Hello World!");}// Create middleware stackconsthandler=createMiddlewareChain().use(logger()).use(cors()).use(rateLimit({windowMs: 60000,maxRequests: 100})).use(timeout(30000)).handle(myHandler);// Start serverDeno.serve({port: 8000},handler);import{compose,logger,cors,rateLimit,timeout}from"jsr:@snaapi/middleware";consthandler=compose([logger(),cors(),rateLimit({windowMs: 60000,maxRequests: 100}),timeout(30000),],myHandler,);Deno.serve({port: 8000},handler);Logs HTTP requests with configurable formats:
import{logger}from"jsr:@snaapi/middleware";// Simple logging.use(logger())// Detailed logging with headers and body.use(logger({format: "detailed",includeHeaders: true,includeBody: true}))// JSON structured logging.use(logger({format: "json"}))Handles Cross-Origin Resource Sharing:
import{cors}from"jsr:@snaapi/middleware";// Basic CORS (allows all origins).use(cors())// Configured CORS.use(cors({origin: ["https://myapp.com","https://admin.myapp.com"],methods: ["GET","POST","PUT","DELETE"],headers: ["Content-Type","Authorization"],credentials: true}))Request rate limiting per client:
import{rateLimit}from"jsr:@snaapi/middleware";// 100 requests per minute.use(rateLimit({windowMs: 60000,maxRequests: 100}))// Custom key generator (rate limit by IP).use(rateLimit({windowMs: 60000,maxRequests: 100,keyGenerator: (req)=>req.headers.get("X-Real-IP")||"unknown"}))Timeout long-running requests:
import{timeout}from"jsr:@snaapi/middleware";// 30 second timeout.use(timeout(30000))Create your own middleware functions:
import{typeMiddleware}from"jsr:@snaapi/middleware";// Simple custom middlewareconstcustomMiddleware: Middleware=async(req,next)=>{console.log(`Processing ${req.method}${req.url}`);constresponse=awaitnext();console.log(`Responded with ${response.status}`);returnresponse;};// Middleware with configurationfunctioncustomAuth(apiKey: string): Middleware{returnasync(req,next)=>{constkey=req.headers.get("X-API-Key");if(key!==apiKey){returnnewResponse("Unauthorized",{status: 401});}returnnext();};}Share data between middleware:
import{withContext,getContext,setContext}from"jsr:@snaapi/middleware";// Add context middleware.use(withContext({startTime: Date.now()}))// Use context in subsequent middleware.use(async(req,next)=>{constcontext=getContext(req);console.log("Request started at:",context.startTime);setContext(req,"userId","user123");returnnext();})Configure error handling behavior:
createMiddlewareChain().use(logger()).use(cors()).configure({continueOnError: false,errorHandler: (error,req)=>{console.error(`Error in ${req.url}:`,error);returnnewResponse(JSON.stringify({error: "Something went wrong"}),{status: 500,headers: {"Content-Type": "application/json"},},);},}).handle(myHandler);import{ResourceHandler}from"./server/resource.ts";import{createMiddlewareChain,logger,cors,rateLimit}from"jsr:@snaapi/middleware";constresourceHandler=newResourceHandler();consthandler=createMiddlewareChain().use(logger()).use(cors()).use(rateLimit({windowMs: 60000,maxRequests: 100})).handle(resourceHandler.handler.bind(resourceHandler));Deno.serve({port: 8000},handler);Apply different middleware to different routes:
consthandler=async(req: Request): Promise<Response>=>{consturl=newURL(req.url);if(url.pathname==="/health"){// Minimal middleware for health checkreturncreateMiddlewareChain().use(logger({format: "simple"})).handle(healthHandler)(req);}// Full middleware stack for API routesreturncreateMiddlewareChain().use(logger({format: "detailed"})).use(cors()).use(auth("my-token")).handle(apiHandler)(req);};typeMiddleware=(req: Request,next: ()=>Promise<Response>,)=>Promise<Response>;typeHandler=(req: Request)=>Response|Promise<Response>;interfaceRequestContext{[key: string]: unknown;}To migrate existing code:
- Replace direct
Deno.serve(handler)calls with middleware-wrapped handlers - Move authentication logic to
auth()middleware - Replace manual CORS handling with
cors()middleware - Add logging with
logger()middleware - Configure error handling with
.configure()
Deno.serve({port: 8000},resourceHandler.handler.bind(resourceHandler));consthandler=createMiddlewareChain().use(logger()).use(cors()).use(rateLimit({windowMs: 60000,maxRequests: 100})).handle(resourceHandler.handler.bind(resourceHandler));Deno.serve({port: 8000},handler);