Define an API endpoint
To define a new API endpoint you can either create a new module or add a new endpoint to an existing module.
Create a new module
To create a new module you can create a new folder in the packages/api/modules folder. For example modules/posts. In this folder create a router.ts file and a procedures folder.
Then create a new .ts file for the endpoint in the procedures folder. For example modules/posts/procedures/published-posts.ts:
import { z } from "zod";
import { publicProcedure } from "../../../orpc/procedures";
import { db } from "@repo/database";
export const publishedPosts = publicProcedure
.route({
method: "GET",
path: "/posts/published",
tags: ["Posts"],
summary: "List published posts",
})
.handler(async () => {
const posts = await db.post.findMany({
where: {
published: true,
},
});
return posts;
});Create the module router
Create a router.ts file in your module folder to export the endpoints:
import { publishedPosts } from "./procedures/published-posts";
export const postsRouter = {
publishedPosts,
};Register module router
To make the module and its endpoints available in the API you need to register the router in the packages/api/orpc/router.ts file:
import { postsRouter } from "../modules/posts/router";
export const router = publicProcedure.router({
// ...existing routers
posts: postsRouter,
});Using input validation
You can add input validation to your endpoints using Zod schemas:
import { z } from "zod";
import { publicProcedure } from "../../../orpc/procedures";
import { db } from "@repo/database";
export const getPost = publicProcedure
.route({
method: "GET",
path: "/posts/{id}",
tags: ["Posts"],
summary: "Get a post by ID",
})
.input(
z.object({
id: z.string(),
}),
)
.handler(async ({ input: { id } }) => {
const post = await db.post.findUnique({
where: { id },
});
return post;
});Using middleware
You can chain middleware to add additional context to your procedures. For example, to add locale information:
import { localeMiddleware } from "../../../orpc/middleware/locale-middleware";
import { protectedProcedure } from "../../../orpc/procedures";
export const myEndpoint = protectedProcedure
.use(localeMiddleware)
.route({
method: "POST",
path: "/my-endpoint",
})
.handler(async ({ context: { user, locale } }) => {
// locale is now available in the context
return { user: user.name, locale };
});