Skip to content

HttpRouter

Builds server-side routers for Effect HTTP applications.

HttpRouter collects routes and middleware while an application layer is being built. Once the router is complete, it handles each HttpServerRequest by finding a matching route and producing an HttpServerResponse. The module also includes helpers for route definitions, prefixes, parameters, request decoding, CORS, and running the router.

33 exports Added in v4.0.0 Source

Constructors

make

Added in v4.0.0 Source

Constructs an empty HttpRouter service.

Details

The returned router accepts route and middleware registrations and later routes the current HttpServerRequest to the matching HttpServerResponse.

Signature

declare const make: Effect<HttpRouter, never, never>;

Converting

toHttpEffect

Added in v4.0.0 Source

Builds an application layer with a router and returns the router as an HTTP handler effect.

Details

The returned effect handles the current HttpServerRequest in the current Scope; route request markers are converted into the ordinary requirements of the returned handler.

Signature

declare function toHttpEffect<A, E, R>(
  appLayer: Layer<A, E, R>,
): Effect<
  Effect<
    HttpServerResponse,
    HttpServerError | Only<"Error", R> | Only<"GlobalRequires", R>,
    Scope | HttpServerRequest | Only<"GlobalRequires", R> | Only<"Requires", R>
  >,
  Without<E>,
  Scope | Exclude<Without<R>, HttpRouter>
>;

toWebHandler

Added in v4.0.0 Source

Builds a Fetch-compatible request handler from an HTTP router application layer.

Details

The result contains a handler function that converts Web Request values to Web Response values and a dispose function for releasing the layer resources.

Signature

declare function toWebHandler<
  A,
  E,
  R extends
    | HttpRouter
    | Request<"Requires", any>
    | Request<"Error", any>
    | Request<"GlobalRequires", any>
    | Request<"GlobalError", any>,
  HE,
  HR = Exclude<Only<"Requires", R>, A> | Exclude<Only<"GlobalRequires", R>, A>,
  ReqR = Exclude<HR, Scope | HttpServerRequest | A>,
>(
  appLayer: Layer<A, E, R>,
  options?: {
    readonly disableLogger?: boolean;
    readonly memoMap?: MemoMap;
    readonly middleware?: (
      effect: Effect<
        HttpServerResponse,
        HttpServerError | Only<"Error", R> | Only<"GlobalError", R>,
        Scope | HttpServerRequest | Only<"Requires", R> | Only<"GlobalRequires", R>
      >,
    ) => Effect<HttpServerResponse, HE, GlobalProvided | HR>;
    readonly routerConfig?: Partial<RouterConfig>;
  },
): {
  readonly dispose: () => Promise<void>;
  readonly handler: [ReqR] extends [never]
    ? (request: Request, context?: Context<never>) => Promise<Response>
    : (request: Request, context: Context<ReqR>) => Promise<Response>;
};

Getters

params

Added in v4.0.0 Source

Effect that returns the path parameters captured for the current matched route.

Signature

declare const params: Effect.Effect<
  ReadonlyRecord<string, string | undefined>,
  never,
  RouteContext
>;

Layers

add

Added in v4.0.0 Source

Create a layer that adds a single route to the HTTP router.

Signature

declare function add<E = never, R = never>(method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | "OPTIONS" | "*", path: PathInput, handler: HttpServerResponse | Effect<HttpServerResponse, E, R> | (request: HttpServerRequest) => Effect<HttpServerResponse, E, R>, options?: {
  readonly uninterruptible?: boolean;
}): Layer<never, never, HttpRouter | From<"Requires", Exclude<R, Provided>> | From<"Error", E>>

addAll

Added in v4.0.0 Source

Create a layer that adds multiple routes to the HTTP router.

Signature

declare function addAll<Routes extends readonly Array<Route<any, any>>, EX = never, RX = never>(routes: Routes | Effect<Routes, EX, RX>, options?: {
  readonly prefix?: string;
}): Layer<never, EX, HttpRouter | Exclude<RX, Scope> | From<"Requires", Exclude<Context<Routes[number]>, Provided>> | From<"Error", Error<Routes[number]>>>

cors

Added in v4.0.0 Source

Middleware that applies CORS headers to the HTTP response.

Signature

