HTTP RPC Specification
#
Methods <-> Type mappingHTTP Method | Mapping | Notes |
---|---|---|
GET | .query() | Input JSON-stringified in query param. e.g. myQuery?input=${encodeURIComponent(JSON.stringify(input)) |
POST | .mutation() | Input as POST body. |
n/a | .subscription() | Subscriptions are not supported in HTTP transport |
#
BatchingWhen batching, we combine all parallel procedure calls of the same type in one request using a data loader.
- The called procedures' names are combined by a comma (
,
) in thepathname
- Input parameters are sent as a a query parameter called
input
which has the shapeRecord<number, unknown>
. - We also need to pass
batch=1
as a query parameter. - If the response has different statuses we send back
207 Multi-Status
(e.g. if one call errored and one succeeded)
#
Batching Example Request/api/trpc
:#
Given a router like this exposed at trpc .router<Context>() .query('postById', { input: String, async resolve({ input, ctx }) { const post = await ctx.post.findUnique({ where: { id: input }, }); return post; }, }) .query('relatedPosts', { input: String, async resolve({ ctx, input }) { const posts = await ctx.findRelatedPostsById(input) return posts; }, })
#
.. And two queries defined like this in a React component:function MyComponent() { const post1 = trpc.useQuery(['postById', '1']) const relatedPosts = trpc.useQuery(['relatedPosts', '1'])
// [...]}
#
The above would result in exactly 1 HTTP call with this data:Location property | Value |
---|---|
pathname | /api/trpc/postById,relatedPosts |
search | ?batch=1&input=%7B%220%22%3A%221%22%2C%221%22%3A%221%22%7D * |
*) input
in the above is the result of:
encodeURIComponent( JSON.stringify({ 0: '1', // <-- input for `postById` 1: '1', // <-- input for `relatedPosts` }))
#
Batching Example ResponseExample output from server
[ // result for `postById` { "id": null, "result": { "type": "data", "data": { "id": "1", "title": "Hello tRPC", "body": "..." // ... } } }, // result for `relatedPosts` { "id": null, "result": { "type": "data", "data": [ /* ... */ ] } }]
#
HTTP Response SpecificationIn order to have a specification that works regardless of the transport layer we try to conform to JSON-RPC 2.0 where possible.
#
Successful ResponseExample JSON Response
{ "id": null, "result": { "type": "data", "data": { "id": "1", "title": "Hello tRPC", "body": "..." } }}
{ id: null; result: { type: 'data'; data: TOutput; // output from procedure };}
#
Error ResponseExample JSON Response
[ { "id": null, "error": { "json": { "message": "Something went wrong", "code": -32600, // JSON-RPC 2.0 code "data": { // Extra, customizable, meta data "code": "INTERNAL_SERVER_ERROR", "httpStatus": 500, "stack": "...", "path": "post.add" } } } }]
- When possible, we propagate HTTP status codes from the error thrown.
- If the response has different statuses we send back
207 Multi-Status
(e.g. if one call errored and one succeeded) - For more on errors and how customize them see Error Formatting.
#
Error Codes <-> HTTP StatusPARSE_ERROR: 400,BAD_REQUEST: 400,NOT_FOUND: 404,INTERNAL_SERVER_ERROR: 500,UNAUTHORIZED: 401,FORBIDDEN: 403,TIMEOUT: 408,CLIENT_CLOSED_REQUEST: 499,PAYLOAD_TOO_LARGE: 413,METHOD_NOT_SUPPORTED: 405,
#
Error Codes <-> JSON-RPC 2.0 Error CodesAvailable codes & JSON-RPC code
/** * JSON-RPC 2.0 Error codes * * `-32000` to `-32099` are reserved for implementation-defined server-errors. * For tRPC we're copying the last digits of HTTP 4XX errors. */export const TRPC_ERROR_CODES_BY_KEY = { /** * Invalid JSON was received by the server. * An error occurred on the server while parsing the JSON text. */ PARSE_ERROR: -32700, /** * The JSON sent is not a valid Request object. */ BAD_REQUEST: -32600, // 400 /** * Internal JSON-RPC error. */ INTERNAL_SERVER_ERROR: -32603, // Implementation specific errors UNAUTHORIZED: -32001, // 401 FORBIDDEN: -32003, // 403 NOT_FOUND: -32004, // 404 METHOD_NOT_SUPPORTED: -32005, // 405 TIMEOUT: -32008, // 408 PAYLOAD_TOO_LARGE: -32013, // 413 CLIENT_CLOSED_REQUEST: -32099, // 499} as const;
#
Dig deeperYou can read more details by drilling into the TypeScript definitions in