trpc-rest

Quick Start

Set up a REST API from a tRPC router in under 5 minutes.

1. Define your router with OpenAPI metadata

Add openapi metadata to any procedure you want exposed as a REST endpoint:

server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import type { OpenApiMeta } from 'trpc-rest';

const t = initTRPC.meta<OpenApiMeta>().create();

export const appRouter = t.router({
  getUser: t.procedure
    .meta({
      openapi: {
        method: 'GET',
        path: '/users/{id}',
        tags: ['Users'],
        summary: 'Get a user by ID',
      },
    })
    .input(z.object({ id: z.string() }))
    .output(z.object({ id: z.string(), name: z.string() }))
    .query(({ input }) => {
      return { id: input.id, name: 'Alice' };
    }),

  createUser: t.procedure
    .meta({
      openapi: {
        method: 'POST',
        path: '/users',
        tags: ['Users'],
        summary: 'Create a user',
      },
    })
    .input(z.object({ name: z.string(), email: z.string() }))
    .output(z.object({ id: z.string(), name: z.string() }))
    .mutation(({ input }) => {
      return { id: 'user-1', name: input.name };
    }),
});

export type AppRouter = typeof appRouter;

2. Create the REST handler

Wire the handler into your framework's routing. Here's Next.js App Router:

app/api/[...trpc]/route.ts
import { createOpenApiFetchHandler } from 'trpc-rest';
import { appRouter } from '@/server/router';

const handler = async (req: Request) => {
  return createOpenApiFetchHandler({
    router: appRouter,
    endpoint: '/api',
    req,
    createContext: async ({ req }) => {
      return {}; // your context factory
    },
  });
};

export { handler as GET, handler as POST, handler as PUT, handler as PATCH, handler as DELETE };

For other frameworks, the pattern is the same — pass any Request object and get a Response back.

3. Generate the OpenAPI spec

app/api/openapi.json/route.ts
import { generateOpenApiDocument } from 'trpc-rest';
import { appRouter } from '@/server/router';

export function GET() {
  const doc = generateOpenApiDocument(appRouter, {
    title: 'My API',
    version: '1.0.0',
    baseUrl: 'https://api.example.com',
  });

  return Response.json(doc);
}

Your API is now available at:

  • GET /api/users/{id} — fetch a user
  • POST /api/users — create a user
  • GET /api/openapi.json — OpenAPI 3.1.0 spec

4. Test it

# Get a user
curl http://localhost:3000/api/users/alice

# Create a user
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Bob", "email": "bob@example.com"}'

# Fetch the spec
curl http://localhost:3000/api/openapi.json

On this page