declare function cors(options?: {
  readonly allowedHeaders?: readonly Array<string>;
  readonly allowedMethods?: readonly Array<string>;
  readonly allowedOrigins?: readonly Array<string>;
  readonly credentials?: boolean;
  readonly exposedHeaders?: readonly Array<string>;
  readonly maxAge?: number;
}): Layer<never, never, HttpRouter>

Middleware that disables the logger for some routes.

Signature

declare const disableLogger: Layer.Layer<never>;

layer

Added in v4.0.0 Source

Layer that provides a newly constructed HttpRouter.

Signature

declare const layer: Layer.Layer<HttpRouter>;

Provides request-level dependencies to some routes.

Signature

declare function provideRequest<A2, E2, R2>(
  layer: Layer<A2, E2, R2>,
): <A, E, R>(self: Layer<A, E, R>) => Layer<A, E2 | E, R2 | Exclude<R, From<"Requires", A2>>>;

serve

Added in v4.0.0 Source

Runs the provided application layer as an HTTP server.

Signature

declare function serve<A, E, R, HE, HR = Only<"Requires", R> | Only<"GlobalRequires", R>>(
  appLayer: Layer<A, E, R>,
  options?: {
    readonly disableListenLog?: boolean;
    readonly disableLogger?: boolean;
    readonly middleware?: (
      effect: Effect<
        HttpServerResponse,
        HttpServerError | Only<"Error", R> | Only<"GlobalError", R>,
        Scope | HttpServerRequest | Only<"Requires", R> | Only<"GlobalRequires", R>
      >,
    ) => Effect<HttpServerResponse, HE, HR>;
    readonly routerConfig?: Partial<RouterConfig>;
  },
): Layer<
  A,
  Without<E>,
  HttpServer | Exclude<Without<R>, HttpRouter> | Exclude<Exclude<HR, GlobalProvided>, HttpRouter>
>;

use

Added in v4.0.0 Source

Creates a layer that accesses the current HttpRouter service and runs the supplied effect.

When to use

Use when you need to register routes or middleware with the router during layer construction.

Signature

declare function use<A, E, R>(
  f: (router: HttpRouter) => Effect<A, E, R>,
): Layer<never, E, HttpRouter | Exclude<R, Scope>>;

Middleware

middleware

Added in v4.0.0 Source

Create a middleware layer that can be used to modify requests and responses.

Details

By default, the middleware only affects the routes that it is provided to.

If you want to create a middleware that applies globally to all routes, pass the global option as true.

Signature

declare const middleware: middleware.Make<never, never> & <Config extends {
  handles?: any;
  provides?: any;
} = {}>() => middleware.Make<Config extends {
  provides: infer R;
} ? R : never, Config extends {
  handles: infer E;
} ? E : never>

Middleware interface

Added in v4.0.0 Source

Composable descriptor for route-scoped HTTP router middleware.

Details

Its layer can be provided to route layers, and combine composes middleware while tracking provided services, handled errors, and remaining requirements at the type level.

Signature

interface Middleware<
  Config extends {
    error: any;
    handles: any;
    layerError: any;
    layerRequires: any;
    provides: any;
    requires: any;
  },
> {
  readonly "~effect/http/HttpRouter/Middleware": Config;
  readonly combine: <
    Config2 extends {
      error: any;
      handles: any;
      layerError: any;
      layerRequires: any;
      provides: any;
      requires: any;
    },
  >(
    other: Middleware<Config2>,
  ) => Middleware<{
    error: Config2["error"] | Exclude<Config["error"], Config2["handles"]>;
    handles: Config2["handles"] | Config["handles"];
    layerError: Config["layerError"] | Config2["layerError"];
    layerRequires: Config["layerRequires"] | Config2["layerRequires"];
    provides: Config["provides"] | Config2["provides"];
    requires: Exclude<Config["requires"], Config2["provides"]> | Config2["requires"];
  }>;
  readonly layer: [Config["requires"]] extends [never]
    ? Layer<
        From<"Requires", Config["provides"]>,
        Config["layerError"],
        Config["layerRequires"] | From<"Requires", any[any]> | From<"Error", Config["error"]>
      >
    : "Need to .combine(middleware) that satisfy the missing request dependencies";
}

