Effect CommunityEC
Effect Community10mo ago
5 replies
tomchristensen

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 route. I tried some other combination of layers and got the /rpc route working but then got 404 on all my existing api routes (e.g. /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);
Was this page helpful?