HttpApiMiddleware
Declares middleware for schema-driven HTTP APIs.
HTTP API middleware wraps endpoint execution on the server and, when the API
requires it, can also wrap requests made by generated clients. It is used for
cross-cutting behavior that belongs to the API contract, such as
authentication, authorization, logging, tracing, rate limiting,
request-scoped services, schema-error handling, and client request
decoration. This module defines the middleware service keys and helpers used
by HttpApi declarations.
Constructors
Creates a Context.Service class for an HTTP API middleware implementation.
When to use
Use when you need an HTTP API middleware service whose configuration declares required services, provided services, typed error schemas, security schemes, client errors, or a matching client middleware requirement.
Signature
declare function Service<Self, Config extends { clientError?: any; provides?: any; requires?: any;} = { clientError: never; provides: never; requires: never;}>(): <Id extends string, Error extends ErrorConstraint = never, Security extends Record<string, HttpApiSecurity> = never, RequiredForClient extends boolean = false>(id: Id, options?: { readonly error?: Error; readonly requiredForClient?: RequiredForClient; readonly security?: Security;}) => ServiceClass<Self, Id, { clientError: "clientError" extends keyof Config ? Config["clientError"] : never; error: Error; provides: "provides" extends keyof Config ? Config["provides"] : never; requiredForClient: RequiredForClient; requires: "requires" extends keyof Config ? Config["requires"] : never; security: Security;}>Guards
isSecurity
Returns true when an HTTP API middleware service is security middleware.
Signature
declare function isSecurity(u: AnyService): u is AnyServiceSecurityLayers
layerClient
Provides a client-side middleware implementation for a middleware that is required by generated clients.
Details
The layer captures the surrounding services and makes the middleware available
through the ForClient service marker used by HTTP API clients.
Signature
declare function layerClient<Id extends AnyId, S, R, EX = never, RX = never>(tag: Key<Id, S>, service: HttpApiMiddlewareClient<Error<Id>, Id["~effect/httpapi/HttpApiMiddleware"]["clientError"], R> | Effect<HttpApiMiddlewareClient<Error<Id>, Id["~effect/httpapi/HttpApiMiddleware"]["clientError"], R>, EX, RX>): Layer<ForClient<Id>, EX, R | Exclude<RX, Scope>>layerSchemaErrorTransform
Creates a middleware layer that transforms HttpApiSchemaError failures.
Details
The middleware catches schema errors produced while running an endpoint and uses
the supplied transform function to convert them into the middleware's declared
error schema.
Signature
declare function layerSchemaErrorTransform<Id, E extends ErrorConstraint, Requires>(service: Service<Id, HttpApiMiddleware<never, E, Requires>>, transform: (error: HttpApiSchemaError, context: { readonly endpoint: Top; readonly group: Top;}) => Effect<HttpServerResponse, HttpApiSchemaError | ErrorSchemaFromConstraint<E>["Type"], Provided | Requires>): Layer<Id>Example
(Mapping schema errors to custom errors)
import { Effect, Schema, type Types } from "effect"import { HttpRouter, HttpServerResponse } from "effect/unstable/http"import { HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiMiddleware} from "effect/unstable/httpapi"
class CustomError extends Schema.TaggedError<CustomError>()("CustomError", {}) {}
class ErrorHandler extends HttpApiMiddleware.Service<ErrorHandler>()("api/ErrorHandler", { error: CustomError}) {}
const messages: Array<string> = []const ErrorHandlerLayer = HttpApiMiddleware.layerSchemaErrorTransform( ErrorHandler, (schemaError) => Effect.sync(() => messages.push(`Mapping ${schemaError.kind} schema error`)).pipe( Effect.andThen(Effect.fail(new CustomError())) ))
const endpoint = HttpApiEndpoint.get("example", "/")const group = HttpApiGroup.make("examples").add(endpoint)const middlewareContext = { endpoint: endpoint as unknown as HttpApiEndpoint.Top, group: group as unknown as HttpApiGroup.Top}const Routes = HttpRouter.add( "GET", "/", Effect.gen(function*() { const applySchemaErrorTransform = yield* ErrorHandler const schemaError = yield* HttpApiError.HttpApiSchemaError.wrap( "Body", Schema.decodeUnknownEffect(Schema.String)(42) ).pipe(Effect.flip) const failingResponse = Effect.fail(schemaError as unknown as Types.unhandled) const result = yield* applySchemaErrorTransform(failingResponse, middlewareContext).pipe( Effect.match({ onFailure: (error) => error instanceof CustomError ? error._tag : "UnexpectedError", onSuccess: () => "Success" }) ) return HttpServerResponse.text(result) })).pipe(HttpRouter.provideRequest(ErrorHandlerLayer))
const program = Effect.acquireUseRelease( Effect.sync(() => HttpRouter.toWebHandler(Routes, { disableLogger: true })), ({ handler }) => Effect.gen(function*() { const response = yield* Effect.promise(() => handler(new Request("http://localhost/"))) const body = yield* Effect.promise(() => response.text()) return body }), ({ dispose }) => Effect.promise(dispose))
const body = await Effect.runPromise(program)const result = [messages, body] // => [["Mapping Body schema error"], "CustomError"]Models
HttpApiMiddleware type
Server-side middleware function for an HTTP API endpoint.
Details
It receives the endpoint response effect and endpoint/group metadata, and returns a new response effect that may require additional services and fail with the middleware's declared error schema.
Signature
type HttpApiMiddleware<Provides, E extends ErrorConstraint, Requires> = (httpEffect: Effect.Effect<HttpServerResponse, unhandled, Provides>, options: { readonly endpoint: HttpApiEndpoint.Top; readonly group: HttpApiGroup.Top;}) => Effect.Effect<HttpServerResponse, unhandled | ErrorSchemaFromConstraint<E>["Type"], Requires | HttpRouter.Provided>HttpApiMiddlewareClient interface
Client-side middleware function for generated HTTP API clients.
Details
It receives endpoint/group metadata, the outgoing request, and a next function
for continuing the request pipeline.
Signature
interface HttpApiMiddlewareClient<_E, CE, R> { (options: { readonly endpoint: Top; readonly group: Top; readonly next: (request: HttpClientRequest) => Effect<HttpClientResponse, HttpClientError>; readonly request: HttpClientRequest; }): Effect<HttpClientResponse, HttpClientError | CE, R>;}HttpApiMiddlewareSecurity type
Server-side middleware implementations for one or more security schemes.
Details
Each property handles the credential decoded for that scheme and wraps the endpoint response effect with the middleware's declared requirements and errors.
Signature
type HttpApiMiddlewareSecurity<Security extends Record<string, HttpApiSecurity.HttpApiSecurity>, Provides, E extends ErrorConstraint, Requires> = { [K in keyof Security]: (httpEffect: Effect.Effect<HttpServerResponse, unhandled, Provides>, options: { readonly credential: HttpApiSecurity.HttpApiSecurity.Type<Security[K]>; readonly endpoint: HttpApiEndpoint.Top; readonly group: HttpApiGroup.Top;}) => Effect.Effect<HttpServerResponse, unhandled | ErrorSchemaFromConstraint<E>["Type"], Requires | HttpRouter.Provided> }Services
AnyService interface
Base service key shape for HTTP API middleware services, including provided services, declared error schemas, and client requirements.
Signature
interface AnyService extends Key<any, any> { readonly "~ClientError": any; readonly "~effect/httpapi/HttpApiMiddleware": "~effect/httpapi/HttpApiMiddleware"; readonly error: ReadonlySet<Top>; readonly provides: any; readonly requiredForClient: boolean;}AnyServiceSecurity interface
Middleware service key shape for security middleware, including the security schemes handled by the service.
Signature
interface AnyServiceSecurity extends AnyService { readonly "~effect/httpapi/HttpApiMiddleware/Security": "~effect/httpapi/HttpApiMiddleware/Security"; readonly security: Record<string, HttpApiSecurity.HttpApiSecurity>;}ServiceClass type
Class type produced by Service for an HTTP API middleware service.
Details
It combines a Context.Service class with the middleware metadata used by
endpoints, builders, and generated clients.
Signature
type ServiceClass<Self, Id extends string, Config extends { clientError: any; error: ErrorConstraint; provides: any; requiredForClient: boolean; requires: any; security: Record<string, HttpApiSecurity.HttpApiSecurity>;}, Service = [Config["security"]] extends [never] ? HttpApiMiddleware<Config["provides"], Config["error"], Config["requires"]> : HttpApiMiddlewareSecurity<Config["security"], Config["provides"], Config["error"], Config["requires"]>> = Context.Service<Self, Service> & { (_: never): Shape<Id, Service> & { readonly "~effect/httpapi/HttpApiMiddleware": { readonly clientError: Config["clientError"]; readonly error: Config["error"]; readonly provides: Config["provides"]; readonly requiredForClient: Config["requiredForClient"]; readonly requires: Config["requires"]; }; }; readonly "~ClientError": Config["clientError"]; readonly "~effect/httpapi/HttpApiMiddleware": typeof TypeId; readonly error: ReadonlySet<Schema.Top>; readonly requiredForClient: Config["requiredForClient"];} & [keyof Config["security"]] extends [never] ? {} : { readonly "~effect/httpapi/HttpApiMiddleware/Security": typeof SecurityTypeId; readonly security: Config["security"];}Utility Types
Type-level identifier carried by middleware services to track provided services, required services, errors, client errors, and client requirements.
Signature
interface AnyId { readonly "~effect/httpapi/HttpApiMiddleware": { readonly clientError: any; readonly error: ErrorConstraint; readonly provides: any; readonly requiredForClient: boolean; readonly requires: any; };}ApplyServices type
Applies a middleware's service changes to an existing requirement type by removing services it provides and adding services it requires.
Signature
type ApplyServices<A extends AnyId, R> = Exclude<R, Provides<A>> | Requires<A>ClientError type
Extracts the client-side error type for middleware that is required on generated clients.
Signature
type ClientError<A> = A extends { readonly "~effect/httpapi/HttpApiMiddleware": { readonly clientError: infer CE; readonly requiredForClient: true; };} ? CE : neverExtracts the decoded error type declared by a middleware identifier.
Signature
type Error<A> = ErrorSchema<A>["Type"]ErrorSchema type
Extracts the schema or schema union used for errors declared by a middleware identifier.
Signature
type ErrorSchema<A> = A extends { readonly "~effect/httpapi/HttpApiMiddleware": { readonly error: infer E; };} ? ErrorSchemaFromConstraint<E> : neverErrorServicesDecode type
Extracts the schema services required to decode errors declared by a middleware identifier.
Signature
type ErrorServicesDecode<A> = ErrorSchema<A>["DecodingServices"]ErrorServicesEncode type
Extracts the schema services required to encode errors declared by a middleware identifier.
Signature
type ErrorServicesEncode<A> = ErrorSchema<A>["EncodingServices"]Client-side service marker required when a middleware declares requiredForClient.
Signature
interface ForClient<Id> { readonly _: typeof _; readonly id: Id;}MiddlewareClient type
Computes the client-side service marker required for middleware that must also run in generated clients.
Signature
type MiddlewareClient<A> = A extends { readonly "~effect/httpapi/HttpApiMiddleware": { readonly requiredForClient: true; };} ? ForClient<A> : neverExtracts the services provided by a middleware identifier.
Signature
type Provides<A> = A extends { readonly "~effect/httpapi/HttpApiMiddleware": { readonly provides: infer P; };} ? P : neverExtracts the services required to run a middleware implementation.
Signature
type Requires<A> = A extends { readonly "~effect/httpapi/HttpApiMiddleware": { readonly requires: infer R; };} ? R : never