Servers and environment

Route requests by method and URL

Read the incoming method and URL, choose a handler, and return an explicit status and content type for every path.

Every incoming request gives you an HTTP method, a URL, and headers. Your job is to match method and pathname, then send the right status and body.

Parse request.url against a base URL so pathname and query string stay separate:

import { createServer } from 'node:http'

function sendJson(response, status, value, headers = {}) {
  response.writeHead(status, {
    'content-type': 'application/json; charset=utf-8',
    ...headers,
  })
  response.end(JSON.stringify(value))
}

const server = createServer((request, response) => {
  const url = new URL(request.url, 'http://localhost')

  if (url.pathname === '/notes' && request.method === 'GET') {
    return sendJson(response, 200, { notes: [] })
  }

  if (url.pathname === '/notes') {
    return sendJson(
      response,
      405,
      { error: 'Method not allowed' },
      { allow: 'GET, POST' }
    )
  }

  return sendJson(response, 404, { error: 'Not found' })
})

Match both method and pathname. A query like /notes?limit=10 still has pathname /notes. Read url.searchParams separately and validate every value.

Use status codes that describe what went wrong:

  • 404 Not Found: no route for this pathname
  • 405 Method Not Allowed: the pathname exists, but not for this method
  • 400 Bad Request: the route exists, but the input is invalid

A 405 response should include an Allow header listing supported methods. Return immediately after you end a response so later code cannot write headers or a second body.

Set Content-Type on success and error responses. JSON should include charset=utf-8. Do not return an HTML stack trace to an API client.

Routing picks a handler. It does not check authorization. A valid match on /notes/42 still needs a permission check before you return that note.

Unexpected handler failures need a final error boundary. Log details on the server and return a generic 500 only if headers have not been sent yet. Once a streamed response has started, closing the response may be the only safe recovery.

Try this on your own project: add POST /notes, validate one query parameter, and send requests that hit 200, 400, 404, and 405. Check each status code, body content type, and Allow header.

Lesson completed