본문으로 건너뛰기
버전: 11.x

HTTP RPC 사양

메서드 <-> 타입 매핑

HTTP 메서드매핑참고사항
GET.query()쿼리 매개변수에 입력을 JSON 문자열로 인코딩합니다.
예: myQuery?input=${encodeURIComponent(JSON.stringify(input))}
POST.mutation()입력을 POST 본문으로 전송합니다.
GET.subscription()구독은 httpSubscriptionLink를 사용하는 서버 전송 이벤트 또는 wsLink를 사용하는 WebSocket을 통해 지원됩니다.

중첩 프로시저에 액세스

중첩 프로시저는 마침표로 구분되므로, 아래에서 byId에 대한 요청은 /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) => {
// [...]
}),
}),
});

배치 처리

배치 처리 시, 데이터 로더를 사용하여 동일한 HTTP 메서드를 사용하는 모든 병렬 프로시저 호출을 하나의 요청으로 결합합니다.

  • 호출된 프로시저 이름은 pathname에서 쉼표(,)로 결합됩니다.
  • 입력 매개변수는 Record<number, unknown> 형식을 가진 input이라는 이름의 쿼리 매개변수로 전송됩니다.
  • 또한 batch=1을 쿼리 매개변수로 전달해야 합니다.
  • 응답의 상태가 서로 다른 경우, 207 Multi-Status를 반환합니다. (예: 한 호출이 오류가 발생하고 다른 호출이 성공한 경우)

배치 처리 예제 요청

/api/trpc에 노출된 다음과 같은 라우터가 있다고 가정하면:

server/router.ts
tsx
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.ts
tsx
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 컴포넌트에서 다음과 같이 두 개의 쿼리가 정의되어 있다고 가정하면:

MyComponent.tsx
tsx
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.tsx
tsx
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 호출로 이어집니다:

위치 속성
pathname/api/trpc/postById,relatedPosts
search?batch=1&input=%7B%220%22%3A%221%22%2C%221%22%3A%221%22%7D *

*) 위의 input은 다음 결과입니다:

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`
}),
);

배치 처리 예제 응답

서버에서 반환된 예제 출력
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 응답 사양

트랜스포트 계층에 관계없이 작동하는 사양을 갖추기 위해 가능한 한 JSON-RPC 2.0에 따르도록 노력합니다.

성공 응답

예제 JSON 응답
json
{
"result": {
"data": {
"id": "1",
"title": "Hello tRPC",
"body": "..."
}
}
}
json
{
"result": {
"data": {
"id": "1",
"title": "Hello tRPC",
"body": "..."
}
}
}
ts
interface SuccessResponse {
result: {
data: TOutput; // output from procedure
}
}
ts
interface SuccessResponse {
result: {
data: TOutput; // output from procedure
}
}

오류 응답

예제 JSON 응답
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"
}
}
}
}
]

  • 가능한 경우, throw된 오류에서 HTTP 상태 코드를 전파합니다.
  • 응답의 상태가 서로 다른 경우, 207 Multi-Status를 반환합니다. (예: 한 호출이 오류가 발생하고 다른 호출이 성공한 경우)
  • 오류 및 커스터마이징 방법에 대한 자세한 내용은 Error Formatting을 참조하세요.

오류 코드 <-> HTTP 상태

ts
const HTTP_STATUS_CODES = {
PARSE_ERROR: 400,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
PAYMENT_REQUIRED: 402,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_SUPPORTED: 405,
TIMEOUT: 408,
CONFLICT: 409,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
UNSUPPORTED_MEDIA_TYPE: 415,
UNPROCESSABLE_CONTENT: 422,
PRECONDITION_REQUIRED: 428,
TOO_MANY_REQUESTS: 429,
CLIENT_CLOSED_REQUEST: 499,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
} as const;
ts
const HTTP_STATUS_CODES = {
PARSE_ERROR: 400,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
PAYMENT_REQUIRED: 402,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_SUPPORTED: 405,
TIMEOUT: 408,
CONFLICT: 409,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
UNSUPPORTED_MEDIA_TYPE: 415,
UNPROCESSABLE_CONTENT: 422,
PRECONDITION_REQUIRED: 428,
TOO_MANY_REQUESTS: 429,
CLIENT_CLOSED_REQUEST: 499,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
} as const;

오류 코드 <-> JSON-RPC 2.0 오류 코드

사용 가능한 코드 & JSON-RPC 코드
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 error
INTERNAL_SERVER_ERROR: -32603, // 500
NOT_IMPLEMENTED: -32603, // 501
BAD_GATEWAY: -32603, // 502
SERVICE_UNAVAILABLE: -32603, // 503
GATEWAY_TIMEOUT: -32603, // 504
 
// Implementation specific errors
UNAUTHORIZED: -32001, // 401
PAYMENT_REQUIRED: -32002, // 402
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
UNSUPPORTED_MEDIA_TYPE: -32015, // 415
UNPROCESSABLE_CONTENT: -32022, // 422
PRECONDITION_REQUIRED: -32028, // 428
TOO_MANY_REQUESTS: -32029, // 429
CLIENT_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 error
INTERNAL_SERVER_ERROR: -32603, // 500
NOT_IMPLEMENTED: -32603, // 501
BAD_GATEWAY: -32603, // 502
SERVICE_UNAVAILABLE: -32603, // 503
GATEWAY_TIMEOUT: -32603, // 504
 
// Implementation specific errors
UNAUTHORIZED: -32001, // 401
PAYMENT_REQUIRED: -32002, // 402
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
UNSUPPORTED_MEDIA_TYPE: -32015, // 415
UNPROCESSABLE_CONTENT: -32022, // 422
PRECONDITION_REQUIRED: -32028, // 428
TOO_MANY_REQUESTS: -32029, // 429
CLIENT_CLOSED_REQUEST: -32099, // 499
} as const;

기본 HTTP 메서드 오버라이드

쿼리/뮤테이션에 사용되는 HTTP 메서드를 오버라이드하려면 methodOverride 옵션을 사용할 수 있습니다:

server/httpHandler.ts
tsx
// Your server must separately allow the client to override the HTTP method
const handler = createHTTPHandler({
router: router,
allowMethodOverride: true,
});
server/httpHandler.ts
tsx
// Your server must separately allow the client to override the HTTP method
const handler = createHTTPHandler({
router: router,
allowMethodOverride: true,
});
client/trpc.ts
tsx
import { createTRPCClient, httpLink } from '@trpc/client';
import type { AppRouter } from './server';
 
// The client can then specify which HTTP method to use for all queries/mutations
const client = createTRPCClient<AppRouter>({
links: [
httpLink({
url: `http://localhost:3000`,
methodOverride: 'POST', // all queries and mutations will be sent to the tRPC Server as POST requests.
}),
],
});
client/trpc.ts
tsx
import { createTRPCClient, httpLink } from '@trpc/client';
import type { AppRouter } from './server';
 
// The client can then specify which HTTP method to use for all queries/mutations
const client = createTRPCClient<AppRouter>({
links: [
httpLink({
url: `http://localhost:3000`,
methodOverride: 'POST', // all queries and mutations will be sent to the tRPC Server as POST requests.
}),
],
});

심층 분석

다음의 TypeScript 정의에서 더 자세한 내용을 확인할 수 있습니다.