| name | api-contract |
| description | Typed HTTP APIs with @effect/platform HttpApiBuilder |
| allowed-tools | Read, Write, Edit, Grep |
| token-budget | 450 |
api-contract
Why HttpApiBuilder
- Type-safe request/response schemas
- Automatic client generation
- Built-in error handling
- OpenAPI spec generation
- NO framework lock-in (no Hono, Express)
Define API Contract
import { HttpApi, HttpApiEndpoint, HttpApiGroup } from "@effect/platform";
import { Schema } from "effect";
const UserSchema = Schema.Struct({
id: Schema.String,
name: Schema.String,
email: Schema.String,
});
class UsersApi extends HttpApiGroup.make("users")
.add(
HttpApiEndpoint.get("getUser", "/users/:id")
.setPath(Schema.Struct({ id: Schema.String }))
.addSuccess(UserSchema)
)
.add(
HttpApiEndpoint.post("createUser", "/users")
.setPayload(Schema.Struct({ name: Schema.String, email: Schema.String }))
.addSuccess(UserSchema)
) {}
class MyApi extends HttpApi.empty.add(UsersApi) {}
Implement Handlers
import { HttpApiBuilder } from "@effect/platform";
const UsersApiLive = HttpApiBuilder.group(MyApi, "users", (handlers) =>
handlers
.handle("getUser", ({ path }) =>
Effect.gen(function* () {
const repo = yield* UserRepository;
return yield* repo.findById(path.id);
})
)
.handle("createUser", ({ payload }) =>
Effect.gen(function* () {
const repo = yield* UserRepository;
return yield* repo.create(payload);
})
)
);
Generate Client
import { HttpApiClient } from "@effect/platform";
// Type-safe client from API definition
const client = HttpApiClient.make(MyApi, {
baseUrl: "https://api.example.com",
});
// Usage
const user = yield* client.users.getUser({ path: { id: "123" } });