Middleware — ODAC.JS Docs
Docs / ODAC.JS / Backend / Routing / Middleware

🔗 Middleware

Middleware allows you to run code before your controllers execute. Perfect for authentication, logging, rate limiting, and more.

Creating Middleware

Create middleware files in the middleware/ directory:

// middleware/auth.js
module.exports = async (Odac) => {
  if (!await Odac.Auth.check()) {
    return Odac.direct('/login')  // Redirect to login
  }
  // No return = continue to next middleware or controller
}

Middleware Rules:

  • Return false → Stop execution (403 Forbidden)
  • Return Odac.abort(code) → Stop with custom error code
  • Return Odac.direct(url) → Stop and redirect
  • Return nothing or true → Continue to next middleware/controller

Using Middleware

Single Route

Odac.Route
  .use('logger')
  .page('/contact', 'contact')

Multiple Routes

Odac.Route
  .use('cors')
  .page('/api/users', 'api.users')
  .page('/api/posts', 'api.posts')
  .get('/api/stats', 'api.stats')

Multiple Middlewares

Odac.Route
  .use('cors', 'rateLimit')
  .post('/api/upload', 'api.upload')

With Auth Routes

Odac.Route.auth already requires authentication. You can add additional middleware on top:

// Admin-only routes (requires login + admin role)
Odac.Route.auth
  .use('admin')
  .page('/admin/dashboard', 'admin.dashboard')
  .page('/admin/users', 'admin.users')
  .post('/admin/settings', 'admin.settings')
// Premium user routes (requires login + premium subscription)
Odac.Route.auth
  .use('premium')
  .page('/premium/content', 'premium.content')
  .page('/premium/downloads', 'premium.downloads')
// Multiple middlewares with auth
Odac.Route.auth
  .use('verified', 'rateLimit')
  .post('/api/sensitive', 'api.sensitive')

Middleware Examples

Authentication

// middleware/auth.js
module.exports = async (Odac) => {
  if (!await Odac.Auth.check()) {
    return Odac.direct('/login')
  }
}

Admin Check

// middleware/admin.js
module.exports = async (Odac) => {
  const user = await Odac.Auth.user()
  if (!user || user.role !== 'admin') {
    return false  // 403 Forbidden
  }
}

CORS Headers

// middleware/cors.js
module.exports = async (Odac) => {
  Odac.Request.header('Access-Control-Allow-Origin', '*')
  Odac.Request.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
}

Rate Limiting

// middleware/rateLimit.js
const requests = new Map()
let lastCleanup = Date.now()

module.exports = async (Odac) => {
  const ip = Odac.Request.ip
  const now = Date.now()
  const limit = 100
  const window = 60000
  
  if (now - lastCleanup > window) {
    for (const [key, times] of requests.entries()) {
      const recent = times.filter(time => now - time < window)
      if (recent.length === 0) {
        requests.delete(key)
      } else {
        requests.set(key, recent)
      }
    }
    lastCleanup = now
  }
  
  if (!requests.has(ip)) {
    requests.set(ip, [])
  }
  
  const userRequests = requests.get(ip).filter(time => now - time < window)
  
  if (userRequests.length >= limit) {
    return Odac.abort(429, 'Too many requests')
  }
  
  userRequests.push(now)
  requests.set(ip, userRequests)
}

Note: This example uses in-memory storage for simplicity. For production environments with multiple server instances, consider using Redis or Memcached for distributed rate limiting.

Premium Check with View

// middleware/premium.js
module.exports = async (Odac) => {
  const user = await Odac.Auth.user()
  
  if (!user.isPremium) {
    return Odac.View.render('premium/upgrade', {
      user: user,
      currentPage: Odac.Request.url
    })
  }
}

Logging

// middleware/logger.js
module.exports = async (Odac) => {
  console.log(`${Odac.Request.method} ${Odac.Request.url}`)
}

Inline Middleware

Odac.Route
  .use(async (Odac) => {
    console.log('Custom middleware')
  })
  .page('/special', 'special')

Complete Example

// route/www.js

// Public routes
Odac.Route.page('/', 'index')
Odac.Route.page('/about', 'about')

// API routes with CORS
Odac.Route
  .use('cors', 'rateLimit')
  .get('/api/public', 'api.public')
  .post('/api/contact', 'api.contact')

// User routes (requires login)
Odac.Route.auth
  .page('/profile', 'profile')
  .page('/settings', 'settings')
  .post('/api/update', 'update')

// Admin routes (requires login + admin role)
Odac.Route.auth
  .use('admin')
  .page('/admin', 'admin.index')
  .page('/admin/users', 'admin.users')
  .post('/admin/delete', 'admin.delete')

Hot Reloading

Middleware files are automatically reloaded when changed (every 5 seconds), just like controllers and routes. No server restart needed during development.