API Handler
tRPC is not a backend of its own, but rather lives inside of other backends such as Next.js or Express. Despite that, most of tRPC's features and syntax are the same no matter which backend you are using. The API handler, also called adapter, enables this by acting as the glue between HTTP requests to your backend and tRPC.
The API Handler sits on a route in your server (usually /api/trpc
, but this is just a convention) and processes all requests to that route and its subroutes. It receives a request from the server, uses the createContext
function to generate context, and then sends the request and context to a procedure in the router.
It can also take some optional arguments such as onError
, a callback function that runs whenever an error is thrown inside of a procedure.
Below is an example implementation in Next.js. The process is similar for AWS Lambda, Express, Fastify, and the Fetch API.
Next.js example
pages/api/trpc/[trpc].tsts
import { createNextApiHandler } from '@trpc/server/adapters/next';import { createContext } from '../../../server/trpc/context';import { appRouter } from '../../../server/trpc/router/_app';// export API handlerexport default createNextApiHandler({router: appRouter, // your outermost router, see https://trpc.io/docs/procedurescreateContext, // your request context, see https://trpc.io/docs/context});
pages/api/trpc/[trpc].tsts
import { createNextApiHandler } from '@trpc/server/adapters/next';import { createContext } from '../../../server/trpc/context';import { appRouter } from '../../../server/trpc/router/_app';// export API handlerexport default createNextApiHandler({router: appRouter, // your outermost router, see https://trpc.io/docs/procedurescreateContext, // your request context, see https://trpc.io/docs/context});
Advanced Usage
While you can usually just "set and forget" the API Handler as shown above, sometimes you might want to modify it further.
The API handler that is created by createNextApiHandler
and equivalents in other frameworks is just a function that takes req
and res
objects. This means you can also modify those objects before passing them to the handler, for example to enable CORS.
pages/api/trpc/[trpc].tsts
import { createNextApiHandler } from '@trpc/server/adapters/next';import { createContext } from '../../../server/trpc/context';import { appRouter } from '../../../server/trpc/router/_app';// create the API handler, but don't return it yetconst nextApiHandler = createNextApiHandler({router: appRouter,createContext,});// @see https://nextjs.org/docs/api-routes/introductionexport default async function handler(req: NextApiRequest,res: NextApiResponse,) {// Modify `req` and `res` objects here// In this case, we are enabling CORSres.setHeader('Access-Control-Allow-Origin', '*');res.setHeader('Access-Control-Request-Method', '*');res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');res.setHeader('Access-Control-Allow-Headers', '*');if (req.method === 'OPTIONS') {res.writeHead(200);return res.end();}// pass the (modified) req/res to the handlerreturn nextApiHandler(req, res);}
pages/api/trpc/[trpc].tsts
import { createNextApiHandler } from '@trpc/server/adapters/next';import { createContext } from '../../../server/trpc/context';import { appRouter } from '../../../server/trpc/router/_app';// create the API handler, but don't return it yetconst nextApiHandler = createNextApiHandler({router: appRouter,createContext,});// @see https://nextjs.org/docs/api-routes/introductionexport default async function handler(req: NextApiRequest,res: NextApiResponse,) {// Modify `req` and `res` objects here// In this case, we are enabling CORSres.setHeader('Access-Control-Allow-Origin', '*');res.setHeader('Access-Control-Request-Method', '*');res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');res.setHeader('Access-Control-Allow-Headers', '*');if (req.method === 'OPTIONS') {res.writeHead(200);return res.end();}// pass the (modified) req/res to the handlerreturn nextApiHandler(req, res);}