HTTP RPC Specification
On this page
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. |
GET | .subscription() | Subscriptions are supported via Server-sent Events using httpSubscriptionLink, or via WebSockets using wsLink. |
Accessing nested procedures
Nested procedures are separated by dots, so a request to byId below would end up being a request to /api/trpc/post.byId.
export const const appRouter: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>>
appRouter = const router: RouterBuilder
<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>(_: {
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}) => BuiltRouter<...>
router({
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>
post: const router: RouterBuilder
<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>(_: {
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}) => BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>
router({
byId: QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>
byId: const publicProcedure: ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>publicProcedure.ProcedureBuilder<object, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).ProcedureBuilder<object, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<void>(resolver: ProcedureResolver<object, object, object, string, UnsetMarker, void>): QueryProcedure<{
input: string;
output: void;
meta: object;
errorShape: DefaultErrorShape;
}>
query(async (opts: ProcedureResolverOptions<object, object, object, string>opts) => {
// [...]
}),
}),
});Batching
When batching, we combine all parallel procedure calls of the same HTTP method in one request using a data loader.
- The called procedures' names are combined by a comma (
,) in thepathname - Input parameters are sent as 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 const appRouter: BuiltRouter<{
ctx: Context;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
postById: QueryProcedure<{
input: string;
output: Post | null;
meta: object;
errorShape: DefaultErrorShape;
}>;
relatedPosts: QueryProcedure<{
input: string;
output: Post[];
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>
appRouter = const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
ctx: Context;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>
t.TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.router: RouterBuilder
<{
postById: QueryProcedure<{
input: string;
output: Post | null;
meta: object;
errorShape: DefaultErrorShape;
}>;
relatedPosts: QueryProcedure<{
input: string;
output: Post[];
meta: object;
errorShape: DefaultErrorShape;
}>;
}>(_: {
postById: QueryProcedure<{
input: string;
output: Post | null;
meta: object;
errorShape: DefaultErrorShape;
}>;
relatedPosts: QueryProcedure<{
input: string;
output: Post[];
meta: object;
errorShape: DefaultErrorShape;
}>;
}) => BuiltRouter<...>
router({
postById: QueryProcedure<{
input: string;
output: Post | null;
meta: object;
errorShape: DefaultErrorShape;
}>
postById: const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
ctx: Context;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>
t.TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure.ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<Post | null>(resolver: ProcedureResolver<Context, object, object, string, UnsetMarker, Post | null>): QueryProcedure<{
input: string;
output: Post | null;
meta: object;
errorShape: DefaultErrorShape;
}>
query(async (opts: ProcedureResolverOptions<Context, object, object, string>opts) => {
const const post: Post | nullpost = await opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.ctx: {
post: {
findUnique: (opts: {
where: {
id: string;
};
}) => Promise<Post | null>;
};
findRelatedPostsById: (id: string) => Promise<Post[]>;
}
ctx.post: {
findUnique: (opts: {
where: {
id: string;
};
}) => Promise<Post | null>;
}
post.findUnique: (opts: {
where: {
id: string;
};
}) => Promise<Post | null>
findUnique({
where: {
id: string;
}
where: { id: stringid: opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.input: stringinput },
});
return const post: Post | nullpost;
}),
relatedPosts: QueryProcedure<{
input: string;
output: Post[];
meta: object;
errorShape: DefaultErrorShape;
}>
relatedPosts: const t: TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, {
ctx: Context;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>
t.TRPCRootObject<Context, object, RuntimeConfigOptions<Context, object>, { ctx: Context; meta: object; errorShape: DefaultErrorShape; transformer: false; }>.procedure: ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>procedure.ProcedureBuilder<Context, object, object, UnsetMarker, UnsetMarker, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.input<StringConstructor>(schema: StringConstructor): ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>input(var String: StringConstructorString).ProcedureBuilder<Context, object, object, string, string, UnsetMarker, UnsetMarker, false, DefaultErrorShape>.query<Post[]>(resolver: ProcedureResolver<Context, object, object, string, UnsetMarker, Post[]>): QueryProcedure<{
input: string;
output: Post[];
meta: object;
errorShape: DefaultErrorShape;
}>
query(async (opts: ProcedureResolverOptions<Context, object, object, string>opts) => {
const const posts: Post[]posts = await opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.ctx: {
post: {
findUnique: (opts: {
where: {
id: string;
};
}) => Promise<Post | null>;
};
findRelatedPostsById: (id: string) => Promise<Post[]>;
}
ctx.findRelatedPostsById: (id: string) => Promise<Post[]>findRelatedPostsById(opts: ProcedureResolverOptions<Context, object, object, string>opts.ProcedureResolverOptions<Context, object, object, string>.input: stringinput);
return const posts: Post[]posts;
}),
});... And two queries defined like this in a React component:
MyComponent.tsx
export function function MyComponent(): React.JSX.ElementMyComponent() {
const const post1: anypost1 = const trpc: anytrpc.postById.useQuery('1');
const const relatedPosts: anyrelatedPosts = const trpc: anytrpc.relatedPosts.useQuery('1');
return (
<React.JSX.IntrinsicElements.pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>pre>
{var JSON: JSONJSON.JSON.stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string (+1 overload)stringify(
{
post1: anypost1: const post1: anypost1.data ?? null,
relatedPosts: anyrelatedPosts: const relatedPosts: anyrelatedPosts.data ?? null,
},
null,
4,
)}
</React.JSX.IntrinsicElements.pre: React.DetailedHTMLProps<React.HTMLAttributes<HTMLPreElement>, HTMLPreElement>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:
function encodeURIComponent(uriComponent: string | number | boolean): stringencodeURIComponent(
var JSON: JSONJSON.JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)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": "..."
}
}
}interface SuccessResponse {
SuccessResponse.result: {
data: TOutput;
}
result: {
data: anydata: type TOutput = anyTOutput; // 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 to customize them see Error Formatting.
Error Codes <-> HTTP Status
const const HTTP_STATUS_CODES: {
readonly PARSE_ERROR: 400;
readonly BAD_REQUEST: 400;
readonly UNAUTHORIZED: 401;
readonly PAYMENT_REQUIRED: 402;
readonly FORBIDDEN: 403;
readonly NOT_FOUND: 404;
readonly METHOD_NOT_SUPPORTED: 405;
readonly TIMEOUT: 408;
readonly CONFLICT: 409;
readonly PRECONDITION_FAILED: 412;
readonly PAYLOAD_TOO_LARGE: 413;
readonly UNSUPPORTED_MEDIA_TYPE: 415;
readonly UNPROCESSABLE_CONTENT: 422;
readonly PRECONDITION_REQUIRED: 428;
readonly TOO_MANY_REQUESTS: 429;
readonly CLIENT_CLOSED_REQUEST: 499;
readonly INTERNAL_SERVER_ERROR: 500;
readonly NOT_IMPLEMENTED: 501;
readonly BAD_GATEWAY: 502;
readonly SERVICE_UNAVAILABLE: 503;
readonly GATEWAY_TIMEOUT: 504;
}
HTTP_STATUS_CODES = {
type PARSE_ERROR: 400PARSE_ERROR: 400,
type BAD_REQUEST: 400BAD_REQUEST: 400,
type UNAUTHORIZED: 401UNAUTHORIZED: 401,
type PAYMENT_REQUIRED: 402PAYMENT_REQUIRED: 402,
type FORBIDDEN: 403FORBIDDEN: 403,
type NOT_FOUND: 404NOT_FOUND: 404,
type METHOD_NOT_SUPPORTED: 405METHOD_NOT_SUPPORTED: 405,
type TIMEOUT: 408TIMEOUT: 408,
type CONFLICT: 409CONFLICT: 409,
type PRECONDITION_FAILED: 412PRECONDITION_FAILED: 412,
type PAYLOAD_TOO_LARGE: 413PAYLOAD_TOO_LARGE: 413,
type UNSUPPORTED_MEDIA_TYPE: 415UNSUPPORTED_MEDIA_TYPE: 415,
type UNPROCESSABLE_CONTENT: 422UNPROCESSABLE_CONTENT: 422,
type PRECONDITION_REQUIRED: 428PRECONDITION_REQUIRED: 428,
type TOO_MANY_REQUESTS: 429TOO_MANY_REQUESTS: 429,
type CLIENT_CLOSED_REQUEST: 499CLIENT_CLOSED_REQUEST: 499,
type INTERNAL_SERVER_ERROR: 500INTERNAL_SERVER_ERROR: 500,
type NOT_IMPLEMENTED: 501NOT_IMPLEMENTED: 501,
type BAD_GATEWAY: 502BAD_GATEWAY: 502,
type SERVICE_UNAVAILABLE: 503SERVICE_UNAVAILABLE: 503,
type GATEWAY_TIMEOUT: 504GATEWAY_TIMEOUT: 504,
} as type const = {
readonly PARSE_ERROR: 400;
readonly BAD_REQUEST: 400;
readonly UNAUTHORIZED: 401;
readonly PAYMENT_REQUIRED: 402;
readonly FORBIDDEN: 403;
readonly NOT_FOUND: 404;
readonly METHOD_NOT_SUPPORTED: 405;
readonly TIMEOUT: 408;
readonly CONFLICT: 409;
readonly PRECONDITION_FAILED: 412;
readonly PAYLOAD_TOO_LARGE: 413;
readonly UNSUPPORTED_MEDIA_TYPE: 415;
readonly UNPROCESSABLE_CONTENT: 422;
readonly PRECONDITION_REQUIRED: 428;
readonly TOO_MANY_REQUESTS: 429;
readonly CLIENT_CLOSED_REQUEST: 499;
readonly INTERNAL_SERVER_ERROR: 500;
readonly NOT_IMPLEMENTED: 501;
readonly BAD_GATEWAY: 502;
readonly SERVICE_UNAVAILABLE: 503;
readonly GATEWAY_TIMEOUT: 504;
}
const;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 const TRPC_ERROR_CODES_BY_KEY: {
readonly PARSE_ERROR: -32700;
readonly BAD_REQUEST: -32600;
readonly INTERNAL_SERVER_ERROR: -32603;
readonly NOT_IMPLEMENTED: -32603;
readonly BAD_GATEWAY: -32603;
readonly SERVICE_UNAVAILABLE: -32603;
readonly GATEWAY_TIMEOUT: -32603;
readonly UNAUTHORIZED: -32001;
readonly PAYMENT_REQUIRED: -32002;
readonly FORBIDDEN: -32003;
readonly NOT_FOUND: -32004;
readonly METHOD_NOT_SUPPORTED: -32005;
readonly TIMEOUT: -32008;
readonly CONFLICT: -32009;
readonly PRECONDITION_FAILED: -32012;
readonly PAYLOAD_TOO_LARGE: -32013;
readonly UNSUPPORTED_MEDIA_TYPE: -32015;
readonly UNPROCESSABLE_CONTENT: -32022;
readonly PRECONDITION_REQUIRED: -32028;
readonly TOO_MANY_REQUESTS: -32029;
readonly CLIENT_CLOSED_REQUEST: -32099;
}
TRPC_ERROR_CODES_BY_KEY = {
/**
* Invalid JSON was received by the server.
* An error occurred on the server while parsing the JSON text.
*/
type PARSE_ERROR: -32700PARSE_ERROR: -32700,
/**
* The JSON sent is not a valid Request object.
*/
type BAD_REQUEST: -32600BAD_REQUEST: -32600, // 400
// Internal JSON-RPC error
type INTERNAL_SERVER_ERROR: -32603INTERNAL_SERVER_ERROR: -32603, // 500
type NOT_IMPLEMENTED: -32603NOT_IMPLEMENTED: -32603, // 501
type BAD_GATEWAY: -32603BAD_GATEWAY: -32603, // 502
type SERVICE_UNAVAILABLE: -32603SERVICE_UNAVAILABLE: -32603, // 503
type GATEWAY_TIMEOUT: -32603GATEWAY_TIMEOUT: -32603, // 504
// Implementation specific errors
type UNAUTHORIZED: -32001UNAUTHORIZED: -32001, // 401
type PAYMENT_REQUIRED: -32002PAYMENT_REQUIRED: -32002, // 402
type FORBIDDEN: -32003FORBIDDEN: -32003, // 403
type NOT_FOUND: -32004NOT_FOUND: -32004, // 404
type METHOD_NOT_SUPPORTED: -32005METHOD_NOT_SUPPORTED: -32005, // 405
type TIMEOUT: -32008TIMEOUT: -32008, // 408
type CONFLICT: -32009CONFLICT: -32009, // 409
type PRECONDITION_FAILED: -32012PRECONDITION_FAILED: -32012, // 412
type PAYLOAD_TOO_LARGE: -32013PAYLOAD_TOO_LARGE: -32013, // 413
type UNSUPPORTED_MEDIA_TYPE: -32015UNSUPPORTED_MEDIA_TYPE: -32015, // 415
type UNPROCESSABLE_CONTENT: -32022UNPROCESSABLE_CONTENT: -32022, // 422
type PRECONDITION_REQUIRED: -32028PRECONDITION_REQUIRED: -32028, // 428
type TOO_MANY_REQUESTS: -32029TOO_MANY_REQUESTS: -32029, // 429
type CLIENT_CLOSED_REQUEST: -32099CLIENT_CLOSED_REQUEST: -32099, // 499
} as type const = {
readonly PARSE_ERROR: -32700;
readonly BAD_REQUEST: -32600;
readonly INTERNAL_SERVER_ERROR: -32603;
readonly NOT_IMPLEMENTED: -32603;
readonly BAD_GATEWAY: -32603;
readonly SERVICE_UNAVAILABLE: -32603;
readonly GATEWAY_TIMEOUT: -32603;
readonly UNAUTHORIZED: -32001;
readonly PAYMENT_REQUIRED: -32002;
readonly FORBIDDEN: -32003;
readonly NOT_FOUND: -32004;
readonly METHOD_NOT_SUPPORTED: -32005;
readonly TIMEOUT: -32008;
readonly CONFLICT: -32009;
readonly PRECONDITION_FAILED: -32012;
readonly PAYLOAD_TOO_LARGE: -32013;
readonly UNSUPPORTED_MEDIA_TYPE: -32015;
readonly UNPROCESSABLE_CONTENT: -32022;
readonly PRECONDITION_REQUIRED: -32028;
readonly TOO_MANY_REQUESTS: -32029;
readonly CLIENT_CLOSED_REQUEST: -32099;
}
const;Overriding the default HTTP method
To override the HTTP method used for queries/mutations, you can use the methodOverride option:
server/httpHandler.ts
// Your server must separately allow the client to override the HTTP method
const const handler: http.RequestListenerhandler = createHTTPHandler<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: CreateHTTPHandlerOptions<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>): http.RequestListener
createHTTPHandler({
BaseHandlerOptions<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{}>>, http.IncomingMessage>.router: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>
router: const router: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>
router,
BaseHandlerOptions<TRouter extends AnyRouter, TRequest>.allowMethodOverride?: boolean | undefinedallowMethodOverride: true,
});client/trpc.ts
import { function createTRPCClient<TRouter extends AnyRouter>(opts: CreateTRPCClientOptions<TRouter>): TRPCClient<TRouter>createTRPCClient, function httpLink<TRouter extends AnyRouter = AnyRouter>(opts: HTTPLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpLink } from '@trpc/client';
import type { type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter } from './server';
// The client can then specify which HTTP method to use for all queries/mutations
const const client: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>
client = createTRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: CreateTRPCClientOptions<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>): TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<...>>>
createTRPCClient<type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>> & DecorateCreateRouterOptions<{}>
AppRouter>({
links: TRPCLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>[]
links: [
httpLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>(opts: HTTPLinkOptions<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>): TRPCLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{}>>>
httpLink({
url: string | URLurl: `http://localhost:3000`,
methodOverride?: "POST" | undefinedmethodOverride: 'POST', // all queries and mutations will be sent to the tRPC Server as POST requests.
}),
],
});Dig deeper
You can read more details by drilling into the TypeScript definitions in