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

スタンドアロンアダプター

非公式ベータ版翻訳

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

tRPCのスタンドアロンアダプターは、新規プロジェクトを最も簡単に動作させる方法です。ローカル開発やサーバーベースの本番環境に最適です。本質的には標準のNode.js HTTP Serverをラップしたもので、tRPC関連の標準オプションを備えています。

既存のExpressFastifyNext.jsなどのAPIデプロイメントにtRPCを統合したい場合は、それぞれのアダプターを参照してください。同様にサーバーレスやエッジコンピュート環境でのホスティングを希望する場合、AWS LambdaFetchなどニーズに合うアダプターも用意されています。

デプロイ先のアダプターがローカルマシンで実行しづらい場合、アプリケーションに2つのエントリーポイントを設けるのも一般的です。ローカル開発にはスタンドアロンアダプターを、デプロイ時には別のアダプターを使用する方法が考えられます。

サンプルアプリケーション

DescriptionLinks
Standalone tRPC Server
Standalone tRPC Server with CORS handling

スタンドアロンtRPCサーバーのセットアップ

1. アプリケーションルーターの実装

tRPCルーターを実装します。例:

appRouter.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
export const t = initTRPC.create();
export const appRouter = t.router({
getUser: t.procedure.input(z.string()).query((opts) => {
return { id: opts.input, name: 'Bilbo' };
}),
createUser: t.procedure
.input(z.object({ name: z.string().min(5) }))
.mutation(async (opts) => {
// use your ORM of choice
return await UserModel.create({
data: opts.input,
});
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;
appRouter.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
export const t = initTRPC.create();
export const appRouter = t.router({
getUser: t.procedure.input(z.string()).query((opts) => {
return { id: opts.input, name: 'Bilbo' };
}),
createUser: t.procedure
.input(z.object({ name: z.string().min(5) }))
.mutation(async (opts) => {
// use your ORM of choice
return await UserModel.create({
data: opts.input,
});
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;

詳細についてはクイックスタートガイドを参照してください

2. スタンドアロンアダプターの使用

スタンドアロンアダプターはシンプルなNode.js HTTPサーバーを実行します。

server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter.ts';
createHTTPServer({
router: appRouter,
createContext() {
console.log('context 3');
return {};
},
// basePath: '/trpc/', // optional, defaults to '/'
}).listen(2022);
server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter.ts';
createHTTPServer({
router: appRouter,
createContext() {
console.log('context 3');
return {};
},
// basePath: '/trpc/', // optional, defaults to '/'
}).listen(2022);

CORS & OPTIONSの処理

デフォルトでは、スタンドアロンサーバーはHTTP OPTIONSリクエストに応答せず、CORSヘッダーも設定しません。

ローカル開発時のように、この処理を代行してくれる環境でホスティングしていない場合は、自身で対応する必要があります。

1. corsのインストール

一般的なcorsパッケージを使用してサポートを追加できます

bash
yarn add cors
yarn add -D @types/cors
bash
yarn add cors
yarn add -D @types/cors

設定方法の詳細については公式ドキュメントを参照してください

2. スタンドアロンサーバーの設定

この例では開発に便利なようCORSを全開放していますが、本番環境ではより厳格に設定すべきです。

server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import cors from 'cors';
createHTTPServer({
middleware: cors(),
router: appRouter,
createContext() {
console.log('context 3');
return {};
},
}).listen(3333);
server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import cors from 'cors';
createHTTPServer({
middleware: cors(),
router: appRouter,
createContext() {
console.log('context 3');
return {};
},
}).listen(3333);

middlewareオプションはconnect/node.jsミドルウェアに類似した関数を受け付けるため、必要に応じてcors処理以外にも使用できます。ただしこれはあくまでシンプルな回避策として設計されているため、単体では複数のミドルウェアを組み合わせられません。これを実現するには次の方法があります:

  1. Expressアダプターなど、より包括的なミドルウェアサポートを備えた代替アダプターを使用する

  2. connectのようなミドルウェア合成ソリューションを利用する

  3. カスタムHTTPサーバーでスタンドアロンのcreateHTTPHandlerを拡張する(下記参照)

カスタムHTTPサーバーへのハンドラー追加

createHTTPServerはNode組み込みのhttp.Server (https://nodejs.org/api/http.html#class-httpserver) インスタンスを返すため、すべてのプロパティとAPIにアクセスできます。ただしcreateHTTPServerが要件を満たさない場合、スタンドアロンアダプターのcreateHTTPHandler関数を使用して独自のHTTPサーバーを構築することも可能です。例:

server.ts
ts
import { createServer } from 'http';
import { initTRPC } from '@trpc/server';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
const handler = createHTTPHandler({
router: appRouter,
createContext() {
return {};
},
});
createServer((req, res) => {
/**
* Handle the request however you like,
* just call the tRPC handler when you're ready
*/
handler(req, res);
}).listen(3001);
server.ts
ts
import { createServer } from 'http';
import { initTRPC } from '@trpc/server';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
const handler = createHTTPHandler({
router: appRouter,
createContext() {
return {};
},
});
createServer((req, res) => {
/**
* Handle the request however you like,
* just call the tRPC handler when you're ready
*/
handler(req, res);
}).listen(3001);

リクエスト処理用カスタムベースパス

スタンドアロンアダプターはbasePathオプションもサポートしており、リクエストパスの先頭からベースパスを切り取ります。

server.ts
ts
import { createServer } from 'http';
import { initTRPC } from '@trpc/server';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
const handler = createHTTPHandler({
router: appRouter,
basePath: '/trpc/',
});
createServer((req, res) => {
if (req.url?.startsWith('/trpc/')) {
return handler(req, res);
}
// [... insert your custom logic here ...]
res.statusCode = 404;
res.end('Not Found');
}).listen(3001);
server.ts
ts
import { createServer } from 'http';
import { initTRPC } from '@trpc/server';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
const handler = createHTTPHandler({
router: appRouter,
basePath: '/trpc/',
});
createServer((req, res) => {
if (req.url?.startsWith('/trpc/')) {
return handler(req, res);
}
// [... insert your custom logic here ...]
res.statusCode = 404;
res.end('Not Found');
}).listen(3001);

HTTP/2対応

スタンドアロンアダプターはHTTP/2もサポートしています。

server.ts
ts
import http2 from 'http2';
import { createHTTP2Handler } from '@trpc/server/adapters/standalone';
import { appRouter } from './_app.ts';
import { createContext } from './context.ts';
const handler = createHTTP2Handler({
router: appRouter,
createContext,
// basePath: '/trpc/', // optional, defaults to '/'
});
const server = http2.createSecureServer(
{
key: '...',
cert: '...',
},
(req, res) => {
/**
* Handle the request however you like,
* just call the tRPC handler when you're ready
*/
handler(req, res);
},
);
server.listen(3001);
server.ts
ts
import http2 from 'http2';
import { createHTTP2Handler } from '@trpc/server/adapters/standalone';
import { appRouter } from './_app.ts';
import { createContext } from './context.ts';
const handler = createHTTP2Handler({
router: appRouter,
createContext,
// basePath: '/trpc/', // optional, defaults to '/'
});
const server = http2.createSecureServer(
{
key: '...',
cert: '...',
},
(req, res) => {
/**
* Handle the request however you like,
* just call the tRPC handler when you're ready
*/
handler(req, res);
},
);
server.listen(3001);
context.ts
ts
import { CreateHTTP2ContextOptions } from '@trpc/server/adapters/standalone';
 
export async function createContext(opts: CreateHTTP2ContextOptions) {
opts.req;
(property) req: http2.Http2ServerRequest
opts.res;
(property) res: http2.Http2ServerResponse
 
opts.info;
(property) info: TRPCRequestInfo
return {};
}
 
export type Context = Awaited<ReturnType<typeof createContext>>;
context.ts
ts
import { CreateHTTP2ContextOptions } from '@trpc/server/adapters/standalone';
 
export async function createContext(opts: CreateHTTP2ContextOptions) {
opts.req;
(property) req: http2.Http2ServerRequest
opts.res;
(property) res: http2.Http2ServerResponse
 
opts.info;
(property) info: TRPCRequestInfo
return {};
}
 
export type Context = Awaited<ReturnType<typeof createContext>>;