Route-Specific Middleware
Route-specific middleware applies to specific route patterns, allowing targeted functionality like authentication for API routes or logging for admin routes.
Matching is boundary-aware: router.use('/api', fn) runs for /api and /api/users, but not for /apiv2, because the pathname must equal the prefix or continue with a /.

Basic Usage
Apply middleware to specific route patterns using the use() method with a route path:
typescript
import { Router } from '@neabyte/deserve'
const router = new Router()
// Runs for paths starting with /api
router.use('/api', async (ctx, next) => {
console.log(`API request: ${ctx.get.method()} ${ctx.get.pathname()}`)
return await next()
})
await router.serve(8000)Route Pattern Matching
Middleware applies to routes that start with the specified pattern:
typescript
// Applies to /api/* routes
router.use('/api', middleware)
// Applies to /api/users/* routes
router.use('/api/users', middleware)
// Applies to /admin/* routes
router.use('/admin', middleware)Common Route-Specific Patterns
API Authentication
typescript
// Require a bearer token under /api
router.use('/api', async (ctx, next) => {
const authHeader = ctx.get.header('authorization')
if (!authHeader) {
return ctx.send.text('API requires authentication', { status: 401 })
}
const token = authHeader.replace('Bearer ', '')
if (!isValidToken(token)) {
return ctx.send.text('Invalid token', { status: 401 })
}
return await next()
})Admin Authorization
typescript
// Allow only the admin role under /admin
router.use('/admin', async (ctx, next) => {
const userRole = ctx.get.header('x-user-role')
if (userRole !== 'admin') {
return ctx.send.text('Admin access required', { status: 403 })
}
return await next()
})Public Route Logging
typescript
// Log access under /public
router.use('/public', async (ctx, next) => {
console.log(`Public access: ${ctx.get.method()} ${ctx.get.pathname()}`)
return await next()
})Version-Specific Middleware
typescript
// Separate middleware per API version
router.use('/api/v1', async (ctx, next) => {
console.log('Legacy API v1 request')
return await next()
})
router.use('/api/v2', async (ctx, next) => {
console.log('Modern API v2 request')
return await next()
})Multiple Route-Specific Middleware
Apply multiple middleware to the same route pattern:
typescript
// Auth runs first under /api
router.use('/api', async (ctx, next) => {
const authHeader = ctx.get.header('authorization')
if (!authHeader) {
return ctx.send.text('Unauthorized', { status: 401 })
}
return await next()
})
// Logging runs after auth passes
router.use('/api', async (ctx, next) => {
console.log(`API: ${ctx.get.method()} ${ctx.get.pathname()}`)
return await next()
})Nested Route Patterns
Apply middleware to nested route patterns:
typescript
// Covers every path under /api
router.use('/api', async (ctx, next) => {
console.log('API request')
return await next()
})
// Narrows to /api/users
router.use('/api/users', async (ctx, next) => {
console.log('User API request')
return await next()
})
// Narrows further and checks role
router.use('/api/users/admin', async (ctx, next) => {
const role = ctx.get.header('x-user-role')
if (role !== 'admin') {
return ctx.send.text('Admin access required', { status: 403 })
}
return await next()
})Middleware Execution Order
Middleware runs in the order it is added:

typescript
// Global runs for every request
router.use(async (ctx, next) => {
console.log('Global middleware')
return await next()
})
// Path middleware runs for /api requests
router.use('/api', async (ctx, next) => {
console.log('API middleware')
return await next()
})
// For /api/users: global, then API, then handler