# Routing & Serving

The `HttpRouter` module is the low-level, hand-written way to build an HTTP server with
Effect. You register routes (method + path + handler) into a router `Layer`, then hand the
finished router to a platform server with `HttpRouter.serve`, or turn it into a Web
`fetch` handler with `HttpRouter.toWebHandler`.
**Router vs HttpApi:** `HttpRouter` is great for webhooks, ad-hoc endpoints, and full manual control. If you
  want a schema-first, fully-typed API with a generated client and OpenAPI, reach for the
  [HttpApi](https://effect.plants.sh/http-api/) modules instead — they build on top of this router.

All of the routing and serving APIs are **unstable** and // Each route is a Layer that registers itself with the current HttpRouter.
const HelloRoute = HttpRouter.add(
  "GET",
  "/hello",
  // A handler can be a plain HttpServerResponse, an Effect of one, or a
  // function from the request to an Effect of one.
  Effect.succeed(HttpServerResponse.text("Hello, World!"))
)

const HealthRoute = HttpRouter.add(
  "GET",
  "/health",
  HttpServerResponse.json({ status: "ok" })
)

// Merge the route layers into the application layer.
export const App = Layer.mergeAll(HelloRoute, HealthRoute)
```

### HTTP methods and path patterns

The method is one of `"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS"`, or `"*"` to
match any method. Paths must be **absolute** (begin with `/`) or the bare wildcard `"*"`.

- `"/users"` — exact match.
- `"/users/:id"` — captures a path parameter named `id`.
- `"/files/*"` — wildcard; a path ending in `/*` also matches the prefix itself
  (`/files` matches too).

```ts
const UserRoute = HttpRouter.add(
  "GET",
  "/users/:id",
  // The handler form that receives the request directly.
  (request) =>
    Effect.gen(function* () {
      // Read the captured ":id" param from RouteContext.
      const { id } = yield* HttpRouter.params
      return HttpServerResponse.text(`user ${id} from ${request.url}`)
    })
)
```
**Tip:** `HEAD` requests automatically fall back to the matching `GET` route, so you usually do
  not register `HEAD` routes yourself.

### Using the router service directly

`HttpRouter.add` / `addAll` are convenience layers built on `HttpRouter.use`, which gives
you the `HttpRouter` service so you can add several routes inside one `Effect.gen`:

```ts
const App = Layer.effectDiscard(
  Effect.gen(function* () {
    const router = yield* HttpRouter.HttpRouter

    yield* router.add("GET", "/", HttpServerResponse.text("home"))
    yield* router.add("POST", "/echo", (request) =>
      Effect.map(request.text, (body) => HttpServerResponse.text(body))
    )
  })
)
```

### Batch registration with `addAll` and `route`

Use `HttpRouter.route` to build standalone `Route` values, then register them all at once
with `HttpRouter.addAll`. You can also pass a `{ prefix }` option to mount the whole batch
under a path.

```ts
const ApiRoutes = HttpRouter.addAll(
  [
    HttpRouter.route("GET", "/users", HttpServerResponse.text("list users")),
    HttpRouter.route("POST", "/users", HttpServerResponse.text("create user"))
  ],
  { prefix: "/api" } // -> GET /api/users, POST /api/users
)
```

## Reading route params

Handlers read captured path params, query params, and the request body through the
`HttpRouter` schema helpers. Each decodes with a `Schema`, so you get parsed, typed values
and a `Schema.SchemaError` (mapped to a `400`) when input is invalid.

```ts
// :id is a string in the URL; Schema coerces and validates it as a number.
const GetUser = HttpRouter.add(
  "GET",
  "/users/:id",
  Effect.gen(function* () {
    const { id } = yield* HttpRouter.schemaPathParams(
      Schema.Struct({ id: Schema.FiniteFromString })
    )
    // HttpServerResponse.json returns an Effect (it can fail to serialize),
    // so yield* it to get the response.
    return yield* HttpServerResponse.json({ id })
  })
)
```

- `params` — raw `Record<string, string | undefined>` of path params (no decoding).
- `schemaPathParams` — decode the path params only.
- `schemaParams` — decode path **and** search params merged together (path wins on a key
  clash).
- `schemaNoBody` — decode method, url, headers, cookies, path params, and search params,
  without reading the body.
- `schemaJson` — decode all of the above **plus** the parsed JSON body.

```ts
const CreateUser = HttpRouter.add(
  "POST",
  "/users",
  Effect.gen(function* () {
    // Pull the typed JSON body out of the request.
    const decoded = yield* HttpRouter.schemaJson(
      Schema.Struct({
        body: Schema.Struct({
          name: Schema.String,
          age: Schema.Number
        })
      })
    )
    return yield* HttpServerResponse.json({ created: decoded.body.name })
  })
)
```

## Prefixing & composition

Mount a group of routes under a shared path. `addAll(..., { prefix })` is the common path;
under the hood it uses `router.prefixed`, `prefixPath`, and `prefixRoute`.

```ts
// Mount each batch under its own prefix and merge.
const v1 = HttpRouter.addAll(
  [HttpRouter.route("GET", "/ping", HttpServerResponse.text("v1 pong"))],
  { prefix: "/v1" }
)
const v2 = HttpRouter.addAll(
  [HttpRouter.route("GET", "/ping", HttpServerResponse.text("v2 pong"))],
  { prefix: "/v2" }
)
```
**Caution:** When a route is matched through a prefix, the matched prefix is stripped from
  `HttpServerRequest.url` before the handler runs, so handlers see the path relative to
  their mount point.

## Router-level middleware

Router middleware wraps the response effect of the routes it is provided to. Unlike the
`serve` middleware (which wraps the whole server chain and cannot change the sent response),
router middleware can **provide services to handlers**, handle configured errors, and modify
the response.

```ts
class CurrentSession extends Context.Service<CurrentSession, {
  readonly token: string
}>()("CurrentSession") {}

// Middleware that provides CurrentSession to the routes it wraps.
const SessionMiddleware = HttpRouter.middleware<{
  provides: CurrentSession
}>()(
  Effect.succeed((httpEffect) =>
    Effect.provideService(httpEffect, CurrentSession, { token: "dummy-token" })
  )
).layer

const Route = HttpRouter.add(
  "GET",
  "/me",
  Effect.gen(function* () {
    const session = yield* CurrentSession
    return HttpServerResponse.text(`token: ${session.token}`)
  })
).pipe(Layer.provide(SessionMiddleware))
```

Pass `{ global: true }` to `middleware` to apply it to **every** route in the router. The
two most common globals have dedicated helpers: `HttpRouter.cors` and
`HttpRouter.disableLogger`.

```ts
// Apply CORS to all routes.
const Cors = HttpRouter.cors({ allowedOrigins: ["https://example.com"] })
```

### `provideRequest` — provide a Layer per request

`HttpRouter.provideRequest` adapts a normal `Layer` so its services are provided to the
routes during request handling, satisfying their request-level requirements.

```ts
class Db extends Context.Service<Db, { readonly url: string }>()("Db") {}
const DbLive = Layer.succeed(Db)({ url: "postgres://localhost" })

const Route = HttpRouter.add(
  "GET",
  "/db",
  Effect.map(Db, (db) => HttpServerResponse.text(db.url))
).pipe(HttpRouter.provideRequest(DbLive))
```

## Serving on a platform server

`HttpRouter.serve` turns the application `Layer` into a server `Layer`. It still requires the
`HttpServer` service, which is provided by a host-specific platform layer. Provide
`NodeHttpServer.layer` or `BunHttpServer.layer` and launch it.

```ts
const App = HttpRouter.add(
  "GET",
  "/",
  HttpServerResponse.text("Hello from Node!")
)

const ServerLayer = HttpRouter.serve(App).pipe(
  Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
)

Layer.launch(ServerLayer).pipe(NodeRuntime.runMain)
```

  ```ts
const App = HttpRouter.add(
  "GET",
  "/",
  HttpServerResponse.text("Hello from Bun!")
)

const ServerLayer = HttpRouter.serve(App).pipe(
  Layer.provide(BunHttpServer.layer({ port: 3000 }))
)

Layer.launch(ServerLayer).pipe(BunRuntime.runMain)
```

  By default `serve` installs the request logger and logs the listening address. Disable
those with the `disableLogger` and `disableListenLog` options. The `middleware` option wraps
the whole server chain.
**Note:** See [Platform](https://effect.plants.sh/platform/) for the full set of host adapters and which services each
  platform layer provides.

## Serving as a Web `fetch` handler

For serverless / edge runtimes, `HttpRouter.toWebHandler` builds a `(request: Request) =>
Promise<Response>` handler plus a `dispose` function for the layer scope. Provide
`HttpServer.layerServices` so the platform-neutral services (`HttpPlatform`, `Path`, ETag,
no-op `FileSystem`) are available.

```ts
const App = HttpRouter.add(
  "GET",
  "/",
  HttpServerResponse.text("Hello from fetch!")
).pipe(Layer.provide(HttpServer.layerServices))

export const { handler, dispose } = HttpRouter.toWebHandler(App)

// const response = await handler(new Request("http://localhost/"))
// => Response with body "Hello from fetch!"
```

---

## HttpRouter reference

The `HttpRouter` module, exhaustively. Import from `effect/unstable/http`.

### `HttpRouter`

The service tag (a `Context.Service`) for the router being assembled. Use
`yield* HttpRouter.HttpRouter` inside a layer effect to get the router and call `add` /
`addAll` / `prefixed` on it.

```ts
const useRouter = Effect.gen(function* () {
  const router = yield* HttpRouter.HttpRouter
  yield* router.add("GET", "/", HttpServerResponse.text("ok"))
})
```

### `make`

Effect that constructs a fresh, empty `HttpRouter` service. Used internally by `layer`; you
rarely call it directly.

```ts
const router = HttpRouter.make
// => Effect<HttpRouter, never, RouterConfig>
```

### `layer`

A `Layer` that provides a newly constructed `HttpRouter`. `serve` and `toWebHandler`
include it for you.

```ts
const RouterLayer = HttpRouter.layer
// => Layer<HttpRouter>
```

### `route`

Builds a standalone `Route` value from a method, path, and handler (without registering it).
Feed an array of routes to `addAll`.

```ts
const r = HttpRouter.route("GET", "/ping", HttpServerResponse.text("pong"))
// => Route<never, never>
```

### `add`

Layer that registers a single route. Accepts a static response, an Effect of a response, or
a function from the request to an Effect of a response. Optional `{ uninterruptible }` keeps
the handler from being made interruptible.

```ts
const Route = HttpRouter.add(
  "GET",
  "/hello",
  Effect.succeed(HttpServerResponse.text("Hello, World!"))
)
// => Layer<never, never, HttpRouter | ...>
```

### `addAll`

Layer that registers many routes at once. Accepts an array of `Route` (or an Effect that
produces one) and an optional `{ prefix }` that mounts them all under a path.

```ts
const Routes = HttpRouter.addAll(
  [HttpRouter.route("GET", "/a", HttpServerResponse.text("a"))],
  { prefix: "/v1" }
)
// => registers GET /v1/a
```

### `use`

Builds a route-registration `Layer` from a function that receives the `HttpRouter` service.
The building block behind `add` and `addAll`.

```ts
const Route = HttpRouter.use((router) =>
  router.add("GET", "/", HttpServerResponse.text("home"))
)
// => Layer<never, never, HttpRouter>
```

### `middleware`

Creates route-scoped (default) or global (`{ global: true }`) middleware. The type
parameters `provides` / `handles` declare which services the middleware adds to handlers and
which errors it handles. `.layer` is the layer you provide to routes; `.combine` composes
two middlewares.

```ts
// Wrap CORS as router middleware.
const Cors = HttpRouter.middleware(HttpMiddleware.cors()).layer
// => Layer<...> to Layer.provide onto routes
```

### `prefixPath`

Pure helper that prefixes a path string. Trailing slashes are trimmed from the prefix;
`"/"` becomes the prefix itself and `"*"` becomes a wildcard under the prefix. Dual.

```ts
HttpRouter.prefixPath("/users", "/api") // => "/api/users"
HttpRouter.prefixPath("*", "/api")      // => "/api/*"
```

### `prefixRoute`

Returns a copy of a `Route` with its path prefixed, also tracking the prefix so it can be
stripped from the request URL at handle time. Dual.

```ts
const base = HttpRouter.route("GET", "/ping", HttpServerResponse.text("pong"))
const prefixed = HttpRouter.prefixRoute(base, "/api")
// => Route matching GET /api/ping
```

### `provideRequest`

Adapts a `Layer` so its services are provided to routes during request handling, satisfying
their request-level requirements.

```ts
class Db extends Context.Service<Db, { readonly url: string }>()("Db") {}

const Route = HttpRouter.add("GET", "/db", Effect.map(Db, (db) =>
  HttpServerResponse.text(db.url)
)).pipe(HttpRouter.provideRequest(Layer.succeed(Db)({ url: "..." })))
```

### `cors`

Global CORS middleware layer. Options: `allowedOrigins`, `allowedMethods`,
`allowedHeaders`, `exposedHeaders`, `maxAge`, `credentials`.

```ts
const Cors = HttpRouter.cors({
  allowedOrigins: ["https://example.com"],
  credentials: true
})
// => Layer<never, never, HttpRouter>
```

### `disableLogger`

A middleware layer that disables the request logger for the routes it is provided to.

```ts
const Route = HttpRouter.add(
  "GET",
  "/quiet",
  HttpServerResponse.text("shh")
).pipe(Layer.provide(HttpRouter.disableLogger))
```

### `params`

Effect returning the raw captured path params for the current matched route.

```ts
const eff = HttpRouter.params
// => Effect<ReadonlyRecord<string, string | undefined>, never, RouteContext>
// for GET /users/:id matching /users/42 => { id: "42" }
```

### `schemaParams`

Decodes a `Schema` from the merged search params and path params (path wins on a clash).

```ts
const decode = HttpRouter.schemaParams(
  Schema.Struct({ id: Schema.FiniteFromString, q: Schema.optional(Schema.String) })
)
// for /users/42?q=hi => { id: 42, q: "hi" }
```

### `schemaPathParams`

Decodes a `Schema` from the path params only.

```ts
const decode = HttpRouter.schemaPathParams(
  Schema.Struct({ id: Schema.FiniteFromString })
)
// for /users/42 => { id: 42 }
```

### `schemaJson`

Decodes a `Schema` from the full request envelope **including** the parsed JSON body
(`method`, `url`, `headers`, `cookies`, `pathParams`, `searchParams`, `body`). Fails with
`HttpServerError` if the body cannot be parsed, or `Schema.SchemaError` on decode failure.

```ts
const decode = HttpRouter.schemaJson(
  Schema.Struct({ body: Schema.Struct({ name: Schema.String }) })
)
// for POST {"name":"Ada"} => { body: { name: "Ada" } }
```

### `schemaNoBody`

Like `schemaJson` but never reads the request body — decodes `method`, `url`, `headers`,
`cookies`, `pathParams`, and `searchParams`.

```ts
const decode = HttpRouter.schemaNoBody(
  Schema.Struct({ headers: Schema.Struct({ "x-trace": Schema.String }) })
)
// reads the x-trace header without consuming the body
```

### `RouteContext`

The `Context.Service` holding the matched `route` and its captured `params`. The schema
helpers and `params` read from it; you can also access it directly.

```ts
const Route = HttpRouter.add("GET", "/u/:id", Effect.gen(function* () {
  const ctx = yield* HttpRouter.RouteContext
  return HttpServerResponse.text(`${ctx.route.path} -> ${ctx.params.id}`)
  // => "/u/:id -> 7" for /u/7
}))
```

### `RouterConfig`

A `Context.Reference` for low-level route-matcher configuration, defaulting to `{}`. Override
it via the `routerConfig` option on `serve` / `toWebHandler`, or by providing it as a layer.

```ts
const config = HttpRouter.RouterConfig
// => Context.Reference<Partial<FindMyWay.RouterConfig>>
```

### `serve`

Turns an application `Layer` into a server `Layer`. Requires `HttpServer` (provided by a
platform layer). Options: `routerConfig`, `disableLogger`, `disableListenLog`, and
`middleware` (wraps the whole server chain).

```ts
const App = HttpRouter.add("GET", "/", HttpServerResponse.text("ok"))

const ServerLayer = HttpRouter.serve(App, { disableListenLog: true }).pipe(
  Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
)
```

### `toHttpEffect`

Builds the application `Layer` and returns the router as a single handler `Effect`
(`HttpServerResponse` from `HttpServerRequest` + `Scope`). Useful for embedding the router
into a larger server effect.

```ts
const App = HttpRouter.add("GET", "/", HttpServerResponse.text("ok"))

const handlerEffect = HttpRouter.toHttpEffect(App)
// => Effect<Effect<HttpServerResponse, ..., Scope | HttpServerRequest | ...>, ...>
```

### `toWebHandler`

Builds a Web `fetch`-compatible handler (`(request: Request) => Promise<Response>`) plus a
`dispose` function. Options: `memoMap`, `routerConfig`, `disableLogger`, `middleware`.

```ts
const App = HttpRouter.add("GET", "/", HttpServerResponse.text("ok")).pipe(
  Layer.provide(HttpServer.layerServices)
)

export const { handler, dispose } = HttpRouter.toWebHandler(App)
// const res = await handler(new Request("http://x/")) // => 200 "ok"
```

### `Route` / `Route.Error` / `Route.Context`

`Route<E, R>` is the description of a registered route (method, path, handler, prefix,
interruptibility). `Route.Error<R>` and `Route.Context<T>` extract a route's error and
requirement types at the type level.

```ts
const r = HttpRouter.route("GET", "/", HttpServerResponse.text("x"))
type E = HttpRouter.Route.Error<typeof r>     // => never
type R = HttpRouter.Route.Context<typeof r>   // => never
```

### `PathInput`

The path type accepted by the router: `` `/${string}` `` or `"*"`.

```ts
const path: HttpRouter.PathInput = "/users/:id"
```

---

## HttpServer reference

The runtime that actually listens for connections and supplies `HttpServerRequest` per
request. Platform packages implement it; you typically consume it through `HttpRouter.serve`.

### `HttpServer`

The service tag. Exposes `serve` (run a response effect per request) and `address` (where it
is listening).

```ts
const addr = Effect.map(HttpServer.HttpServer, (s) => s.address)
// => Effect<Address, never, HttpServer>
```

### `make`

Constructs an `HttpServer` service from a `serve` implementation and an `address`. Used by
platform adapters.

```ts
const service = HttpServer.make({
  serve: (_httpEffect, _middleware) => Effect.void,
  address: { _tag: "TcpAddress", hostname: "127.0.0.1", port: 3000 }
})
```

### `serve`

Creates a `Layer` that starts serving a response effect with the current `HttpServer`. The
request service is supplied by the server; an optional middleware is applied at the server
boundary. (`HttpRouter.serve` wraps this for router layers.)

```ts
const ServeLayer = HttpServer.serve(
  HttpServerResponse.text("hello")
)
// => Layer<never, never, HttpServer | ...>
```

### `serveEffect`

Like `serve` but returns an `Effect` (requiring `Scope`) instead of a `Layer`.

```ts
const eff = HttpServer.serveEffect(HttpServerResponse.text("hi"))
// => Effect<void, never, Scope | HttpServer | ...>
```

### `formatAddress`

Formats an `Address` as a display string: TCP becomes `http://host:port`, Unix becomes
`unix://path`.

```ts
HttpServer.formatAddress({ _tag: "TcpAddress", hostname: "localhost", port: 3000 })
// => "http://localhost:3000"
```

### `addressFormattedWith`

Reads the current server address, formats it, and passes the string to your effectful
function.

```ts
const log = HttpServer.addressFormattedWith((url) => Effect.log(`up at ${url}`))
// => Effect<void, never, HttpServer>
```

### `logAddress`

Effect that logs `Listening on <formatted address>` for the current server.

```ts
const eff = HttpServer.logAddress
// => logs e.g. "Listening on http://localhost:3000"
```

### `withLogAddress`

Wraps a server-providing `Layer` so it logs the listening address on startup. `serve`
applies this by default unless `disableListenLog` is set.

```ts
const ServerLayer = HttpServer.withLogAddress(
  NodeHttpServer.layer(createServer, { port: 3000 })
)
```

### `makeTestClient`

Builds an `HttpClient` whose requests are prepended with the running server's URL (and
`0.0.0.0` rewritten to `127.0.0.1`). TCP only — Unix sockets are not supported.

```ts
const clientEffect = HttpServer.makeTestClient
// => Effect<HttpClient, never, HttpServer | HttpClient>
```

### `layerTestClient`

Layer that provides the test `HttpClient` from `makeTestClient`.

```ts
const TestClient = HttpServer.layerTestClient
// => Layer<HttpClient, never, HttpServer | HttpClient>
```

### `layerServices`

Layer bundling the platform-neutral services HTTP servers commonly need: `HttpPlatform`,
`Path`, a weak ETag generator, and a no-op `FileSystem`. Provide it to `toWebHandler` apps.

```ts
const Services = HttpServer.layerServices
// => Layer<Path | HttpPlatform | FileSystem | Etag.Generator>
```

### `Address` / `TcpAddress` / `UnixAddress`

`Address` is the union `TcpAddress | UnixAddress`. `TcpAddress` has `hostname` and `port`;
`UnixAddress` has `path`. Both carry a `_tag` discriminator.

```ts
const tcp: HttpServer.TcpAddress = { _tag: "TcpAddress", hostname: "0.0.0.0", port: 3000 }
const unix: HttpServer.UnixAddress = { _tag: "UnixAddress", path: "/tmp/app.sock" }
```

---

## Web handler interop (`HttpEffect`)

`HttpRouter.toWebHandler` delegates to the lower-level `HttpEffect` module, which you can use
directly to bridge Effect HTTP programs and Web-standard `Request` / `Response`. Import from
`effect/unstable/http`.

### `HttpEffect.toWebHandler`

Converts an HTTP server effect (requiring only `HttpServerRequest | Scope`) into a
`(request: Request) => Promise<Response>` handler with an empty base context.

```ts
const app = Effect.succeed(HttpServerResponse.text("ok"))
const handler = HttpEffect.toWebHandler(app)
// const res = await handler(new Request("http://x/")) // => 200 "ok"
```

### `HttpEffect.toWebHandlerWith`

Same as `toWebHandler` but you supply a base `Context` whose services are available to every
request.

```ts
const handlerFactory = HttpEffect.toWebHandlerWith(Context.empty())
const handler = handlerFactory(Effect.succeed(HttpServerResponse.text("ok")))
```

### `HttpEffect.toWebHandlerLayer`

Builds a web handler whose services come from a `Layer`, returning `{ handler, dispose }`.
Call `dispose` to release the layer scope at shutdown.

```ts
const { handler, dispose } = HttpEffect.toWebHandlerLayer(
  Effect.succeed(HttpServerResponse.text("ok")),
  HttpServer.layerServices
)
```

### `HttpEffect.toWebHandlerLayerWith`

The most general form: a `Layer` plus a `toHandler` factory that builds the response effect
from the layer's context. `HttpRouter.toWebHandler` is implemented with this.

```ts
const { handler, dispose } = HttpEffect.toWebHandlerLayerWith(
  HttpServer.layerServices,
  { toHandler: () => Effect.succeed(Effect.succeed(HttpServerResponse.text("ok"))) }
)
```

### `HttpEffect.fromWebHandler`

The inverse: embeds an existing Web-standard handler inside an Effect HTTP server, producing
an `HttpServerResponse` for the current `HttpServerRequest`.

```ts
const eff = HttpEffect.fromWebHandler(
  async (_req) => new Response("from web handler")
)
// => Effect<HttpServerResponse, HttpServerError, HttpServerRequest>
```

### `HttpEffect.PreResponseHandler`

The type of a function run with the current request and response just before the response is
sent; it may replace the response or fail with `HttpServerError`.

```ts
const handler: HttpEffect.PreResponseHandler = (_request, response) =>
  Effect.succeed(HttpServerResponse.setHeader(response, "x-served-by", "effect"))
```

### `HttpEffect.appendPreResponseHandler`

Registers a pre-response handler for the current request. Runs before the bytes are sent (not
after a streaming body starts).

```ts
const eff = HttpEffect.appendPreResponseHandler((_req, res) =>
  Effect.succeed(HttpServerResponse.setHeader(res, "x-app", "demo"))
)
// => Effect<void, never, HttpServerRequest>
```

### `HttpEffect.withPreResponseHandler`

Runs an effect after registering a pre-response handler for the current request. Dual.

```ts
const eff = HttpEffect.withPreResponseHandler(
  Effect.succeed(HttpServerResponse.text("ok")),
  (_req, res) => Effect.succeed(HttpServerResponse.setHeader(res, "x-app", "demo"))
)
```

---

## Server errors reference

Failures raised by the server runtime live in `HttpServerError`. Import from
`effect/unstable/http`.

### `HttpServerError`

The wrapper tagged error (`_tag: "HttpServerError"`). It carries a `reason` and exposes
`request` and optional `response`, and is `Respondable` so it can convert itself to an HTTP
response.

```ts
declare const u: unknown
if (HttpServerError.isHttpServerError(u)) {
  // u.reason, u.request, u.response
}
```

### `isHttpServerError`

Refinement predicate for `HttpServerError`.

```ts
HttpServerError.isHttpServerError(new Error("x")) // => false
```

### `RouteNotFound`

Reason raised when no route matched. Converts to an empty `404` and is ignored by the error
reporter.

```ts
declare const request: any
const reason = new HttpServerError.RouteNotFound({ request })
// => 404
```

### `RequestParseError`

Reason for a failure to parse or read the incoming request. Converts to an empty `400`.

```ts
declare const request: any
const reason = new HttpServerError.RequestParseError({ request, description: "bad body" })
// => 400
```

### `ResponseError`

Reason tied to a response that was being built or sent; carries both `request` and
`response`. Converts to an empty `500` (it does not reuse the failed response, which may be
partly sent).

```ts
declare const request: any
declare const response: any
const reason = new HttpServerError.ResponseError({ request, response })
// => 500
```

### `InternalError`

Reason for an unexpected server-side failure while handling a request. Converts to an empty
`500`.

```ts
declare const request: any
const reason = new HttpServerError.InternalError({ request, cause: new Error("boom") })
// => 500
```

### `ServeError`

Tagged error wrapping a low-level failure from the server implementation itself (outside an
individual handler response) — e.g. the port could not be bound.

```ts
const err = new HttpServerError.ServeError({ cause: new Error("EADDRINUSE") })
```

### `ClientAbort`

A context annotation marking an interrupt as caused by the client aborting the request.
`causeResponse` maps it to a `499` instead of a server-abort `503`.

```ts
const annotation = HttpServerError.ClientAbort.annotation
// used to annotate an interrupt => maps to 499
```

### `RequestError` / `HttpServerErrorReason`

Type aliases: `RequestError = RequestParseError | RouteNotFound | InternalError`, and
`HttpServerErrorReason = RequestError | ResponseError` — the value carried as the `reason` of
an `HttpServerError`.

```ts
declare const reason: HttpServerError.HttpServerErrorReason
```

### `causeResponse`

Converts a failed handler `Cause` into the `[response, cause]` pair to send and report.
Respondable failures choose their own response; pure interrupts become `499` (client abort)
or `503` (server abort); everything else defaults to `500`.

```ts
const eff = HttpServerError.causeResponse(Cause.die("boom"))
// => Effect<[HttpServerResponse (500), Cause]>
```

### `exitResponse`

Extracts the `HttpServerResponse` from a successful handler `Exit`, or derives one
(stripping any embedded response defect, else `500`) from the failure cause.

```ts
const res = HttpServerError.exitResponse(Exit.succeed(HttpServerResponse.text("ok")))
// => HttpServerResponse "ok"
```

---

## Where to next

- [HttpApi](https://effect.plants.sh/http-api/) — schema-first APIs with typed clients and OpenAPI, built on this
  router.
- [HTTP Client](https://effect.plants.sh/http-client/) — make outbound requests (and test your server).
- [Platform](https://effect.plants.sh/platform/) — the host adapters (`NodeHttpServer`, `BunHttpServer`) that provide
  the `HttpServer` service.