Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

HttpMiddleware unstable

Wraps HTTP server apps with request and response behavior.

A middleware is a function from one HTTP server app effect to another. The app runs with the current HttpServerRequest in its context, so middleware can inspect or rewrite the request, provide request-scoped services, attach hooks before the response is sent, or observe the app exit. This module includes middleware for response logging, server tracing, forwarded proxy headers, parsed search parameters, and CORS response headers.

15 exports Since v4.0.0 Source

Compression

compression

unstable
Since v4.0.0

Middleware that compresses HTTP response bodies based on the request's Accept-Encoding header.

Details

Content negotiation follows RFC 9110: the first algorithm in server preference order that the client accepts with a positive q-value and the platform supports is used. When no algorithm is acceptable the response is sent uncompressed.

The body transform is performed by the HttpPlatform service.

Responses are skipped when the status is 1xx, 204, 206, or 304, when a Content-Encoding is already present, when Cache-Control: no-transform is set, when the content type is absent or not compressible, when a known body length is below minSize, or when the body is empty or FormData. A response carrying Content-Encoding: identity opts out of compression and has the header stripped before sending.

Vary: Accept-Encoding is set on every response that was eligible by status and content type, including ones skipped by negotiation or minSize.

Do not combine this middleware with Deno's automatic response compression. On edge runtimes that already apply automatic compression, the middleware is unnecessary. Platforms backed by Web CompressionStream also cannot explicitly flush each input chunk, so incremental delivery depends on the runtime's implementation.

Gotchas

Compression can expose secrets through BREACH-style attacks when one response contains both secret data and attacker-controlled input and an attacker can observe the compressed response length. For affected routes, disable compression with Content-Encoding: identity or Cache-Control: no-transform, or use compressible to restrict which response content types can be compressed.

Signature

declare function compression(options?: {
readonly algorithms?: readonly Array<CompressionAlgorithm>;
readonly compressible?: (contentType: string) => boolean;
readonly levels?: {
readonly br?: number;
readonly deflate?: number;
readonly gzip?: number;
readonly zstd?: number;
};
readonly minSize?: number;
}): <E, R>(httpApp: Effect<HttpServerResponse, E, R>) => Effect<HttpServerResponse, E, HttpServerRequest | HttpPlatform | R>
Since v4.0.0

Middleware that decompresses request bodies sent with a Content-Encoding of gzip or deflate.

Details

The request service is replaced with a view whose body accessors (stream, text, json, arrayBuffer, urlParamsBody, multipart) yield the decompressed body, and whose headers no longer include Content-Encoding or Content-Length. Decompression is lazy and only happens when the body is read. Stacked codings such as deflate, gzip are undone in reverse order, and identity members are ignored.

Requests whose Content-Encoding includes any other coding are rejected with 415 Unsupported Media Type and Accept-Encoding: gzip, deflate, without running the app. Malformed compressed data fails the body read with a RequestParseError, or a MultipartError with reason Parse when reading multipart data.

The decompressed size is limited to maxDecompressedSize, falling back to the MaxBodySize reference and then to 10 MiB. Exceeding it fails the body read with a RequestParseError, or a MultipartError with reason BodyTooLarge when reading multipart data. The limit applies to every body accessor, including stream.

Decompression uses the global DecompressionStream. deflate means the zlib format (RFC 1950); raw deflate data is rejected.

Gotchas

request.source is still the original, compressed request. HttpServerRequest.toWeb returns that compressed request only when the source is a Web Request. On other platforms, such as Node, it builds a new Request from the decompressed body and the stripped headers.

Signature

declare function decompression(options?: {
readonly maxDecompressedSize?: Input;
}): <E, R>(httpApp: Effect<HttpServerResponse, E, R>) => Effect<HttpServerResponse, E, HttpServerRequest | R>

Constructors

make

unstable
Since v4.0.0

Defines an HttpMiddleware while preserving its precise type.

Signature

declare function make<M extends HttpMiddleware>(middleware: M): M

Layers

Creates a layer that disables server-side tracing for requests whose URL exactly matches one of the supplied URLs.

Signature

declare function layerTracerDisabledForUrls(urls: readonly Array<string>): Layer<never>

Logging

logger

unstable
Since v4.0.0

Middleware that logs sent HTTP responses with request method, request URL, and response status annotations.

Signature

declare const logger: <E, R>(httpApp: Effect.Effect<HttpServerResponse, E, HttpServerRequest | R>) => Effect.Effect<HttpServerResponse, E, HttpServerRequest | R>
Since v4.0.0

Runs an effect with HTTP response logging disabled for the current server request.

Signature

declare function withLoggerDisabled<A, E, R>(self: Effect<A, E, R>): Effect<A, E, HttpServerRequest | R>

Middleware

cors

unstable
Since v4.0.0

Middleware that handles CORS preflight requests and adds configured CORS headers to HTTP responses.

Signature

declare function cors(options?: {
readonly allowedHeaders?: readonly Array<string>;
readonly allowedMethods?: readonly Array<string>;
readonly allowedOrigins?: readonly Array<string> | Predicate<string>;
readonly credentials?: boolean;
readonly exposedHeaders?: readonly Array<string>;
readonly maxAge?: number;
}): <E, R>(httpApp: Effect<HttpServerResponse, E, R>) => Effect<HttpServerResponse, E, HttpServerRequest | R>

Models

HttpMiddleware

interface unstable
Since v4.0.0

Middleware that transforms an HTTP server app effect into another HTTP server app effect.

Signature

interface HttpMiddleware {
<E, R>(self: Effect<HttpServerResponse, E, HttpServerRequest | R>): Effect<HttpServerResponse, any, any>;
}

Other

Since v4.0.0

Namespace containing types associated with HttpMiddleware.

Parsing

Since v4.0.0

Middleware that parses the current request URL's search parameters and provides them as ParsedSearchParams.

Signature

declare function searchParamsParser<E, R>(httpApp: Effect<HttpServerResponse, E, R>): Effect<HttpServerResponse, E, HttpServerRequest | Exclude<R, ParsedSearchParams>>

Proxying

Since v4.0.0

Middleware that trusts X-Forwarded-Host and X-Forwarded-For, updating the request host header and remote address.

Signature

declare const xForwardedHeaders: <E, R>(httpApp: Effect<HttpServerResponse, E, HttpServerRequest | R>) => Effect<HttpServerResponse, E, HttpServerRequest | R>

Services

Since v4.0.0

Context reference for generating server span names from HTTP server requests.

Details

Defaults to the request method unchanged.

Signature

declare const SpanNameGenerator: Reference<(request: HttpServerRequest) => string>
Since v4.0.0

Context reference for a predicate that disables server-side tracing for matching requests.

Signature

declare const TracerDisabledWhen: Reference<Predicate<HttpServerRequest>>
Since v4.0.0

Context reference for filtering request and response headers added to server spans.

Details

Header capture is opt-in: the default filter records no headers. Captured headers listed in Headers.CurrentRedactedNames are recorded as <redacted>.

Signature

declare const TracerHeaderFilter: Reference<(headerName: string, phase: "request" | "response") => boolean>

Tracing

tracer

unstable
Since v4.0.0

Middleware that creates a server trace span for each request and records request and response HTTP attributes.

Signature

declare const tracer: <E, R>(httpApp: Effect.Effect<HttpServerResponse, E, HttpServerRequest | R>) => Effect.Effect<HttpServerResponse, E, HttpServerRequest | R>