Inside the entry file at main.ts
we collect all the layers and execute them in a nodejs server (node:http
).
We compose the main app layer from HttpApiBuilder.api
, providing all the required dependencies:
const MainApiLive = HttpApiBuilder.api(MainApi).pipe(
Layer.provide(PaddleApiLive)
);
It's recommended to provide all the dependencies at the service level, so that the final
main
only contains the coreHttp
layers:
dependencies
when usingEffect.Service
Layer.provide
when usingContext.Tag
The server is based on HttpApiBuilder.serve
, providing a NodeHttpServer
layer that creates the server using node:http
on port 3000
:
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
Layer.provide(HttpApiBuilder.middlewareCors()),
Layer.provide(MainApiLive),
HttpServer.withLogAddress,
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
);
main.ts
is then executed using NodeRuntime
to start the server:
Layer.launch(HttpLive).pipe(NodeRuntime.runMain);
At the top of the file we also import dotenv/config
to load the environment variables from .env
file.
The final result is as follows:
import "dotenv/config";
import { MainApi } from "@app/api-client";
import { HttpApiBuilder, HttpMiddleware, HttpServer } from "@effect/platform";
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node";
import { Layer } from "effect";
import { createServer } from "node:http";
import { PaddleApiLive } from "./paddle-api";
const MainApiLive = HttpApiBuilder.api(MainApi).pipe(
Layer.provide(PaddleApiLive)
);
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
Layer.provide(HttpApiBuilder.middlewareCors()),
Layer.provide(MainApiLive),
HttpServer.withLogAddress,
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
);
Layer.launch(HttpLive).pipe(NodeRuntime.runMain);
Now executing pnpm run dev
will use tsx
to execute main.ts
and start the server.
"scripts": {
"dev": "tsx watch src/main.ts",
"typecheck": "tsc"
}
pnpm run dev