tRPC-SvelteKit

tRPC is a framework for building type-safe APIs in TypeScript. It provides a set of tools and conventions for defining your API, including endpoints, input and output types, and middlewares.

Endpoints

All the endpoints are defined inside src/trpc/routes folder.

Creating a new endpoint

To create a new endpoint, you can create a new file inside the src/trpc/routes folder. For example, to create a hello endpoint, you can create a file called hello.ts with the following content:

trpc/routes/hello.ts
import { t } from "$trpc/t";
import { helloWorldSchema } from "./schema";

export const hello = t.router({
  world: t.procedure.input(helloWorldSchema).query(async ({ input }) => {
    return `Hello, ${input.name}!`;
  })
  loggedUser: t.procedure.query(async ({ ctx }) => {
    return ctx.user;
});

Then, you can import the endpoint in the src/trpc/index.ts file and add it to the routes object:

trpc/index.ts
import { hello } from "./hello";

export const routes = {
  ...hello
};

Schemas

SvelteKit does not allow executing server-side code on the client side: tRPC endpoints run on the server.

So to better aligns with our use of Svelte forms, allowing us to derive the schema directly on the client side, we can define the schema in a separate file and import it into the endpoint file.

trpc/routes/schema.ts
import { z } from "zod";

export const helloWorldSchema = z.object({
  name: z.string()
});

Context

The ctx object is a special object that contains information about the current request, including the user, the request body, and other request-specific information. You can access the ctx object inside your endpoint handlers to perform operations like authentication, logging, and error handling.

You can add additioanl context to the ctx object by adding a middleware to the src/trpc/context folder.

trpc/context.ts
export async function createContext(event: RequestEvent) {
  try {
    return {
      user: event.locals.user,
      team: event.locals.user?.teams.current
    };
  } catch {
    return { user: null, team: null };
  }
}

Usage

You can use the endpoint in your frontend like

import { trpc } from "$trpc;

const sayHello = async () => {
  const r = await trpc().hello.world.query({ name: "World" });
  console.log(r.data);
}