Effect Rpc http client complete example

Languages

typescript5.6.3

Libraries

effect3.14.2
nodejs22.8.6
GithubCode

This snippet implements an RPC server and client using effect:

  • effect: Core library
  • @effect/rpc: RPC library
  • @effect/platform: HTTP client requests (web handler)

The implementation starts from api.ts. Inside it, we define all the requests supported by the RPC server. Each request is defined from a RpcGroup using Rpc.make:

  • error
  • success
  • payload

RpcGroup represents the requests definition, shared between server and client.

export class RpcAuth extends RpcGroup.make(
  Rpc.make("SignUpRequest", {
    error: RequestError,
    success: Schema.Boolean,
    payload: {
      email: Schema.NonEmptyString,
      password: Schema.String,
    },
  })
) {}

Server

server.ts defines the implementation of each request using toLayer:

const RpcAuthLayer = RpcAuth.toLayer({
  SignUpRequest: (params) =>
    Effect.gen(function* () {
      yield* Effect.log(params.email, params.password);
      return true;
    }),
});

We then convert RpcAuth to a web handler that accepts the standard web Request/Response model:

export const RpcWebHandler = RpcServer.toHttpApp(RpcAuth).pipe(
  Effect.map(HttpApp.toWebHandler),
);

route.ts shows an example of using the web handler for a next API route (passing Request and returning a Response).

Client

On the client you use RpcClient.make to derive a type-safe HTTP client that sends requests to the server API.

The client is fully type-safe since it's derived from the shared RpcAuth, with both success, error and payload types extracted from Rpc.make.

The configuration for the HTTP request is defined as RpcClient.Protocol (url, HttpClient, RpcSerialization), which is provided as a Layer to RpcAuthClient.

import { Rpc, RpcGroup } from "@effect/rpc";
import { Schema } from "effect";

class RequestError extends Schema.Class<RequestError>("RequestError")({
  errorMessage: Schema.String,
}) {}

// 👇 Rpc API group shared between server and client
export class RpcAuth extends RpcGroup.make(
  Rpc.make("SignUpRequest", {
    error: RequestError,
    success: Schema.Boolean,
    payload: {
      email: Schema.NonEmptyString,
      password: Schema.String,
    },
  })
) {}