Skip to content

Context Object

The Context object wraps the native Request and provides convenient methods for accessing request data, setting response headers, and sending responses.

What is Context?

Context is a wrapper around Deno's native Request object. Instead of working with raw Request directly, you use Context which gives you:

  • Lazy parsing - Data is parsed only when you access it
  • Convenient methods - Simple APIs for common operations
  • Response utilities - Built-in methods for sending responses
  • Header management - Easy response header manipulation

Why Using Context?

Context avoids multiple parsing and repeated processing during the request lifecycle. The handler receives one Context object that persists through the entire lifecycle — from middleware to route handler.

Creating Context

Deserve creates Context automatically when requests arrive:

typescript
import type { Context } from '@neabyte/deserve'

export function GET(ctx: Context): Response {
  return ctx.send.json({ message: 'Hello' })
}

Context Structure

Context wraps several key pieces:

  1. Original Request - Access via ctx.request
  2. Parsed URL - Used internally for query params
  3. Route Parameters - Extracted from dynamic routes
  4. Response Headers - Set before sending response

Lazy Parsing

Context uses lazy parsing for performance:

typescript
export function GET(ctx: Context): Response {
  // Query params aren't parsed yet

  const query = ctx.query() // Parsed on first access
  // Now cached, subsequent calls return cached value

  const body = await ctx.body() // Parsed on first access
  // Parsed based on Content-Type

  return ctx.send.json({ query, body })
}

Request Data Access

Access request data through Context methods:

  • Query Parameters - ctx.query(), ctx.queries()
  • Route Parameters - ctx.param(), ctx.params()
  • Headers - ctx.header(), ctx.headers
  • Cookies - ctx.cookie()
  • Body - ctx.body(), ctx.json(), ctx.formData(), ctx.text(), ctx.arrayBuffer(), ctx.blob()
  • URL Information - ctx.url, ctx.pathname

Response Utilities

Send responses using ctx.send:

  • ctx.send.json() - JSON responses
  • ctx.send.text() - Plain text
  • ctx.send.html() - HTML content
  • ctx.send.file() - File downloads
  • ctx.send.data() - In-memory data downloads
  • ctx.send.redirect() - Redirects
  • ctx.send.custom() - Custom responses
  • ctx.handleError() - Error handling

You can also use ctx.redirect() directly as a convenience method:

typescript
export function GET(ctx: Context): Response {
  return ctx.redirect('/new-location', 301)
  // Equivalent to: ctx.send.redirect('/new-location', 301)
}

Response Headers

Set response headers before sending:

typescript
export function GET(ctx: Context): Response {
  ctx.setHeader('X-Custom', 'value')
  ctx.setHeader('Cache-Control', 'no-cache')
  return ctx.send.json({ data: 'test' })
}

Setting Multiple Headers

Use setHeaders() to set multiple headers at once:

typescript
export function GET(ctx: Context): Response {
  ctx.setHeaders({
    'X-Custom': 'value',
    'Cache-Control': 'no-cache',
    'X-Request-ID': 'abc123'
  })
  return ctx.send.json({ data: 'test' })
}

Reading Response Headers

Access all response headers that have been set:

typescript
export function GET(ctx: Context): Response {
  ctx.setHeader('X-Custom', 'value')
  ctx.setHeader('Cache-Control', 'no-cache')
  const headers = ctx.responseHeadersMap // { 'X-Custom': 'value', 'Cache-Control': 'no-cache' }
  return ctx.send.json({ data: 'test' })
}

URL and Pathname

Get URL information directly:

  • ctx.url - Full URL string
  • ctx.pathname - Pathname portion of URL (e.g., /api/users/123)
typescript
export function GET(ctx: Context): Response {
  const fullUrl = ctx.url // 'http://localhost:8000/api/users/123?sort=name'
  const path = ctx.pathname // '/api/users/123'
  return ctx.send.json({ path, fullUrl })
}

Error Handling

Handle errors consistently using ctx.handleError():

typescript
export function GET(ctx: Context): Response {
  try {
    if (!isAuthorized) {
      return ctx.handleError(401, new Error('Unauthorized'))
    }
    return ctx.send.json({ data: 'success' })
  } catch (error) {
    return ctx.handleError(500, error as Error)
  }
}

How It Works

ctx.handleError() respects your global error handler set with router.catch():

  • If router.catch() is defined - Uses your custom error handler
  • If no error handler - Returns a simple response with the status code

Use in Middleware

Middleware can use ctx.handleError() to trigger error handling:

typescript
router.use(async (ctx, next) => {
  if (!isValid) {
    return ctx.handleError(401, new Error('Unauthorized'))
    // This will use router.catch() if defined
  }
  return await next()
})

Context Lifecycle

  1. Request arrives - Deserve creates Context with Request and URL
  2. Route matching - Route parameters extracted and added to Context
  3. Middleware execution - Context passed through middleware chain
  4. Route handler - Your handler receives Context
  5. Response sent - Context methods used to build Response

Released under the MIT License.