Skip to content
    SeaCode
    Learning tracksCode ArenaWorkshops & EventsInstructors
    Log inSign up
    NODENode.js

    Runtime and core tooling

    • What is Node.js?
    • CommonJS and ES modules
    • npm and package.json
    • process and command-line apps

    Async I/O and events

    • Event loop: callbacks to async/await
    • Files and paths with fs/promises
    • EventEmitter
    • Streams and backpressure

    HTTP and APIs

    • Your first HTTP server
    • Routing and JSON bodies
    • Build a tiny router and middleware chain
    • REST: resources and status codes
    • Validation and error handling

    Production: security, testing and deployment

    • Authentication basics with crypto
    • Configuration and environment secrets
    • Testing with assert and node:test
    • API security fundamentals
    • Project: tasks REST API and deployment
    Node.js

    HTTP and APIs · Lesson 11 of 18

    Build a tiny router and middleware chain

    Understand what Express does: route matching and a next() middleware chain.

    14 minutes2 games

    Express removes boilerplate but is not magic. Middleware receives a context and next: it can log, authenticate or parse, then calls next to continue. A router selects a handler by method and path. We will implement the idea without a package.

    Request

    logger

    auth

    route handler

    Response unwinds

    Node.js
    async function run(middleware, ctx) {
      async function dispatch(i) {
        if (i < middleware.length) await middleware[i](ctx, () => dispatch(i + 1))
      }
      await dispatch(0)
    }
    const steps = []
    run([
      async (_ctx, next) => { steps.push("before"); await next(); steps.push("after") },
      async (ctx) => { ctx.body = "ok"; steps.push("handler") }
    ], {}).then(() => console.log(steps.join(" > ")))

    Each middleware must either finish the response or call and await next(). Forgetting next stops the chain; calling it twice may run downstream twice. A production wrapper prevents double-next and catches rejected promises.

    JavaScript
    // Real Express equivalent (Express is not installed in this runner)
    import express from "express"
    const app = express()
    app.use(express.json())
    app.use((req, _res, next) => { console.log(req.method, req.url); next() })
    app.get("/health", (_req, res) => res.json({ ok: true }))
    app.listen(process.env.PORT || 3000)

    Important

    Middleware order is behavior: body parsing before routes that need a body, authentication before protected resources, and error handling where the framework expects it. Slow global middleware affects every request.

    Quick question

    A middleware neither responds nor calls next. What happens?

    Interview question

    Why is the middleware pattern useful?

    Exercise

    Complete middleware adding 1 before next and 10 after it; the handler adds 2. Print 13.

    Expected output: 13

    Node.js
    async function run(list, ctx) {
      async function go(i) { if (i < list.length) await list[i](ctx, () => go(i + 1)) }
      await go(0)
    }
    const ctx = { value: 0 }
    run([
      async (ctx, next) => {
    
      },
      async (ctx) => { ctx.value += 2 }
    ], ctx).then(() => console.log(ctx.value))

    Learn more from

    • Express: Using middlewareexpressjs.com
    • Node.js: HTTPnodejs.org

    Played 0 of 2 games

    Sign in to save your progress and earn XP.

    PreviousRouting and JSON bodiesNextREST: resources and status codes
    SeaCode

    Learn to code for real, online or at our branch in front of Cairo University, Giza.

    Learn

    • All courses
    • Interactive tutorials
    • Interview practice problems
    • Mock interview
    • Learning tracks
    • Code Arena
    • Workshops & Events
    • Knowledge library
    • Team projects

    Your account

    • Log in
    • Sign up
    • Learning plan
    • Certificates
    • Site map

    Contact us

    • WhatsApp
    • 010 9094 1104
    • In front of Cairo University, Giza

    © 2026 SeaCode. All rights reserved.