Bird
Raised Fist0
Denoframework~10 mins

Middleware patterns in Deno - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Middleware patterns
Incoming Request
↓
Middleware 1
↓
Middleware 2
↓
Middleware 3
↓
Final Handler
↓
Response Sent
The request passes through a chain of middleware functions, each can modify the request or response, then the final handler sends the response.
Execution Sample
Deno
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use(async (ctx, next) => {
  console.log("Middleware 1 start");
  await next();
  console.log("Middleware 1 end");
});
This code sets up a middleware that logs before and after calling the next middleware.
Execution Table
StepMiddlewareActionConsole OutputNext CalledResponse Status
1Middleware 1Start processing requestMiddleware 1 startYesPending
2Middleware 2Start processing requestMiddleware 2 startYesPending
3Middleware 3Start processing requestMiddleware 3 startYesPending
4Final HandlerSend responseNo200 OK
5Middleware 3After next()Middleware 3 endN/A200 OK
6Middleware 2After next()Middleware 2 endN/A200 OK
7Middleware 1After next()Middleware 1 endN/A200 OK
💡 All middleware called next() until final handler sent response, then middleware resumed after next() in reverse order.
Variable Tracker
VariableStartAfter Middleware 1After Middleware 2After Middleware 3Final
ctx.response.statusundefinedPendingPendingPending200 OK
console outputemptyMiddleware 1 startMiddleware 1 start, Middleware 2 startMiddleware 1 start, Middleware 2 start, Middleware 3 startMiddleware 1 start, Middleware 2 start, Middleware 3 start, Middleware 3 end, Middleware 2 end, Middleware 1 end
Key Moments - 3 Insights
Why do middleware functions call 'await next()'?
Calling 'await next()' passes control to the next middleware. Without it, the chain stops and later middleware or the final handler won't run, as shown in execution_table steps 1 and 2.
Why do console logs appear both before and after 'await next()'?
Logs before 'await next()' run when request enters middleware; logs after run when response returns back through middleware, shown in execution_table steps 1 and 7.
What happens if a middleware does not call 'next()'?
The chain stops at that middleware, so later middleware and final handler won't run, and response may never be sent. This is why 'Next Called' is important in the table.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is logged to console at Step 3?
AMiddleware 1 end
BMiddleware 3 start
CMiddleware 2 end
DFinal Handler response
💡 Hint
Check the 'Console Output' column at Step 3 in execution_table.
At which step does the response status become '200 OK'?
AStep 4
BStep 1
CStep 7
DStep 2
💡 Hint
Look at the 'Response Status' column in execution_table where it changes from 'Pending' to '200 OK'.
If Middleware 2 did not call 'await next()', what would happen?
AMiddleware 1 would not run
BResponse status would be 404
CMiddleware 3 and Final Handler would not run
DMiddleware 3 would run twice
💡 Hint
Refer to the 'Next Called' column in execution_table and the key moment about skipping next().
Concept Snapshot
Middleware patterns chain functions that process requests in order.
Each middleware calls 'await next()' to pass control.
After final handler sends response, middleware resumes after 'next()'.
This allows pre- and post-processing around request handling.
Missing 'next()' stops the chain and blocks response.
Full Transcript
Middleware patterns in Deno let you process requests step-by-step. Each middleware function receives the request context and a 'next' function. When middleware calls 'await next()', it passes control to the next middleware. This continues until the final handler sends the response. Then middleware functions resume after 'next()', allowing code to run after response generation. This pattern helps add logging, authentication, or modify requests and responses in a clear order. If a middleware does not call 'next()', the chain stops and later middleware or the final handler won't run, so the response may never be sent. The execution table shows the order of middleware calls, console logs, and when the response status changes. Understanding this flow helps you build reliable web servers with Deno middleware.

Practice

(1/5)
1. What is the main purpose of middleware in a Deno web application?
easy
A. To compile TypeScript code into JavaScript
B. To store data permanently in a database
C. To run code step-by-step for each incoming request
D. To create user interface components

Solution

  1. Step 1: Understand middleware role

    Middleware processes each request in order, allowing code to run before sending a response.
  2. Step 2: Compare options

    Only To run code step-by-step for each incoming request describes this step-by-step request handling. Other options describe unrelated tasks.
  3. Final Answer:

    To run code step-by-step for each incoming request -> Option C
  4. Quick Check:

    Middleware = step-by-step request code [OK]
