Combining RpcServer and HttpApi in Effect Typescript
What's the best way to add Rpc to an existing HttpApi? I tried the following but I get a 404 on the
/rpc/rpc route. I tried some other combination of layers and got the /rpc/rpc route working but then got 404 on all my existing api routes (e.g. /health/health).import {
HttpApiBuilder,
HttpMiddleware,
HttpServer,
HttpServerResponse,
} from "@effect/platform";
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node";
import { RpcSerialization, RpcServer } from "@effect/rpc";
import { Config, Effect, Layer, pipe } from "effect";
import { createServer } from "node:http";
import {
HttpApiLive,
MyRpcs,
MyRpcsLive,
} from "myCoolApp";
const HealthLive = HttpApiBuilder.Router.use((router) =>
Effect.gen(function* () {
yield* router.get(
"/health",
HttpServerResponse.text("OK", { status: 200 }).pipe(
HttpMiddleware.withLoggerDisabled
)
);
})
);
const ServerLive = pipe(
Config.all({
host: Config.string("HOST").pipe(Config.withDefault("localhost")),
port: Config.integer("PORT").pipe(Config.withDefault(4000)),
}),
Effect.map(({ host, port }) =>
NodeHttpServer.layer(createServer, { host, port })
),
Layer.unwrapEffect
);
const RpcLayer = RpcServer.layer(MyRpcs).pipe(Layer.provide(MyRpcsLive));
const HttpProtocol = RpcServer.layerProtocolHttp({
path: "/rpc",
}).pipe(Layer.provide(RpcSerialization.layerNdjson));
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
Layer.provide(HealthLive),
Layer.provide(HttpApiLive),
Layer.provide(RpcLayer),
Layer.provide(HttpProtocol),
HttpServer.withLogAddress,
Layer.provide(ServerLive)
);
Layer.launch(HttpLive).pipe(NodeRuntime.runMain);import {
HttpApiBuilder,
HttpMiddleware,
HttpServer,
HttpServerResponse,
} from "@effect/platform";
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node";
import { RpcSerialization, RpcServer } from "@effect/rpc";
import { Config, Effect, Layer, pipe } from "effect";
import { createServer } from "node:http";
import {
HttpApiLive,
MyRpcs,
MyRpcsLive,
} from "myCoolApp";
const HealthLive = HttpApiBuilder.Router.use((router) =>
Effect.gen(function* () {
yield* router.get(
"/health",
HttpServerResponse.text("OK", { status: 200 }).pipe(
HttpMiddleware.withLoggerDisabled
)
);
})
);
const ServerLive = pipe(
Config.all({
host: Config.string("HOST").pipe(Config.withDefault("localhost")),
port: Config.integer("PORT").pipe(Config.withDefault(4000)),
}),
Effect.map(({ host, port }) =>
NodeHttpServer.layer(createServer, { host, port })
),
Layer.unwrapEffect
);
const RpcLayer = RpcServer.layer(MyRpcs).pipe(Layer.provide(MyRpcsLive));
const HttpProtocol = RpcServer.layerProtocolHttp({
path: "/rpc",
}).pipe(Layer.provide(RpcSerialization.layerNdjson));
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
Layer.provide(HealthLive),
Layer.provide(HttpApiLive),
Layer.provide(RpcLayer),
Layer.provide(HttpProtocol),
HttpServer.withLogAddress,
Layer.provide(ServerLive)
);
Layer.launch(HttpLive).pipe(NodeRuntime.runMain);