Skip to content

Instantly share code, notes, and snippets.

@titouancreach
Created March 24, 2025 10:01
Show Gist options
  • Save titouancreach/b605ed4b2730b838c341d41c6d31a7aa to your computer and use it in GitHub Desktop.
Save titouancreach/b605ed4b2730b838c341d41c6d31a7aa to your computer and use it in GitHub Desktop.
import {
FetchHttpClient,
HttpRouter,
HttpServer,
HttpServerResponse,
} from "@effect/platform";
import { BunHttpServer, BunRuntime } from "@effect/platform-bun";
import {
Rpc,
RpcClient,
RpcGroup,
RpcSerialization,
RpcServer,
} from "@effect/rpc";
import { toWebHandler } from "@effect/rpc/RpcServer";
import { Context, Effect, Layer, Schema as S } from "effect";
class UserGroup extends RpcGroup.make(
Rpc.make("GetUser", {
error: S.Never,
payload: {
id: S.Number,
},
success: S.Struct({
name: S.String,
}),
}),
) {}
class AdminGroup extends RpcGroup.make(
Rpc.make("GetAdmin", {
error: S.Never,
payload: {
id: S.Number,
},
success: S.Struct({
name: S.String,
}),
}),
) {}
// implémentation
export const UserLive = UserGroup.toLayer(
Effect.gen(function* () {
return {
GetUser: Effect.fn("GetUser")(function* ({ id }) {
yield* Effect.log("Called GetUser");
return {
name: "John Doe",
};
}),
};
}),
);
export const AdminLive = AdminGroup.toLayer(
Effect.gen(function* () {
return {
GetAdmin: Effect.fn("GetAdmin")(function* ({ id }) {
yield* Effect.log("Called GetAdmin");
return {
name: "Admin",
};
}),
};
}),
);
export class UserClient extends Context.Tag("UserClient")<
UserClient,
RpcClient.RpcClient<RpcGroup.Rpcs<typeof UserGroup>>
>() {
static layer = Layer.scoped(UserClient, RpcClient.make(UserGroup));
}
export class AdminClient extends Context.Tag("AdminClient")<
AdminClient,
RpcClient.RpcClient<RpcGroup.Rpcs<typeof AdminGroup>>
>() {
static layer = Layer.scoped(AdminClient, RpcClient.make(AdminGroup));
}
const app = toWebHandler(AdminGroup.merge(UserGroup), {
layer: Layer.mergeAll(AdminLive, UserLive).pipe(
Layer.merge(RpcSerialization.layerJson),
Layer.merge(HttpServer.layerContext),
),
});
const app2 = RpcServer.toHttpApp(AdminGroup.merge(UserGroup)).pipe(
Effect.provide(AdminLive),
Effect.provide(UserLive),
Effect.provide(RpcSerialization.layerJson),
);
const Router = Effect.gen(function* () {
const _app = yield* app2;
return HttpRouter.empty.pipe(
HttpRouter.mountApp("/rpc", _app),
HttpServer.serve(),
Layer.provide(BunHttpServer.layer({ port: 3000 })),
);
});
const AllClients = Layer.mergeAll(UserClient.layer, AdminClient.layer);
const ClientRuntime = AllClients.pipe(
Layer.provide(
RpcClient.layerProtocolHttp({
url: "http://localhost:3000/rpc",
}),
),
Layer.provide(RpcSerialization.layerJson),
Layer.provide(FetchHttpClient.layer),
);
const clientMain = Effect.gen(function* () {
const admin = yield* AdminClient;
const adminUser = yield* admin.GetAdmin({ id: 1 });
console.log(adminUser);
const client = yield* UserClient;
const user = yield* client.GetUser({ id: 1 });
console.log(user);
console.log("finished");
}).pipe(Effect.provide(ClientRuntime), Effect.delay("500 millis"));
const clientServer = Effect.all(
[Layer.launch(Layer.unwrapScoped(Router)), clientMain],
{
concurrency: 2,
},
);
BunRuntime.runMain(clientServer);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment