@aletso/effect-route
v0.1.4
Published
Effect-native RPC route contract definitions
Readme
@aletso/effect-route
Typed route contracts for Effect RPC.
Use this package to define payload, success, and error schemas once, group routes with a prefix, and expose a typed RpcGroup for server wiring.
Install
pnpm add @aletso/effect-route @effect/rpc effectDefine routes with schemas and middleware
Example domain contract setup.
import * as Route from "@aletso/effect-route/Route";
import * as RouteGroup from "@aletso/effect-route/RouteGroup";
import * as Schema from "effect/Schema";
import { AuthMiddleware } from "../Policy";
export const SurveyListItem = Schema.Struct({
id: Schema.String,
title: Schema.String,
});
export const SurveyPublished = Schema.Struct({
id: Schema.String,
title: Schema.String,
status: Schema.Literal("published"),
});
export class SurveyNotFound extends Schema.TaggedError<SurveyNotFound>()(
"SurveyNotFound",
{
id: Schema.String,
},
) {}
export class Group extends RouteGroup.make(
Route.make("find_many", {
success: Schema.Array(SurveyListItem),
}).middleware(AuthMiddleware),
Route.make("find_by_id", {
success: SurveyListItem,
error: SurveyNotFound,
payload: Schema.Struct({ id: Schema.String }),
}).middleware(AuthMiddleware),
Route.make("publish", {
success: SurveyPublished,
error: SurveyNotFound,
payload: Schema.Struct({ id: Schema.String }),
}).middleware(AuthMiddleware),
).prefix("survey_") {}After prefixing:
Group.find_by_id._tagissurvey_find_by_idGroup.find_by_id.keyis@aletso/effect-route/Route/survey_find_by_id
Merge route groups into one RPC domain
Example domain-level RpcGroup merge.
import * as RpcGroup from "@effect/rpc/RpcGroup";
import * as Health from "./api/Health";
import * as Identity from "./api/Identity";
import * as Survey from "./api/Survey";
export class DomainRpc extends RpcGroup.make().merge(
Health.Group.RpcGroup,
Identity.Group.RpcGroup,
Survey.Group.RpcGroup,
) {}Bind handlers on the server
RouteGroup.RpcGroup gives a ready to use Effect RPC group.
import { Group as SurveyRoutes } from "../domain/api/Survey";
import { SurveyService } from "../server/public/survey/service";
import * as Effect from "effect/Effect";
export const SurveyRpcLive = SurveyRoutes.RpcGroup.toLayer({
survey_find_many: () => Effect.flatMap(SurveyService, (s) => s.findMany),
survey_find_by_id: ({ id }) =>
Effect.flatMap(SurveyService, (s) => s.findById(id)),
survey_publish: ({ id }) =>
Effect.flatMap(SurveyService, (s) => s.publish(id)),
});Use the same contracts in the data layer
These contracts are designed to be consumed by @aletso/atom-query.
import * as Query from "@aletso/atom-query/Query";
import { Group as SurveyRoutes } from "../domain/api/Survey";
export const surveyFindById = Query.familyFromRoute(SurveyRoutes.find_by_id, {
effect: ({ id }) => api.findById(id),
runtime,
});API surface
Route.make(...)route.middleware(...)route.prefix(...)RouteGroup.make(...)routeGroup.prefix(...)routeGroup.merge(...)routeGroup.middleware(...)routeGroup.RpcGroup