Models

PathInput type

Added in v4.0.0 Source

Path pattern accepted by the router. Routes must use an absolute path beginning with / or the wildcard *.

Signature

type PathInput = `/${string}` | "*";

Other

middleware

Added in v4.0.0 Source

Types used by the middleware constructor.

Request

Added in v4.0.0 Source

Helper types for request-level dependency markers used by router layers and middleware.

Route

Added in v4.0.0 Source

Helper types for extracting the error and context types carried by Route values.

Routes

prefixRoute

Added in v4.0.0 Source

Returns a copy of a route with its path prefixed.

Details

The prefix is also tracked on the route so that, when the route handles a request, the matched prefix can be removed from the request URL seen by the handler.

Signature

declare const prefixRoute: {
  (prefix: string): <E, R>(self: Route<E, R>) => Route<E, R>;
  <E, R>(self: Route<E, R>, prefix: string): Route<E, R>;
};

route

Added in v4.0.0 Source

Constructs a Route from an HTTP method, path, and handler.

Details

The handler may be a static response, an effect that produces a response, or a function from the current request to a response effect. Set uninterruptible to prevent the route handler from being made interruptible while it runs.

Signature

declare function route<E = never, R = never>(method: "*" | HttpMethod, path: PathInput, handler: HttpServerResponse | Effect<HttpServerResponse, E, R> | (request: HttpServerRequest) => Effect<HttpServerResponse, E, R>, options?: {
  readonly uninterruptible?: boolean;
}): Route<E, Exclude<R, Provided>>

Route interface

Added in v4.0.0 Source

Description of a registered HTTP route.

Details

A route pairs an HTTP method and path pattern with a response handler, plus metadata used for prefix handling and interruptibility.

Signature

interface Route<E = never, R = never> {
  readonly "~effect/http/HttpRouter/Route": "~effect/http/HttpRouter/Route";
  readonly handler: Effect<HttpServerResponse, E, R>;
  readonly method: "*" | HttpMethod;
  readonly path: PathInput;
  readonly prefix: Option<string>;
  readonly uninterruptible: boolean;
}

Schemas

schemaJson

Added in v4.0.0 Source

Decodes a schema from the current request and its JSON body.

Details

The input passed to the schema includes the request method, URL, headers, cookies, path parameters, search parameters, and parsed JSON body. The effect fails if the body cannot be parsed or the schema decode fails.

Signature

declare function schemaJson<
  A,
  I extends Partial<{
    readonly body: any;
    readonly cookies: Readonly<Record<string, string | undefined>>;
    readonly headers: Readonly<Record<string, string | undefined>>;
    readonly method: HttpMethod;
    readonly pathParams: Readonly<Record<string, string | undefined>>;
    readonly searchParams: Readonly<Record<string, string | ReadonlyArray<string> | undefined>>;
    readonly url: string;
  }>,
  RD,
>(
  schema: ConstraintCodec<A, I, RD, unknown>,
  options?: ParseOptions,
): Effect<
  A,
  SchemaError | HttpServerError,
  HttpServerRequest | ParsedSearchParams | RouteContext | RD
>;

schemaNoBody

Added in v4.0.0 Source

Decodes a schema from the current request without reading the request body.

Details

The input passed to the schema includes the request method, URL, headers, cookies, path parameters, and search parameters.

Signature

declare function schemaNoBody<
  A,
  I extends Partial<{
    readonly cookies: Readonly<Record<string, string | undefined>>;
    readonly headers: Readonly<Record<string, string | undefined>>;
    readonly method: HttpMethod;
    readonly pathParams: Readonly<Record<string, string | undefined>>;
    readonly searchParams: Readonly<Record<string, string | ReadonlyArray<string> | undefined>>;
    readonly url: string;
  }>,
  RD,
>(
  schema: ConstraintCodec<A, I, RD, unknown>,
  options?: ParseOptions,
): Effect<A, SchemaError, HttpServerRequest | ParsedSearchParams | RouteContext | RD>;

schemaParams

Added in v4.0.0 Source

Decodes a schema from the current route path parameters and search parameters.

Details

When the same key appears in both sources, the path parameter value is used.

Signature

declare function schemaParams<A, I extends Readonly<Record<string, string | readonly Array<string> | undefined>>, RD>(schema: ConstraintCodec<A, I, RD, unknown>, options?: ParseOptions): Effect<A, SchemaError, ParsedSearchParams | RouteContext | RD>

Decodes a schema from the path parameters captured for the current matched route.

Signature

declare function schemaPathParams<A, I extends Readonly<Record<string, string | undefined>>, RD>(
  schema: ConstraintCodec<A, I, RD, unknown>,
  options?: ParseOptions,
): Effect<A, SchemaError, RouteContext | RD>;

Services

HttpRouter

Added in v4.0.0 Source

Service tag for the HTTP router used while constructing an HTTP application. Route and middleware layers require this service to register themselves with the router.

Signature

declare const HttpRouter: Service<HttpRouter, HttpRouter>;

HttpRouter interface

Added in v4.0.0 Source

Defines the service interface for registering HTTP routes and middleware.

Details

An HttpRouter can add routes, apply path prefixes, install global middleware, and expose the registered routes as an Effect that handles the current server request.

Signature

interface HttpRouter {
  readonly "~effect/http/HttpRouter": "~effect/http/HttpRouter";
  readonly add: <E = never, R = never>(method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | "OPTIONS" | "*", path: PathInput, handler: HttpServerResponse | Effect<HttpServerResponse, E, R> | (request: HttpServerRequest) => Effect<HttpServerResponse, E, R>, options?: {
    readonly uninterruptible?: boolean;
  }) => Effect<void, never, From<"Requires", Exclude<R, Provided>> | From<"Error", E>>;
  readonly addAll: <Routes extends readonly Array<Route<any, any>>>(routes: Routes) => Effect<void, never, From<"Requires", Exclude<Context<Routes[number]>, Provided>> | From<"Error", Error<Routes[number]>>>;
  readonly addGlobalMiddleware: <E, R>(middleware: (effect: Effect<HttpServerResponse, unhandled>) => Effect<HttpServerResponse, E, R> & unhandled extends E ? unknown : "You cannot handle any errors") => Effect<void, never, From<"GlobalRequires", Exclude<R, GlobalProvided>> | From<"GlobalError", Exclude<E, unhandled>>>;
  readonly asHttpEffect: () => Effect<HttpServerResponse, unknown, Scope | HttpServerRequest>;
  readonly prefixed: (prefix: string) => HttpRouter;
}

RouteContext

Added in v4.0.0 Source

Service for the matched HTTP route in the current request.

When to use

Use to read captured path parameters and route metadata while handling a request matched by the router.

Details

It provides the route definition and the path parameters captured by the route matcher.

Signature

declare class RouteContext extends Shape<
  "effect/http/HttpRouter/RouteContext",
  {
    readonly params: Readonly<Record<string, string | undefined>>;
    readonly route: Route<unknown, unknown>;
  },
  this
> {
  constructor(_: never);
}

RouterConfig

Added in v4.0.0 Source

Context reference for low-level router configuration.

Details

The value is passed to the route matcher when an HttpRouter is created and defaults to an empty configuration.

Signature

declare const RouterConfig: Reference<Partial<RouterConfig>>;

Transforming

prefixPath

Added in v4.0.0 Source

Adds a path prefix to a route path.

Details

Trailing slashes are removed from the prefix; / becomes the prefix itself and * becomes a wildcard route under the prefix.

Signature

declare const prefixPath: {
  (prefix: string): (self: string) => string;
  (self: string, prefix: string): string;
};

Utility Types

GlobalProvided type

Added in v4.0.0 Source

Services provided to global middleware.

Signature

type GlobalProvided = HttpServerRequest.HttpServerRequest | Scope.Scope;

Provided type

Added in v4.0.0 Source

Services provided by the HTTP router, which are available in the request context.

Signature

type Provided =
  | HttpServerRequest.HttpServerRequest
  | Scope.Scope
  | HttpServerRequest.ParsedSearchParams
  | RouteContext;

Request interface

Added in v4.0.0 Source

Represents a request-level dependency, that needs to be provided by middleware.

Signature

interface Request<Kind extends string, T> {
  readonly _: typeof _;
  readonly kind: Kind;
  readonly type: T;
}