Comprehensive reference for @effect/platform (v0.94.2) — unified, platform-independent abstractions for HTTP, filesystem, terminal, workers, and more. Covers all 56 public modules, their service patterns, Layer composition, and architecture flows.
- Package Overview
- Module Map
- HTTP Client
- HTTP Server
- HTTP Router
- Declarative HTTP API
- HTTP Request & Response Types
- HTTP Middleware
- HTTP Core Components
- FileSystem
- Terminal
- KeyValueStore
- Command & CommandExecutor
- Path
- Socket & SocketServer
- Worker & WorkerRunner
- Data Formats
- Platform Utilities
- Error Model
- Key Patterns
- Architecture Flows
- Quick Reference
@effect/platform v0.94.2
"Unified interfaces for common platform-specific services"
Purpose: Platform-independent abstractions for Node.js, Bun, and browsers. Defines service interfaces — implementations live in downstream packages (@effect/platform-node, @effect/platform-bun, @effect/platform-browser).
| Dependency | Purpose |
|---|---|
find-my-way-ts |
Radix-tree HTTP router matching |
msgpackr |
MessagePack binary serialization |
multipasta |
Multipart form data parsing |
effect (peer) |
Core Effect library |
{
".": "./src/index.ts",
"./*": "./src/*.ts",
"./internal/*": null
}- Wildcard exports: Every
src/*.tsis importable as@effect/platform/ModuleName - Internal blocked:
./internal/*mapped tonull— implementation files are private - Import convention:
import { HttpClient } from "@effect/platform"(barrel) orimport * as HttpClient from "@effect/platform/HttpClient"(tree-shakeable)
Each public module follows a consistent structure:
- Type definitions & interfaces (in
src/ModuleName.ts) TypeIdsymbols for discriminated unions- Re-exports from
./internal/moduleName.js(hidden implementation)
| Category | Count | Modules |
|---|---|---|
| HTTP API | 8 | HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiBuilder, HttpApiSchema, HttpApiScalar, HttpApiSecurity, HttpApiMiddleware |
| HTTP Server | 7 | HttpServer, HttpServerRequest, HttpServerResponse, HttpServerError, HttpServerRespondable, HttpApp, HttpRouter |
| HTTP Client | 6 | HttpClient, HttpClientRequest, HttpClientResponse, HttpClientError, FetchHttpClient, HttpIncomingMessage |
| HTTP Core | 8 | HttpMethod, HttpBody, Headers, Cookies, HttpPlatform, HttpTraceContext, Etag, HttpLayerRouter |
| HTTP Docs | 4 | OpenApi, OpenApiJsonSchema, HttpApiSwagger, HttpApiClient |
| HTTP Composition | 2 | HttpMiddleware, HttpMultiplex |
| Platform Services | 7 | FileSystem, Path, Terminal, KeyValueStore, PlatformConfigProvider, PlatformLogger, Runtime |
| Process/Workers | 5 | Command, CommandExecutor, Worker, WorkerRunner, WorkerError |
| Data Formats | 3 | MsgPack, Multipart, Ndjson |
| URLs & Web | 3 | Url, UrlParams, ChannelSchema |
| Sockets | 2 | Socket, SocketServer |
| Utilities | 4 | Effectify, Error, Template, Transferable |
| Total | 56 |
Module: HttpClient.ts — Service tag-based HTTP client with middleware pipeline.
import { HttpClient } from "@effect/platform";
// HttpClient is a Context.Tag
// execute: (request: HttpClientRequest) => Effect<HttpClientResponse, HttpClientError, R>HTTP verb shortcuts all return Effect<HttpClientResponse, HttpClientError, HttpClient>:
HttpClient.get(url);
HttpClient.post(url);
HttpClient.put(url);
HttpClient.patch(url);
HttpClient.del(url);
HttpClient.head(url);
HttpClient.options(url);HttpClientRequest
→ preprocess (validation/transformation)
→ execute (platform-specific fetch/http)
→ postprocess (response extraction)
→ HttpClientResponse
makeWith({ postprocess, preprocess })— constructor combining both phasesmake(handler)— custom handler implementation via callback
// Transform request before sending
HttpClient.mapRequest(client, f);
HttpClient.mapRequestEffect(client, f);
// Transform response after receiving
HttpClient.transformResponse(client, f);
// Full transform: access both request and effect
HttpClient.transform(client, f);HttpClient.catchAll(client, handler);
HttpClient.catchTag(client, tag, handler);
HttpClient.filterStatus(client, range);
HttpClient.filterStatusOk(client); // only 2xx
HttpClient.retry(client, schedule);
HttpClient.retryTransient(client, schedule); // retry on transient failuresHttpClient.withCookiesRef(client, ref); // persist cookies across requests
HttpClient.followRedirects(client); // automatic redirect handling
HttpClient.withTracerPropagation(client, enabled); // distributed tracing
HttpClient.withSpanNameGenerator(client, fn); // custom span namingimport { FetchHttpClient } from "@effect/platform";
// Layer providing HttpClient backed by browser/Node fetch
FetchHttpClient.layer;Module: HttpServer.ts — Abstract HTTP server interface.
interface HttpServer {
serve<E, R>(httpApp: App.Default<E, R>): Effect<void, never, R | Scope>;
address: Address; // TcpAddress | UnixAddress
}type TcpAddress = { _tag: "TcpAddress"; hostname: string; port: number };
type UnixAddress = { _tag: "UnixAddress"; path: string };// Layer-based serving (recommended)
HttpServer.serve();
HttpServer.serve(httpApp, middleware);
// Effect-based serving
HttpServer.serveEffect();HttpServer.addressWith(f); // run effect with server address
HttpServer.addressFormattedWith(f); // run with formatted address string
HttpServer.logAddress; // log server address on startup
HttpServer.layerTestClient; // HttpClient pointing to running server (tests)
HttpServer.layerContext; // provides HttpPlatform, FileSystem, Etag.Generator, PathModule: HttpRouter.ts — Immutable, composable request router using find-my-way-ts radix tree.
// HttpRouter<E, R> extends App.Default<E | RouteNotFound, R>
const router = HttpRouter.empty;interface Route<E, R> {
method: HttpMethod | "*";
path: PathInput; // "/{param}" or "*" wildcard
handler: Route.Handler<E, R>;
prefix?: string;
uninterruptible?: boolean;
}HttpRouter.get(path, handler);
HttpRouter.post(path, handler);
HttpRouter.put(path, handler);
HttpRouter.patch(path, handler);
HttpRouter.del(path, handler);
HttpRouter.all(path, handler); // any methodHttpRouter.concat(router1, router2);
HttpRouter.mount(router, "/api", subRouter);
HttpRouter.mountApp(router, "/api", httpApp);
HttpRouter.prefixAll(router, "/v1");// RouteContext tag provides params: Record<string, string>
HttpRouter.params; // get path params
HttpRouter.schemaParams(schema); // validate path params via Schema
HttpRouter.schemaPathParams(schema);
HttpRouter.schemaJson(schema); // validate JSON body
HttpRouter.schemaNoBody(schema); // validate without body// Create named router with .Live, .router, .use, .unwrap, .serve
const MyRouter = HttpRouter.Tag<"MyRouter">();
const layer = MyRouter.router;
// Pre-defined default
HttpRouter.Default;Modules: HttpApi.ts, HttpApiGroup.ts, HttpApiEndpoint.ts, HttpApiBuilder.ts
The declarative API layer separates definition from implementation — define your API shape with schemas, then implement handlers separately.
const getUser = HttpApiEndpoint.get("getUser", "/users/:id")
.setPathParams(Schema.Struct({ id: Schema.NumberFromString }))
.addSuccess(UserSchema)
.addError(NotFoundError, { status: 404 })
.setHeaders(Schema.Struct({ authorization: Schema.String }));Properties:
name,path,methodpathSchema,urlParamsSchema,payloadSchema,headersSchemasuccessSchema,errorSchema
const usersGroup = HttpApiGroup.make("users")
.add(getUser)
.add(createUser)
.addError(AuthError, { status: 401 })
.prefix("/api")
.middleware(AuthMiddleware);const api = HttpApi.make("MyAPI")
.add(usersGroup)
.add(postsGroup)
.addError(ServerError)
.middleware(LoggingMiddleware);// Implement endpoints and serve
const layer = HttpApiBuilder.api(api).pipe(
HttpServer.serve(HttpMiddleware.logger)
);
// Web standard handler for edge deployments
const handler = HttpApiBuilder.toWebHandler(api);| Module | Purpose |
|---|---|
HttpApiSchema |
Schema handling for API endpoints |
HttpApiScalar |
Scalar type support |
HttpApiSecurity |
Authentication/authorization definitions |
HttpApiMiddleware |
Middleware for API groups/endpoints |
HttpApiClient |
Auto-generated client from API definition |
HttpApiSwagger |
Swagger UI integration |
OpenApi |
OpenAPI spec generation |
OpenApiJsonSchema |
JSON Schema for OpenAPI |
// Extract metadata for code generation, docs, etc.
HttpApi.reflect(api, {
onGroup: ({ group }) => ...,
onEndpoint: ({ endpoint, successes, errors }) => ...,
})interface HttpClientRequest {
method: HttpMethod;
url: string;
urlParams: UrlParams;
hash?: string;
headers: Headers;
body: HttpBody;
}Constructors (typed — GET excludes body, POST excludes URL params):
HttpClientRequest.get(url);
HttpClientRequest.post(url);
// ... all HTTP verbsModification:
HttpClientRequest.setHeader(req, key, value);
HttpClientRequest.bearerToken(req, token);
HttpClientRequest.basicAuth(req, user, pass);
HttpClientRequest.bodyJson(req, data);
HttpClientRequest.bodyStream(req, stream);
HttpClientRequest.bodyFormData(req, formData);interface HttpClientResponse extends IncomingMessage<ResponseError> {
request: HttpClientRequest;
status: number;
cookies: Cookies;
formData: Effect<FormData, ResponseError>;
}Processing:
HttpClientResponse.matchStatus(response, {
200: (r) => ...,
404: (r) => ...,
"4xx": (r) => ...,
})
HttpClientResponse.schemaJson(schema)(response)
HttpClientResponse.stream(response) // Stream<Uint8Array>// Properties: source, url, originalUrl, method, cookies
// Body parsing:
HttpServerRequest.schemaBodyJson(schema);
HttpServerRequest.schemaBodyForm(schema);
HttpServerRequest.schemaBodyMultipart(schema);
// WebSocket:
HttpServerRequest.upgrade; // WebSocket upgrade
// Web standard:
HttpServerRequest.toWeb();ParsedSearchParamstag for query string access
Constructors:
HttpServerResponse.empty();
HttpServerResponse.text("hello");
HttpServerResponse.json({ data: 42 });
HttpServerResponse.redirect("/other");
HttpServerResponse.html`<h1>Hello ${name}</h1>`; // template literal
HttpServerResponse.stream(byteStream);
HttpServerResponse.file(path);
HttpServerResponse.formData(data);Combinators:
HttpServerResponse.setHeader(res, key, value);
HttpServerResponse.setStatus(res, 201);
HttpServerResponse.setCookie(res, name, value);
HttpServerResponse.schemaJson(schema)(data);Module: HttpMiddleware.ts
type HttpMiddleware = <E, R>(self: App.Default<E, R>) => App.Default<any, any>;HttpMiddleware.logger; // request/response logging
HttpMiddleware.xForwardedHeaders; // X-Forwarded-* processing
HttpMiddleware.searchParamsParser; // automatic query parsing
HttpMiddleware.cors({
// CORS
allowedOrigins: ["https://example.com"], // or predicate
allowedMethods: ["GET", "POST"],
credentials: true,
maxAge: Duration.hours(1),
});HttpMiddleware.withTracerDisabledWhen(predicate); // disable per-request
HttpMiddleware.withTracerDisabledForUrls(patterns); // disable for URL patterns
HttpMiddleware.withSpanNameGenerator(fn); // custom span naming// Toggle per-fiber via Effect.locally()
HttpMiddleware.loggerDisabled;
HttpMiddleware.currentTracerDisabledWhen;| Module | Purpose |
|---|---|
HttpMethod |
HTTP method types (GET, POST, etc.) and guards |
HttpBody |
Request/response body encoding (JSON, text, stream, form, file) |
Headers |
HTTP headers utilities (get, set, merge, schema validation) |
Cookies |
Cookie parsing, serialization, CookiesRef for state |
HttpPlatform |
Platform-specific HTTP abstractions |
HttpTraceContext |
W3C trace context propagation for distributed tracing |
Etag |
Entity tag generation and comparison |
HttpLayerRouter |
Router exposed as a Layer for composition |
HttpMultiplex |
Request multiplexing across multiple apps |
Module: FileSystem.ts — Abstract filesystem operations.
Context.GenericTag<FileSystem>("@effect/platform/FileSystem");FileSystem.readFile(path) // Effect<Uint8Array, PlatformError>
FileSystem.writeFile(path, data) // Effect<void, PlatformError>
FileSystem.readFileString(path) // Effect<string, PlatformError>
FileSystem.writeFileString(path, str) // Effect<void, PlatformError>
FileSystem.exists(path) // Effect<boolean, PlatformError>
FileSystem.remove(path) // Effect<void, PlatformError>
FileSystem.copy(src, dst) // Effect<void, PlatformError>
FileSystem.rename(old, new) // Effect<void, PlatformError>FileSystem.readDirectory(path); // Effect<Array<string>>
FileSystem.makeDirectory(path); // Effect<void>
FileSystem.makeTempDirectory(); // Effect<string>
FileSystem.makeTempDirectoryScoped(); // Effect<string, _, Scope>FileSystem.stream(path); // Stream<Uint8Array>
FileSystem.sink(path); // Sink<void, Uint8Array>
FileSystem.watch(path); // Stream<WatchEvent> (Create | Update | Remove)interface File {
read(buf): Effect<Size>;
write(buf): Effect<Size>;
readAlloc(size): Effect<Option<Uint8Array>>;
writeAll(buf): Effect<void>;
seek(offset, whence): Effect<void>;
stat: Effect<File.Info>;
sync: Effect<void>;
truncate(length?): Effect<void>;
}type Size = bigint & Brand<"Size">;
// Unit helpers: Size.KiB, Size.MiB, Size.GiB, Size.TiB, Size.PiB
type FileDescriptor = number & Brand<"FileDescriptor">;FileSystem.layerNoop(impl); // testing layer
// Platform implementations: @effect/platform-node, @effect/platform-bunModule: Terminal.ts — Terminal/console access.
Context.GenericTag<Terminal>("@effect/platform/Terminal");Terminal.columns; // Effect<number> — terminal width
Terminal.rows; // Effect<number> — terminal height
Terminal.isTTY; // Effect<boolean> — interactive check
Terminal.readLine; // Effect<string, QuitException>
Terminal.readInput; // Effect<ReadonlyMailbox<UserInput>, never, Scope>
Terminal.display(text); // Effect<void, PlatformError>interface Key { name: string; ctrl: boolean; meta: boolean; shift: boolean }
interface UserInput { input: Option<string>; key: Key }
class QuitException // Ctrl+CModule: KeyValueStore.ts — Simple key-value storage abstraction.
Context.GenericTag<KeyValueStore>("@effect/platform/KeyValueStore");KeyValueStore.get(key); // Effect<Option<string>>
KeyValueStore.getUint8Array(key); // Effect<Option<Uint8Array>>
KeyValueStore.set(key, value); // Effect<void>
KeyValueStore.remove(key); // Effect<void>
KeyValueStore.clear(); // Effect<void>
KeyValueStore.size; // Effect<number>
KeyValueStore.has(key); // Effect<boolean>
KeyValueStore.modify(key, f); // update if exists
KeyValueStore.forSchema(schema); // SchemaStore<A, R>const store = KeyValueStore.forSchema(UserSchema);
store.get(key); // Effect<Option<User>, ParseError | PlatformError>
store.set(key, user);KeyValueStore.layerMemory; // in-memory Map
KeyValueStore.layerFileSystem(directory); // file-based (requires FileSystem + Path)
KeyValueStore.layerStorage(evaluate); // Web Storage API wrapper
KeyValueStore.layerSchema(schema, tagId); // tagged layer for typed storeKeyValueStore.prefix(store, "myapp:"); // prefixed view
KeyValueStore.make(impl); // fill derived methods from primitives
KeyValueStore.makeStringOnly(impl); // base64 encoding for binary in string-only backendsModules: Command.ts, CommandExecutor.ts — Process execution.
// No service tag — pure builder pattern
const cmd = Command.make("git", "status")
|> Command.workingDirectory("/repo")
|> Command.env({ NODE_ENV: "production" })
|> Command.stdin("pipe")
|> Command.stdout("pipe")
|> Command.runInShell("/bin/bash")
// Pipe commands together
const piped = Command.pipeTo(
Command.make("cat", "file.txt"),
Command.make("grep", "pattern")
)Context.Tag<CommandExecutor, CommandExecutor>;
CommandExecutor.exitCode(cmd); // Effect<ExitCode>
CommandExecutor.start(cmd); // Effect<Process, PlatformError, Scope>
CommandExecutor.string(cmd); // Effect<string>
CommandExecutor.lines(cmd); // Effect<Array<string>>
CommandExecutor.stream(cmd); // Stream<Uint8Array>
CommandExecutor.streamLines(cmd); // Stream<string>interface Process {
pid: ProcessId; // branded number
exitCode: Effect<ExitCode>; // branded number
isRunning: Effect<boolean>;
kill(signal?: Signal): Effect<void>; // POSIX signals
stdout: Stream<Uint8Array>;
stderr: Stream<Uint8Array>;
stdin: Sink<void, Uint8Array>;
}Module: Path.ts — Cross-platform path utilities.
Context.Tag<Path, Path>;Path.sep // path separator
Path.join(...paths) // join segments
Path.resolve(...segments) // resolve to absolute
Path.basename(path, suffix?) // filename
Path.dirname(path) // directory
Path.extname(path) // extension
Path.normalize(path)
Path.relative(from, to)
Path.isAbsolute(path)
Path.parse(path) // { root, dir, base, ext, name }
Path.format(parsed) // reconstruct
Path.toFileUrl(path) // Effect<URL, BadArgument>
Path.fromFileUrl(url) // Effect<string, BadArgument>Module: Socket.ts — Low-level socket operations with WebSocket support.
Context.GenericTag<Socket>("@effect/platform/Socket")
Socket.run(handler, options?) // process binary data
Socket.runRaw(handler, options?) // process string or binary
Socket.writer // Effect<write fn, never, Scope>Socket.toChannel(); // Channel<Chunk<Uint8Array>, ...>
Socket.toChannelString(); // string channel
Socket.toChannelMap(f); // mapped channelSocket.makeWebSocket(url, options); // Socket from WebSocket URL
Socket.fromWebSocket(acquire, options); // Socket from WebSocket instance
Socket.fromTransformStream(stream); // Socket from ReadableStream/WritableStreamtype SocketError = SocketGenericError | SocketCloseError;
// SocketGenericError: reason "Write" | "Read" | "Open" | "OpenTimeout"
// SocketCloseError: code + closeReasoninterface SocketServer {
address: Address; // TcpAddress | UnixAddress
run<E, R>(
handler: (socket: Socket) => Effect<_, E, R>
): Effect<never, SocketServerError, R>;
}Modules: Worker.ts, WorkerRunner.ts — Worker thread abstraction with pool management.
PlatformWorker; // backend spawner
WorkerManager; // pools and spawns workers
Spawner; // worker factory functionWorker.execute(message); // Stream<O, E | WorkerError> — streaming response
Worker.executeEffect(message); // Effect<O, E | WorkerError> — single responseWorker.makePool({
size: 4, // or minSize/maxSize for elastic
concurrency: 10,
targetUtilization: 0.8,
timeToLive: Duration.minutes(5),
});PlatformRunner; // message-based worker server
WorkerRunner.make(process, options); // raw handler
WorkerRunner.makeSerialized(schema, handlers); // schema-based dispatch
WorkerRunner.launch(layer); // launch with close latch// Wire format: [id, type, data | cause, optional trace]
type BackingWorker<I, O> = { send(message): Effect; run(handler): Effect };| Module | Purpose | Dependency |
|---|---|---|
MsgPack |
MessagePack binary codec | msgpackr |
Multipart |
Multipart form data handling | multipasta |
Ndjson |
Newline-delimited JSON streaming | — |
| Module | Purpose |
|---|---|
PlatformConfigProvider |
ConfigProvider from file trees (fromFileTree) or .env files (fromDotEnv) |
PlatformLogger |
File-based logger via toFile(path, options) — requires FileSystem |
Runtime |
Runtime environment utilities |
Effectify |
Convert Node.js-style callbacks to Effect |
Template |
Template string utilities |
Transferable |
Collect Transferable objects for worker postMessage — optional Collector service |
Url |
URL parsing and manipulation |
UrlParams |
Query parameter utilities |
ChannelSchema |
Schema for channel-based communication |
PlatformConfigProvider.layerFileTree(options?) // directory tree as config
PlatformConfigProvider.layerDotEnv(path) // .env file as config
PlatformConfigProvider.layerFileTreeAdd // merge with existing
PlatformConfigProvider.layerDotEnvAdd // merge with existing// Optional service — gracefully degrades if not provided
Transferable.Collector; // Tag<Collector, CollectorService>
Transferable.addAll(transferables);
Transferable.schema(self, f); // wrap schema to collect on encode
// Pre-built schemas
Transferable.ImageData;
Transferable.MessagePort;
Transferable.Uint8Array;Module: Error.ts
type PlatformError = BadArgument | SystemError
// BadArgument: invalid parameters
interface BadArgument {
_tag: "BadArgument"
module: string // "FileSystem", "Command", etc.
method: string
message: string
}
// SystemError: OS-level failures
interface SystemError {
_tag: "SystemError"
reason: "AlreadyExists" | "NotFound" | "Busy" | "PermissionDenied" | ...
module: string
method: string
syscall: string
pathOrDescriptor: string | FileDescriptor
}class WorkerError extends Schema.TaggedError<WorkerError>() {
reason: "spawn" | "decode" | "send" | "unknown" | "encode";
}All platform errors are serializable via Schema.
Every capability is an abstract service accessed through Context.Tag:
// Two tag forms used across the package:
Context.GenericTag<FileSystem>("@effect/platform/FileSystem"); // simpler
Context.Tag<CommandExecutor, CommandExecutor>; // standardServices ship with layer constructors — pick the implementation for your platform:
// In-memory for tests
KeyValueStore.layerMemory;
// Platform-specific (from @effect/platform-node)
NodeFileSystem.layer;
NodeTerminal.layer;
NodeHttpServer.layer({ port: 3000 });Most services have a make(impl) that fills in derived methods from primitives:
// Only implement the core methods, derived ones (has, isEmpty, modify) are auto-generated
const store = KeyValueStore.make({
get: (key) => ...,
set: (key, value) => ...,
remove: (key) => ...,
clear: ...,
size: ...,
})Type-safe wrappers prevent mixing up raw primitives:
type Size = bigint & Brand<"Size">;
type ProcessId = number & Brand<"ProcessId">;
type ExitCode = number & Brand<"ExitCode">;
type FileDescriptor = number & Brand<"FileDescriptor">;Deep integration with @effect/schema for validation, serialization, and documentation:
- HTTP API endpoints use Schema for path params, body, headers, response
- KeyValueStore has
forSchema()for typed access - Worker messages use
Schema.TaggedRequestfor dispatch - Transferable uses Schema transforms for collection
Many functions support both data-first and data-last calling:
// data-first
HttpClient.mapRequest(client, f);
// data-last (pipeable)
client.pipe(HttpClient.mapRequest(f));File handles, server connections, and processes use Scope for automatic cleanup:
// Process requires Scope — automatically killed when scope closes
CommandExecutor.start(cmd); // Effect<Process, PlatformError, Scope>
// Temp directories cleaned up with scope
FileSystem.makeTempDirectoryScoped(); // Effect<string, PlatformError, Scope>Readable operations return Stream, writable operations return Sink:
FileSystem.stream(path); // Stream<Uint8Array>
FileSystem.sink(path); // Sink<void, Uint8Array>
Process.stdout; // Stream<Uint8Array>
Process.stdin; // Sink<void, Uint8Array>Some services gracefully degrade when not provided:
// Transferable.Collector checks serviceOption — no-ops if absent
Transferable.addAll(items); // safe to call without Collector in contextHttpClientRequest.post(url)
|> HttpClientRequest.bearerToken(token)
|> HttpClientRequest.bodyJson(data)
→ HttpClient.preprocess (validation/transformation)
→ HttpClient.execute (platform fetch)
→ HttpClient.postprocess (response extraction)
→ HttpClientResponse
→ HttpClientResponse.schemaJson(ResponseSchema)
→ typed response data
Incoming HTTP request
→ HttpServerRequest (platform-specific source wrapped)
→ HttpMiddleware.logger (logging)
→ HttpRouter (find-my-way-ts radix tree match)
→ RouteContext { params: Record<string, string> }
→ Route.Handler (endpoint logic)
→ HttpServerResponse.json(data)
→ HttpMiddleware.cors (CORS headers)
→ Response sent
1. DEFINE (pure data):
HttpApiEndpoint.get("getUser", "/users/:id")
→ HttpApiGroup.make("users").add(endpoint)
→ HttpApi.make("MyAPI").add(group)
2. IMPLEMENT (effectful layers):
HttpApiBuilder.api(api)
→ generates HttpRouter from endpoint definitions
→ validates path params, body, headers via Schema
→ routes to handler implementations
3. SERVE:
HttpApiBuilder.api(api)
.pipe(HttpServer.serve(HttpMiddleware.logger))
→ Layer<never, HttpServerError, HttpServer.HttpServer>
4. GENERATE (optional):
HttpApiClient.make(api) → type-safe client
OpenApi.fromApi(api) → OpenAPI spec
HttpApiSwagger.layer → Swagger UI
const ServerLive = HttpApiBuilder.api(api).pipe(
Layer.provide(HandlerLayers), // endpoint implementations
HttpServer.serve(HttpMiddleware.logger),
Layer.provide(NodeHttpServer.layer({ port: 3000 })),
Layer.provide(NodeHttpPlatform.layer)
);
// Run
Layer.launch(ServerLive);// Barrel import (most common)
import { HttpClient, HttpServer, FileSystem } from "@effect/platform";
// Direct module import (tree-shakeable)
import * as HttpClient from "@effect/platform/HttpClient";
// Platform implementation
import { NodeHttpServer } from "@effect/platform-node";// Typical Node.js server
Layer.mergeAll(
NodeHttpServer.layer({ port: 3000 }),
NodeFileSystem.layer,
NodeTerminal.layer,
NodeHttpPlatform.layer
);| Category | Modules |
|---|---|
| HTTP API & Docs | 12 |
| HTTP Server & Routing | 9 |
| HTTP Client | 6 |
| HTTP Core & Middleware | 10 |
| Platform Services | 7 |
| Process/Workers | 5 |
| Data Formats | 3 |
| URLs & Web | 3 |
| Sockets | 2 |
| Utilities | 4 |
| Total Public | ~56 |