HttpLayerRouter
Configuration
RouterConfig
Signature
declare class RouterConfig extends any { constructor();}HttpApi
addHttpApi
Signature
declare function addHttpApi<Id extends string, Groups extends Any, E, R>(api: HttpApi<Id, Groups, E, R>, options?: { readonly openapiPath?: `/${string}`;}): Layer<never, never, Generator | FileSystem | HttpPlatform | Path | HttpRouter | R | ToService<Id, Groups> | ErrorContext<Groups>>Example
import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer"import * as NodeRuntime from "@effect/platform-node/NodeRuntime"import * as HttpApi from "@effect/platform/HttpApi"import * as HttpApiBuilder from "@effect/platform/HttpApiBuilder"import * as HttpApiEndpoint from "@effect/platform/HttpApiEndpoint"import * as HttpApiGroup from "@effect/platform/HttpApiGroup"import * as HttpApiScalar from "@effect/platform/HttpApiScalar"import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as HttpMiddleware from "@effect/platform/HttpMiddleware"import * as Effect from "effect/Effect"import * as Layer from "effect/Layer"import { createServer } from "http"
// First, we define our HttpApiclass MyApi extends HttpApi.make("api").add( HttpApiGroup.make("users").add( HttpApiEndpoint.get("me", "/me") ).prefix("/users")) {}
// Implement the handlers for the APIconst UsersApiLayer = HttpApiBuilder.group(MyApi, "users", (handers) => handers.handle("me", () => Effect.void))
// Use `HttpLayerRouter.addHttpApi` to register the API with the routerconst HttpApiRoutes = HttpLayerRouter.addHttpApi(MyApi, { openapiPath: "/docs/openapi.json"}).pipe( // Provide the api handlers layer Layer.provide(UsersApiLayer))
// Create a /docs route for the API documentationconst DocsRoute = HttpApiScalar.layerHttpLayerRouter({ api: MyApi, path: "/docs"})
const CorsMiddleware = HttpLayerRouter.middleware(HttpMiddleware.cors())// You can also use HttpLayerRouter.cors() to create a CORS middleware
// Finally, we merge all routes and serve them using the Node HTTP serverconst AllRoutes = Layer.mergeAll( HttpApiRoutes, DocsRoute).pipe( Layer.provide(CorsMiddleware.layer))
HttpLayerRouter.serve(AllRoutes).pipe( Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 })), Layer.launch, NodeRuntime.runMain)HttpRouter
Create a layer that adds a single route to the HTTP router.
Signature
declare function add<E, R>(method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "*", path: PathInput, handler: 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>>Example
import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
const Route = HttpLayerRouter.add("GET", "/hello", HttpServerResponse.text("Hello, World!"))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]>>>Example
import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
const Routes = HttpLayerRouter.addAll([ HttpLayerRouter.route("GET", "/hello", HttpServerResponse.text("Hello, World!"))])HttpRouter
Signature
declare const HttpRouter: Tag<HttpRouter, HttpRouter>HttpRouter interface
Signature
interface HttpRouter { readonly [TypeId]: typeof TypeId; readonly add: <E, R>(method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "*", path: PathInput, handler: 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;}Signature
declare const layer: Layer.Layer<HttpRouter>Signature
declare const make: Effect<any, unknown, unknown>toHttpEffect
Signature
declare function toHttpEffect<A, E, R>(appLayer: Layer<A, E, R>): Effect<Effect<HttpServerResponse, RouteNotFound | Only<"Error", R> | Only<"GlobalRequires", R>, Scope | HttpServerRequest | Only<"GlobalRequires", R> | Only<"Requires", R>>, Without<E>, Scope | Exclude<Without<R>, HttpRouter>>Signature
declare const TypeId: unique symbolSignature
type TypeId = typeof TypeIdA helper function that is the equivalent of:
Signature
declare function use<A, E, R>(f: (router: HttpRouter) => Effect<A, E, R>): Layer<never, E, HttpRouter | Exclude<R, Scope>>Example
import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as Effect from "effect/Effect"import * as Layer from "effect/Layer"
const MyRoute = Layer.scopedDiscard(Effect.gen(function*() { const router = yield* HttpLayerRouter.HttpRouter
// then use `yield* router.add(...)` to add a route}))Middleware
A 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> | Predicate<string>; readonly credentials?: boolean; readonly exposedHeaders?: readonly Array<string>; readonly maxAge?: number;}): Layer<never, never, HttpRouter>disableLogger
A middleware that disables the logger for some routes.
Signature
declare const disableLogger: Layer.Layer<never>Example
import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as HttpServerResponse from "@effect/platform/HttpServerResponse"import * as Layer from "effect/Layer"
const Route = HttpLayerRouter.add("GET", "/hello", HttpServerResponse.text("Hello, World!")).pipe( // disable the logger for this route Layer.provide(HttpLayerRouter.disableLogger))middleware
Create a middleware layer that can be used to modify requests and responses.
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>Example
import * as HttpLayerRouter from "@effect/platform/HttpLayerRouter"import * as HttpMiddleware from "@effect/platform/HttpMiddleware"import * as HttpServerResponse from "@effect/platform/HttpServerResponse"import * as Context from "effect/Context"import * as Effect from "effect/Effect"import * as Layer from "effect/Layer"
// Here we are defining a CORS middlewareconst CorsMiddleware = HttpLayerRouter.middleware(HttpMiddleware.cors()).layer// You can also use HttpLayerRouter.cors() to create a CORS middleware
class CurrentSession extends Context.Tag("CurrentSession")<CurrentSession, { readonly token: string}>() {}
// You can create middleware that provides a service to the HTTP requests.const SessionMiddleware = HttpLayerRouter.middleware<{ provides: CurrentSession}>()( Effect.gen(function*() { yield* Effect.log("SessionMiddleware initialized")
return (httpEffect) => Effect.provideService(httpEffect, CurrentSession, { token: "dummy-token" }) })).layer
Effect.gen(function*() { const router = yield* HttpLayerRouter.HttpRouter yield* router.add( "GET", "/hello", Effect.gen(function*() { // Requests can now access the current session const session = yield* CurrentSession return HttpServerResponse.text(`Hello, World! Your token is ${session.token}`) }) )}).pipe( Layer.effectDiscard, // Provide the SessionMiddleware & CorsMiddleware to some routes Layer.provide([SessionMiddleware, CorsMiddleware]))middleware
Middleware interface
Signature
interface Middleware<Config extends { error: any; handles: any; layerError: any; layerRequires: any; provides: any; requires: any;}> { readonly [MiddlewareTypeId]: 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";}MiddlewareTypeId
Signature
declare const MiddlewareTypeId: unique symbolMiddlewareTypeId type
Signature
type MiddlewareTypeId = typeof MiddlewareTypeIdA pseudo-error type that represents an error that should be not handled by the middleware.
Signature
interface unhandled { readonly _: typeof _;}Models
RouteContext interface
Signature
interface RouteContext { readonly [RouteContextTypeId]: typeof RouteContextTypeId; readonly params: Readonly<Record<string, string | undefined>>; readonly route: Route<unknown, unknown>;}PathInput
Signature
type PathInput = `/${string}` | "*"prefixPath
Signature
declare const prefixPath: { (prefix: string): (self: string) => string; (self: string, prefix: string): string;}Re-Exports
FindMyWay
Signature
declare const FindMyWay: anyRequest Types
GlobalProvided type
Services provided to global middleware.
Signature
type GlobalProvided = HttpServerRequest.HttpServerRequest | Scope.ScopeServices provided by the HTTP router, which are available in the request context.
Signature
type Provided = HttpServerRequest.HttpServerRequest | Scope.Scope | HttpServerRequest.ParsedSearchParams | RouteContextRepresents 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;}Route
prefixRoute
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>;}Signature
declare function route<E, R>(method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "*", path: PathInput, handler: Effect<HttpServerResponse, E, R> | (request: HttpServerRequest) => Effect<HttpServerResponse, E, R>, options?: { readonly uninterruptible?: boolean;}): Route<E, Exclude<R, Provided>>Signature
interface Route<E = never, R = never> { readonly [RouteTypeId]: typeof RouteTypeId; readonly handler: Effect<HttpServerResponse, E, R>; readonly method: HttpMethod | "*"; readonly path: PathInput; readonly prefix: Option<string>; readonly uninterruptible: boolean;}RouteTypeId
Signature
declare const RouteTypeId: unique symbolRouteTypeId type
Signature
type RouteTypeId = typeof RouteTypeIdRoute Context
Signature
declare const params: Effect.Effect<Readonly<Record<string, string | undefined>>, never, RouteContext>RouteContext
Signature
declare const RouteContext: Tag<RouteContext, RouteContext>schemaJson
Signature
declare const schemaJson: <R, I extends Partial<{ readonly body: any; readonly cookies: Readonly<Record<string, string | undefined>>; readonly headers: Readonly<Record<string, string | undefined>>; readonly method: Method.HttpMethod; readonly pathParams: Readonly<Record<string, string | undefined>>; readonly searchParams: Readonly<Record<string, string | ReadonlyArray<string> | undefined>>; readonly url: string;}>, A>(schema: Schema.Schema<A, I, R>, options?: ParseOptions) => Effect.Effect<A, Error.RequestError | ParseResult.ParseError, RouteContext | R | ServerRequest.HttpServerRequest | ServerRequest.ParsedSearchParams>schemaNoBody
Signature
declare const schemaNoBody: <R, I extends Partial<{ readonly cookies: Readonly<Record<string, string | undefined>>; readonly headers: Readonly<Record<string, string | undefined>>; readonly method: Method.HttpMethod; readonly pathParams: Readonly<Record<string, string | undefined>>; readonly searchParams: Readonly<Record<string, string | ReadonlyArray<string> | undefined>>; readonly url: string;}>, A>(schema: Schema.Schema<A, I, R>, options?: ParseOptions) => Effect.Effect<A, ParseResult.ParseError, R | RouteContext | ServerRequest.HttpServerRequest | ServerRequest.ParsedSearchParams>schemaParams
Signature
declare const schemaParams: <A, I extends Readonly<Record<string, string | ReadonlyArray<string> | undefined>>, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions) => Effect.Effect<A, ParseResult.ParseError, R | RouteContext | ServerRequest.ParsedSearchParams>schemaPathParams
Signature
declare const schemaPathParams: <A, I extends Readonly<Record<string, string | undefined>>, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions) => Effect.Effect<A, ParseResult.ParseError, R | RouteContext>Server
Serves 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, RouteNotFound | Only<"Error", R> | Only<"GlobalError", R>, Scope | HttpServerRequest | Only<"Requires", R> | Only<"GlobalRequires", R>>) => Effect<HttpServerResponse, HE, HR>; readonly routerConfig?: any;}): Layer<A, Without<E>, HttpServer | Exclude<Without<R>, HttpRouter> | Exclude<Exclude<HR, GlobalProvided>, HttpRouter>>toWebHandler
Signature
declare function toWebHandler<A, E, R extends HttpRouter | Request<"Requires", any> | Request<"GlobalRequires", any> | Request<"Error", any> | Request<"GlobalError", any>, HE, HR = Exclude<Only<"Requires", R>, A> | Exclude<Only<"GlobalRequires", R>, A>>(appLayer: Layer<A, E, R>, options?: { readonly disableLogger?: boolean; readonly memoMap?: MemoMap; readonly middleware?: (effect: Effect<HttpServerResponse, RouteNotFound | Only<"Error", R> | Only<"GlobalError", R>, Scope | HttpServerRequest | Only<"Requires", R> | Only<"GlobalRequires", R>>) => Effect<HttpServerResponse, HE, HR>; readonly routerConfig?: any;}): { readonly dispose: () => Promise<void>; readonly handler: [HR] extends [never] ? (request: Request, context?: Context<never>) => Promise<Response> : (request: Request, context: Context<HR>) => Promise<Response>;}