Hint: Middleware runs code for each request in order [OK]
Common Mistakes:
  • Confusing middleware with database operations
  • Thinking middleware builds UI components
  • Assuming middleware compiles code
2. Which of the following is the correct way to call the next middleware in Deno?
easy
A. next.await()
B. next()
C. call next()
D. await next()

Solution

  1. Step 1: Recall async middleware pattern

    Middleware functions are async and must await next() to continue the chain.
  2. Step 2: Check syntax correctness

    Only 'await next()' correctly waits for the next middleware to finish before continuing.
  3. Final Answer:

    await next() -> Option D
  4. Quick Check:

    Use await next() to proceed [OK]
Hint: Always use await before next() in async middleware [OK]
Common Mistakes:
  • Calling next() without await causing unexpected behavior
  • Using incorrect syntax like call next()
  • Trying to use next.await() which is invalid
3. Given this middleware code snippet in Deno:
async function logger(ctx, next) {
  console.log('Before');
  await next();
  console.log('After');
}

async function handler(ctx) {
  ctx.response.body = 'Hello';
}

// Middleware chain: logger -> handler
What will be printed to the console when a request is handled?
medium
A. Before\nAfter
B. After\nBefore
C. Before
D. After

Solution

  1. Step 1: Analyze middleware flow

    Logger prints 'Before', then awaits next middleware (handler), then prints 'After'.
  2. Step 2: Understand order of prints

    Since handler runs between the two console.logs, output order is 'Before' then 'After'.
  3. Final Answer:

    Before\nAfter -> Option A
  4. Quick Check:

    Middleware logs before and after next() [OK]
Hint: Middleware logs before and after await next() [OK]
Common Mistakes:
  • Assuming 'After' prints before 'Before'
  • Thinking only 'Before' or 'After' prints
  • Ignoring await causing wrong order
4. Identify the error in this Deno middleware code:
async function auth(ctx, next) {
  if (!ctx.request.headers.get('Authorization')) {
    ctx.response.status = 401;
    ctx.response.body = 'Unauthorized';
  }
  await next();
}
medium
A. Missing await before ctx.request.headers.get
B. Should return after setting 401 to stop middleware chain
C. ctx.response.body must be a JSON object
D. next() should not be awaited

Solution

  1. Step 1: Understand middleware flow control

    If authorization header is missing, response is set to 401, but code still calls await next(), continuing the chain.
  2. Step 2: Identify fix to stop chain

    To prevent further middleware running, function should return immediately after setting 401 response.
  3. Final Answer:

    Should return after setting 401 to stop middleware chain -> Option B
  4. Quick Check:

    Return early to stop middleware chain [OK]
Hint: Return after response to stop middleware chain [OK]
Common Mistakes:
  • Not returning causes next middleware to run anyway
  • Thinking await is missing on header get
  • Believing response body must be JSON always
5. You want to create a middleware in Deno that measures how long each request takes and adds a custom header X-Response-Time with the duration in milliseconds. Which of the following middleware implementations correctly achieves this?
hard
A. async function responseTime(ctx, next) { const start = performance.now(); await next(); const ms = performance.now() - start; ctx.response.headers.set('X-Response-Time', ms.toFixed(2)); }
B. async function responseTime(ctx, next) { const start = Date.now(); const ms = Date.now() - start; ctx.response.headers.set('X-Response-Time', `${ms}ms`); await next(); }
C. async function responseTime(ctx, next) { const start = Date.now(); next(); const ms = Date.now() - start; ctx.response.headers.set('X-Response-Time', `${ms}ms`); }
D. async function responseTime(ctx, next) { await next(); const ms = Date.now(); ctx.response.headers.set('X-Response-Time', ms); }

Solution

  1. Step 1: Measure time before and after next()

    Start timer before await next(), then calculate duration after it finishes.
  2. Step 2: Use precise timer and set header correctly

    performance.now() gives better precision than Date.now(). Setting header with ms.toFixed(2) formats nicely.
  3. Final Answer:

    Middleware using performance.now(), await next(), and setting header after next() -> Option A
  4. Quick Check:

    Use performance.now() and await next() then set header [OK]
Hint: Start timer before await next(), set header after [OK]
Common Mistakes:
  • Calculating time before await next() runs
  • Using Date.now() which is less precise
  • Setting header before next() completes
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard