メインコンテンツへスキップ
バージョン: 11.x

JSON以外のコンテンツタイプ

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

JSONとしてシリアライズ可能なデータに加えて、tRPCはプロシージャの入力としてFormData、File、その他のバイナリタイプを使用できます

クライアント側の設定

情報

tRPCは複数の非JSONシリアライズ可能な型をネイティブサポートしていますが、クライアント側では設定に応じてリンクの設定を若干調整する必要がある場合があります。

httpLinkは非JSONコンテンツタイプを標準でサポートしています。このリンクのみを使用している場合、既存の設定は即座に動作します

ts
import { httpLink } from '@trpc/client';
trpc.createClient({
links: [
httpLink({
url: 'http://localhost:2022',
}),
],
});
ts
import { httpLink } from '@trpc/client';
trpc.createClient({
links: [
httpLink({
url: 'http://localhost:2022',
}),
],
});

ただし、すべてのリンクがこれらの新しいコンテンツタイプをサポートしているわけではありません。httpBatchLinkhttpBatchStreamLinkを使用している場合は、splitLinkを追加し、コンテンツに応じて使用するリンクを判別する必要があります

ts
import {
httpBatchLink,
httpLink,
isNonJsonSerializable,
splitLink,
} from '@trpc/client';
trpc.createClient({
links: [
splitLink({
condition: (op) => isNonJsonSerializable(op.input),
true: httpLink({
url,
}),
false: httpBatchLink({
url,
}),
}),
],
});
ts
import {
httpBatchLink,
httpLink,
isNonJsonSerializable,
splitLink,
} from '@trpc/client';
trpc.createClient({
links: [
splitLink({
condition: (op) => isNonJsonSerializable(op.input),
true: httpLink({
url,
}),
false: httpBatchLink({
url,
}),
}),
],
});

tRPCサーバーでtransformerを使用している場合、TypeScriptではクライアントリンクでもtransformerを定義する必要があります。
以下の例をベースとして使用してください:

ts
import {
httpBatchLink,
httpLink,
isNonJsonSerializable,
splitLink,
} from '@trpc/client';
import superjson from 'superjson';
trpc.createClient({
links: [
splitLink({
condition: (op) => isNonJsonSerializable(op.input),
true: httpLink({
url,
transformer: {
// request - convert data before sending to the tRPC server
serialize: (data) => data,
// response - convert the tRPC response before using it in client
deserialize: superjson.deserialize, // or your other transformer
},
}),
false: httpBatchLink({
url,
transformers: superjson, // or your other transformer
}),
}),
],
});
ts
import {
httpBatchLink,
httpLink,
isNonJsonSerializable,
splitLink,
} from '@trpc/client';
import superjson from 'superjson';
trpc.createClient({
links: [
splitLink({
condition: (op) => isNonJsonSerializable(op.input),
true: httpLink({
url,
transformer: {
// request - convert data before sending to the tRPC server
serialize: (data) => data,
// response - convert the tRPC response before using it in client
deserialize: superjson.deserialize, // or your other transformer
},
}),
false: httpBatchLink({
url,
transformers: superjson, // or your other transformer
}),
}),
],
});

サーバー側の使用方法

情報

tRPCがリクエストを処理する際、リクエストのContent-Typeヘッダーに基づいてリクエストボディの解析を行います。
Failed to parse body as XXXのようなエラーが発生した場合は、サーバー(例: Express, Next.js)がtRPCが処理する前にリクエストボディを解析していないことを確認してください。

ts
// Example in express
// incorrect
const app = express();
app.use(express.json()); // this try to parse body before tRPC.
app.post('/express/hello', (req,res) => {/* ... */ }); // normal express route handler
app.use('/trpc', trpcExpress.createExpressMiddleware({ /* ... */}))// tRPC fails to parse body
// correct
const app = express();
app.use('/express', express.json()); // do it only in "/express/*" path
app.post('/express/hello', (req,res) => {/* ... */ });
app.use('/trpc', trpcExpress.createExpressMiddleware({ /* ... */}))// tRPC can parse body
ts
// Example in express
// incorrect
const app = express();
app.use(express.json()); // this try to parse body before tRPC.
app.post('/express/hello', (req,res) => {/* ... */ }); // normal express route handler
app.use('/trpc', trpcExpress.createExpressMiddleware({ /* ... */}))// tRPC fails to parse body
// correct
const app = express();
app.use('/express', express.json()); // do it only in "/express/*" path
app.post('/express/hello', (req,res) => {/* ... */ });
app.use('/trpc', trpcExpress.createExpressMiddleware({ /* ... */}))// tRPC can parse body

FormData入力

FormDataはネイティブでサポートされています。より高度な使用方法として、zod-form-dataのようなライブラリと組み合わせて、型安全な方法で入力を検証することもできます

ts
import { z } from 'zod';
 
export const t = initTRPC.create();
const publicProcedure = t.procedure;
 
export const appRouter = t.router({
hello: publicProcedure.input(z.instanceof(FormData)).mutation((opts) => {
const data = opts.input;
const data: FormData
return {
greeting: `Hello ${data.get('name')}`,
};
}),
});
ts
import { z } from 'zod';
 
export const t = initTRPC.create();
const publicProcedure = t.procedure;
 
export const appRouter = t.router({
hello: publicProcedure.input(z.instanceof(FormData)).mutation((opts) => {
const data = opts.input;
const data: FormData
return {
greeting: `Hello ${data.get('name')}`,
};
}),
});

より高度なコードサンプルについては、こちらのサンプルプロジェクトをご覧ください

Fileおよびその他のバイナリタイプ入力

tRPCは多くのオクテットコンテンツタイプをReadableStreamに変換し、プロシージャ内で利用できるようにします。現在サポートされているのはBlobUint8ArrayFileです

ts
import { octetInputParser } from '@trpc/server/http';
 
export const t = initTRPC.create();
const publicProcedure = t.procedure;
 
export const appRouter = t.router({
upload: publicProcedure.input(octetInputParser).mutation((opts) => {
const data = opts.input;
const data: ReadableStream<any>
return {
valid: true,
};
}),
});
ts
import { octetInputParser } from '@trpc/server/http';
 
export const t = initTRPC.create();
const publicProcedure = t.procedure;
 
export const appRouter = t.router({
upload: publicProcedure.input(octetInputParser).mutation((opts) => {
const data = opts.input;
const data: ReadableStream<any>
return {
valid: true,
};
}),
});