HTTP RPC 规范
方法 <-> 类型映射
¥Methods <-> Type mapping
HTTP 方法 | 测绘 | 注意 |
---|---|---|
GET | .query() | 在查询参数中输入 JSON 字符串。 例如 myQuery?input=${encodeURIComponent(JSON.stringify(input))} |
POST | .mutation() | 作为 POST 正文输入。 |
不适用 | .subscription() | HTTP 传输不支持订阅 |
访问嵌套过程
¥Accessing nested procedures
嵌套过程由点分隔,因此下面对 byId
的请求最终将成为对 /api/trpc/post.byId
的请求。
¥Nested procedures are separated by dots, so for a request to byId
below would end up being a request to /api/trpc/post.byId
.
ts
export const appRouter = router({post: router({byId: publicProcedure.input(String).query(async (opts) => {// [...]}),}),});
ts
export const appRouter = router({post: router({byId: publicProcedure.input(String).query(async (opts) => {// [...]}),}),});
批量
¥Batching
批处理时,我们使用数据加载器将同一 HTTP 方法的所有并行过程调用合并到一个请求中。
¥When batching, we combine all parallel procedure calls of the same HTTP method in one request using a data loader.
被调用过程的名称由逗号 (
,
) 组合在pathname
中¥The called procedures' names are combined by a comma (
,
) in thepathname
输入参数作为名为
input
的查询参数发送,其形状为Record<number, unknown>
。¥Input parameters are sent as a query parameter called
input
which has the shapeRecord<number, unknown>
.我们还需要传递
batch=1
作为查询参数。¥We also need to pass
batch=1
as a query parameter.如果响应有不同的状态,我们发回
207 Multi-Status
(例如,如果一个调用出错而一个调用成功)¥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 /api/trpc
:
server/router.tstsx
export const appRouter = t.router({postById: t.procedure.input(String).query(async (opts) => {const post = await opts.ctx.post.findUnique({where: { id: opts.input },});return post;}),relatedPosts: t.procedure.input(String).query(async (opts) => {const posts = await opts.ctx.findRelatedPostsById(opts.input);return posts;}),});
server/router.tstsx
export const appRouter = t.router({postById: t.procedure.input(String).query(async (opts) => {const post = await opts.ctx.post.findUnique({where: { id: opts.input },});return post;}),relatedPosts: t.procedure.input(String).query(async (opts) => {const posts = await opts.ctx.findRelatedPostsById(opts.input);return posts;}),});
...在 React 组件中定义了两个这样的查询:
¥... And two queries defined like this in a React component:
MyComponent.tsxtsx
export function MyComponent() {const post1 = trpc.postById.useQuery('1');const relatedPosts = trpc.relatedPosts.useQuery('1');return (<pre>{JSON.stringify({post1: post1.data ?? null,relatedPosts: relatedPosts.data ?? null,},null,4,)}</pre>);}
MyComponent.tsxtsx
export function MyComponent() {const post1 = trpc.postById.useQuery('1');const relatedPosts = trpc.relatedPosts.useQuery('1');return (<pre>{JSON.stringify({post1: post1.data ?? null,relatedPosts: relatedPosts.data ?? null,},null,4,)}</pre>);}
以上将导致使用此数据进行 1 个 HTTP 调用:
¥The above would result in exactly 1 HTTP call with this data:
位置属性 | 值 |
---|---|
pathname | /api/trpc/postById,relatedPosts |
search | ?batch=1&input=%7B%220%22%3A%221%22%2C%221%22%3A%221%22%7D * |
*) 上面的 input
是以下结果:
¥*) input
in the above is the result of:
ts
encodeURIComponent(JSON.stringify({0: '1', // <-- input for `postById`1: '1', // <-- input for `relatedPosts`}),);
ts
encodeURIComponent(JSON.stringify({0: '1', // <-- input for `postById`1: '1', // <-- input for `relatedPosts`}),);
批处理示例响应
¥Batching Example Response
Example output from server
json
[// result for `postById`{"result": {"data": {"id": "1","title": "Hello tRPC","body": "..."// ...}}},// result for `relatedPosts`{"result": {"data": [/* ... */]}}]
json
[// result for `postById`{"result": {"data": {"id": "1","title": "Hello tRPC","body": "..."// ...}}},// result for `relatedPosts`{"result": {"data": [/* ... */]}}]
HTTP 响应规范
¥HTTP Response Specification
为了拥有一个无论传输层如何都能工作的规范,我们尝试尽可能遵守 JSON-RPC 2.0。
¥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
json
{"result": {"data": {"id": "1","title": "Hello tRPC","body": "..."}}}
json
{"result": {"data": {"id": "1","title": "Hello tRPC","body": "..."}}}
ts
{result: {data: TOutput; // output from procedure}}
ts
{result: {data: TOutput; // output from procedure}}
错误响应
¥Error Response
Example JSON Response
json
[{"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"}}}}]
json
[{"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"}}}}]
如果可能,我们会传播抛出的错误中的 HTTP 状态代码。
¥When possible, we propagate HTTP status codes from the error thrown.
如果响应有不同的状态,我们发回
207 Multi-Status
(例如,如果一个调用出错而一个调用成功)¥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 to customize them see Error Formatting.
错误代码 <-> HTTP 状态
¥Error Codes <-> HTTP Status
ts
PARSE_ERROR: 400,BAD_REQUEST: 400,UNAUTHORIZED: 401,NOT_FOUND: 404,FORBIDDEN: 403,METHOD_NOT_SUPPORTED: 405,TIMEOUT: 408,CONFLICT: 409,PRECONDITION_FAILED: 412,PAYLOAD_TOO_LARGE: 413,UNPROCESSABLE_CONTENT: 422,TOO_MANY_REQUESTS: 429,CLIENT_CLOSED_REQUEST: 499,INTERNAL_SERVER_ERROR: 500,NOT_IMPLEMENTED: 501,
ts
PARSE_ERROR: 400,BAD_REQUEST: 400,UNAUTHORIZED: 401,NOT_FOUND: 404,FORBIDDEN: 403,METHOD_NOT_SUPPORTED: 405,TIMEOUT: 408,CONFLICT: 409,PRECONDITION_FAILED: 412,PAYLOAD_TOO_LARGE: 413,UNPROCESSABLE_CONTENT: 422,TOO_MANY_REQUESTS: 429,CLIENT_CLOSED_REQUEST: 499,INTERNAL_SERVER_ERROR: 500,NOT_IMPLEMENTED: 501,
错误代码 <-> JSON-RPC 2.0 错误代码
¥Error Codes <-> JSON-RPC 2.0 Error Codes
Available codes & JSON-RPC code
ts
/*** 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 errorINTERNAL_SERVER_ERROR: -32603,NOT_IMPLEMENTED: -32603,// Implementation specific errorsUNAUTHORIZED: -32001, // 401FORBIDDEN: -32003, // 403NOT_FOUND: -32004, // 404METHOD_NOT_SUPPORTED: -32005, // 405TIMEOUT: -32008, // 408CONFLICT: -32009, // 409PRECONDITION_FAILED: -32012, // 412PAYLOAD_TOO_LARGE: -32013, // 413UNPROCESSABLE_CONTENT: -32022, // 422TOO_MANY_REQUESTS: -32029, // 429CLIENT_CLOSED_REQUEST: -32099, // 499} as const;
ts
/*** 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 errorINTERNAL_SERVER_ERROR: -32603,NOT_IMPLEMENTED: -32603,// Implementation specific errorsUNAUTHORIZED: -32001, // 401FORBIDDEN: -32003, // 403NOT_FOUND: -32004, // 404METHOD_NOT_SUPPORTED: -32005, // 405TIMEOUT: -32008, // 408CONFLICT: -32009, // 409PRECONDITION_FAILED: -32012, // 412PAYLOAD_TOO_LARGE: -32013, // 413UNPROCESSABLE_CONTENT: -32022, // 422TOO_MANY_REQUESTS: -32029, // 429CLIENT_CLOSED_REQUEST: -32099, // 499} as const;
深入挖掘
¥Dig deeper
你可以通过深入研究 TypeScript 定义来阅读更多详细信息
¥You can read more details by drilling into the TypeScript definitions in