Effect-TS 1: Http backend demo
If you are unfamiliar with Effect Systems, ZIO, or Effect-TS, I recommend reading the following article: https://www.sandromaglione.com/articles/typescript-code-with-and-without-effect and then returning here.
Other good information about Effect-TS can be found on:
Disclaimer: The following article will work with Effect-TS Version 3 hoping that the APIs will stay compatible for the near future.
Let's make our lives easier by using Bun for this project. Bun is fantastic for quickly starting small TypeScript projects because it’s super fast and easy to use. It combines a native TypeScript transpiler, a built-in bundler, and a speedy package manager, so we can dive right into coding without the hassle of setting up multiple tools.
- Open a terminal and navigate to the directory where you want to create your project. Create a clean folder:
mkdir effect-web
cd effect-web
- Run the following command to initialize a new Bun project:
bun init
We will just use the default options. This command will create a new Bun project with the default project structure and configuration files.
- Once the project is initialized, you can start adding your code and customizing the project according to your needs. Let's install some basic dependencies for what we want to do with Effect Http.
bun add effect effect-http effect-http-node @effect/platform @effect/platform-node
- We now create a new Typescript file with the name
app.ts
and the following content
import { Schema } from "@effect/schema";
import { pipe } from "effect";
import { Api } from "effect-http";
// Define the response schema for the user endpoint
const UserResponse = Schema.Struct({
name: Schema.String,
id: pipe(Schema.Number, Schema.int(), Schema.positive())
});
// Define the request query schema for the getUser endpoint
const GetUserQuery = Schema.Struct({ id: Schema.NumberFromString });
// Create an instance of the Effect HTTP API
const api = pipe(
Api.make({ title: "Users API" }),
Api.addEndpoint(
pipe(
Api.get("getUser", "/user"),
Api.setResponseBody(UserResponse),
Api.setRequestQuery(GetUserQuery)
)
)
);
Here we are using the library https://github.com/sukovanej/effect-http. It's possible that this library becomes part of the official Effect-TS framework later on.
The code above demonstrates how to create a simple web server using Effect HTTP. It defines a response schema for the user endpoint and a request query schema for the getUser endpoint. The Api.make
function is used to create the definition of our API, and the Api.addEndpoint
function is used to add an endpoint to the API routes. This is not the actual implementation; you can think of it as an interface.
- The actual implementation is achieved by changing our imports to
import { Schema } from "@effect/schema";
import { Effect, pipe } from "effect";
import { Api, RouterBuilder } from "effect-http";
and implementing the actual execution as
const app = pipe(
RouterBuilder.make(api),
RouterBuilder.handle("getUser", ({ query }) =>
Effect.succeed({ name: "milan", id: query.id })),
RouterBuilder.build
)
- We execute the server by adding
import { NodeRuntime } from "@effect/platform-node"
import { NodeServer } from "effect-http-node";
// remaining code
app.pipe(NodeServer.listen({ port: 3000 }), NodeRuntime.runMain);
- In another terminal we call the server by using curl
curl "http://localhost:3000/user?id=1"
which will corretly print {"name":"milan","id":1}
to STDOUT.
This is the first part of a series about Effect-TS in backend engineering. Future topics will cover:
More features from Effect-HTTP
Layers and Services in Effect-TS
Interaction with OpenAI APIs
Telemetry through OpenTelemetry
I hope you enjoyed this introduction to writing functional TypeScript code with Effect-TS.
Subscribe to my newsletter
Read articles from Alexander Knips directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Alexander Knips
Alexander Knips
Developer from Germany who moved to the Bay area who is excited about functional programming, software architecture and much more.