> ## Documentation Index
> Fetch the complete documentation index at: https://eo.utopy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build a Effect-aware oRPC router.

## Define a service and error

```ts title="users.ts" theme={null}
import { Effect } from "effect";
import { ORPCTaggedError } from "effect-orpc";
import * as z from "zod";

export const User = z.object({
  id: z.string(),
  name: z.string(),
});

const users: Array<z.infer<typeof User>> = [
  { id: "1", name: "Ada Lovelace" },
  { id: "2", name: "Grace Hopper" },
];

export class UsersRepo extends Effect.Service<UsersRepo>()("UsersRepo", {
  accessors: true,
  sync: () => ({
    findById: (id: string) => users.find((user) => user.id === id),
  }),
}) {}

export class UserNotFoundError extends ORPCTaggedError("UserNotFoundError", {
  status: 404,
  message: "User not found",
  schema: z.object({ id: z.string() }),
}) {}
```

## Create the router

```ts title="router.ts" theme={null}
import { os } from "@orpc/server";
import { eos } from "effect-orpc";
import * as z from "zod";

import { User, UserNotFoundError, UsersRepo } from "./users";

const effectProcedure = eos
  .provide(UsersRepo.Default)
  .errors({ UserNotFoundError });

export const router = {
  health: os.handler(() => "ok"),

  users: {
    get: effectProcedure
      .input(z.object({ id: z.string() }))
      .output(User)
      .effect(function* ({ input }) {
        const user = yield* UsersRepo.findById(input.id);

        if (!user) {
          return yield* new UserNotFoundError({
            data: { id: input.id },
          });
        }

        return user;
      }),
  },
};

export type Router = typeof router;
```

## Call it!

Use `.callable()` when you want to invoke a procedure directly in tests, scripts, or local examples.

```ts title="main.ts" theme={null}
import { router } from "./router";

const getUser = router.users.get.callable();

console.log(await getUser({ id: "1" }));
// { id: "1", name: "Ada Lovelace" }
```

## What happened

<Steps>
  <Step title="`eos` wrapped an oRPC builder">
    `eos` exposes familiar oRPC builder methods and adds Effect-aware methods
    such as `.provide(...)`, `.effect(...)`, and `.traced(...)`.
  </Step>

  <Step title="The service layer satisfied Effect requirements">
    `UsersRepo.Default` was provided before the handler, so `yield*`\ `
            UsersRepo.findById(...)` is available at compile-time.
  </Step>

  <Step title="The tagged error became an oRPC error">
    `UserNotFoundError` is yieldable in Effect code and serializable as an oRPC
    error.
  </Step>
</Steps>

## Next steps

<CardGroup cols={2}>
  <Card title="Mental model" icon="brain" href="/getting-started/mental-model">
    Learn how builders, layers, runtimes, and request boundaries fit together.
  </Card>

  <Card title="Effect procedures" icon="function" href="/capabilities/effect-procedures">
    Focus on `.effect(...)` handlers and their typed handler options.
  </Card>
</CardGroup>
