Effect HTTP Node.js Server
effect-http-node is a crucial adapter package within the `effect-ts` ecosystem, providing the Node.js-specific implementation for serving declarative HTTP APIs built with `effect-http`. It leverages the `@effect/platform-node` package to bridge `effect-http`'s server abstractions with Node.js's native HTTP server capabilities, enabling developers to run highly type-safe, functional, and concurrently managed web services. The current stable version is 0.27.0. This package, along with `effect-http` and core `effect` libraries, follows a rapid release cadence, often undergoing minor version bumps to align with updates in its peer dependencies, reflecting the active development of the `effect-ts` project. Its key differentiator lies in enabling the `effect-ts` programming model—emphasizing structured concurrency, resource management, and robust error handling—directly within Node.js for HTTP services, providing a strong alternative to traditional imperative frameworks. It does not introduce new HTTP API paradigms but rather provides the runtime environment for `effect-http`'s existing ones.
Common errors
-
Error: EADDRINUSE: address already in use :::3000
cause The specified port (e.g., 3000) is already occupied by another process.fixChange the `port` in `NodeServer.make` to an available port, or terminate the process currently using the port. -
TypeError: (0 , effect_http_node_1.NodeServer.make) is not a function
cause This error typically indicates an ESM/CJS module incompatibility. You might be trying to `require` an ESM-only module or using incorrect named/default import syntax.fixEnsure your project is configured for ESM (e.g., `"type": "module"` in `package.json`) and use `import { NodeServer } from 'effect-http-node';` syntax. Avoid `require()` for Effect-TS modules. -
TS2345: Argument of type 'Api<...>' is not assignable to parameter of type 'HttpApp<...>'
cause The `NodeServer.make` function expects an `HttpApp` (an implemented router), not just an `Api` definition. The `Api` needs to be transformed into a `Router` (application) with handlers.fixEnsure you've created an `EffectHttp.Router` instance by calling `Router.make(api).pipe(Router.handle(...))` before passing it to `NodeServer.make`.
Warnings
- breaking The `effect-http` library, and by extension `effect-http-node`, is considered 'deprecated in favour of the @effect/platform' as of August 30, 2024. Users are advised to migrate to `@effect/platform` for future-proof HTTP server development within the Effect ecosystem.
- gotcha Due to the rapid development and interconnectedness of the Effect-TS ecosystem, frequent minor version updates across `effect`, `@effect/platform`, `@effect/platform-node`, and `effect-http` are common. Mismatched peer dependencies can lead to runtime errors or subtle type-system inconsistencies.
- gotcha The Effect ecosystem is designed for TypeScript and leverages advanced type features. Incorrect type inference or usage can lead to complex type errors. While powerful, this can be a learning curve for developers new to Effect.
Install
-
npm install effect-http-node -
yarn add effect-http-node -
pnpm add effect-http-node
Imports
- NodeServer
const NodeServer = require('effect-http-node').NodeServer;import { NodeServer } from 'effect-http-node'; - NodeRuntime
import { NodeRuntime } from '@effect/platform-node';import * as NodePlatform from '@effect/platform-node'; // ... NodePlatform.NodeRuntime.runMain(program);
- Api
import { Api } from 'effect-http';
Quickstart
import { pipe, Effect } from 'effect';
import { Api, Router } from 'effect-http';
import { NodeServer } from 'effect-http-node';
import * as NodePlatform from '@effect/platform-node';
import * as Logger from '@effect/data/Logger';
// 1. Define your API using effect-http
const api = Api.make().pipe(
Api.get('hello', '/hello', {
response: Api.string(),
}),
Api.post('echo', '/echo', {
request: {
body: Api.string(),
},
response: Api.string(),
}),
);
// 2. Implement the API handlers
const app = Router.make(api).pipe(
Router.handle('hello', () => Effect.succeed('Hello from Effect-HTTP!')),
Router.handle('echo', ({ body }) => Effect.succeed(`You said: ${body}`)),
);
// 3. Create a Node.js server from the API and application
const server = NodeServer.make(app, { port: 3000 });
// 4. Run the server using NodePlatform.NodeRuntime
pipe(
server.pipe(
Effect.tap(() =>
Effect.logInfo('Server started on http://localhost:3000'),
),
),
NodePlatform.NodeRuntime.runMain,
);