HTTP RPC Specification
Methods <-> Type mapping​
| HTTP 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 | 
Batching​
When 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 
inputwhich has the shapeRecord<number, unknown>. - We also need to pass 
batch=1as 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​
Given a router like this exposed at /api/trpc:​
server/router.ts
export const appRouter = 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:​
MyComponent.tsx
export function MyComponent() {
  const post1 = trpc.useQuery(['postById', '1'])
  const relatedPosts = trpc.useQuery(['relatedPosts', '1'])
  return (
    <pre>{
      JSON.stringify(
        {
          post1: post1.data ?? null,
          relatedPosts: relatedPosts.data ?? null,
        },
        null,
        4,
      )
    }</pre>
  )
}
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 Response​
Example output from server
[
  // result for `postById`
  {
    "result": {
      "data": {
        "id": "1",
        "title": "Hello tRPC",
        "body": "..."
        // ...
      }
    }
  },
  // result for `relatedPosts`
  {
    "result": {
      "data": [
        /* ... */
      ]
    }
  }
]
HTTP Response Specification​
In order to have a specification that works regardless of the transport layer we try to conform to JSON-RPC 2.0 where possible.
Successful Response​
Example JSON Response
{
  "result": {
    "data": {
      "id": "1",
      "title": "Hello tRPC",
      "body": "..."
    }
  }
}
{
  result: {
    data: TOutput; // output from procedure
  };
}
Error Response​
Example JSON Response
[
  {
    "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 Status​
PARSE_ERROR: 400,
BAD_REQUEST: 400,
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
TIMEOUT: 408,
CONFLICT: 409,
CLIENT_CLOSED_REQUEST: 499,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
METHOD_NOT_SUPPORTED: 405,
Error Codes <-> JSON-RPC 2.0 Error Codes​
Available 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
  CONFLICT: -32009, // 409
  PRECONDITION_FAILED: -32012, // 412
  PAYLOAD_TOO_LARGE: -32013, // 413
  CLIENT_CLOSED_REQUEST: -32099, // 499
} as const;
Dig deeper​
You can read more details by drilling into the TypeScript definitions in