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

스탠드얼론 어댑터

tRPC의 스탠드얼론 어댑터는 새 프로젝트를 실행하는 가장 간단한 방법입니다. 로컬 개발 및 서버 기반 프로덕션 환경에 이상적입니다. 본질적으로 tRPC 관련 표준 옵션을 갖춘 표준 Node.js HTTP 서버의 래퍼입니다.

tRPC를 통합하려는 Express, Fastify, 또는 Next.js와 같은 기존 API 배포 환경이 있다면 해당 어댑터를 확인해 보시기 바랍니다. 또한 서버리스 또는 엣지 컴퓨팅에서 호스팅하는 것을 선호한다면 AWS LambdaFetch와 같은 어댑터가 필요에 부합할 수 있습니다.

배포된 어댑터를 로컬 머신에서 실행하기 어려운 경우가 흔하며, 이 경우 애플리케이션에 두 개의 진입점을 두는 것이 일반적입니다. 로컬 개발에는 스탠드얼론 어댑터를 사용하고, 배포 시에는 다른 어댑터를 사용할 수 있습니다.

예제 앱

설명링크
스탠드얼론 tRPC 서버
CORS 처리가 포함된 스탠드얼론 tRPC 서버
AI 에이전트

AI 코딩 에이전트를 사용하는 경우, 더 나은 코드 생성을 위해 tRPC 스킬을 설치하세요:

bash
npx @tanstack/intent@latest install
bash
npx @tanstack/intent@latest install

스탠드얼론 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 { id: '1', ...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 { id: '1', ...opts.input };
}),
});
 
// export type definition of API
export type AppRouter = typeof appRouter;

자세한 내용은 빠른 시작 가이드를 참고하세요.

2. 스탠드얼론 어댑터 사용

스탠드얼론 어댑터는 간단한 Node.js HTTP 서버를 실행합니다.

server.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
createHTTPServer({
router: appRouter,
createContext() {
return {};
},
// basePath: '/trpc/', // optional, defaults to '/'
}).listen(2022);
server.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
createHTTPServer({
router: appRouter,
createContext() {
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 { createHTTPServer } from '@trpc/server/adapters/standalone';
import cors from 'cors';
import { appRouter } from './appRouter';
 
createHTTPServer({
middleware: cors(),
router: appRouter,
createContext() {
return {};
},
}).listen(3333);
server.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import cors from 'cors';
import { appRouter } from './appRouter';
 
createHTTPServer({
middleware: cors(),
router: appRouter,
createContext() {
return {};
},
}).listen(3333);

middleware 옵션은 connect/node.js 미들웨어와 유사한 모든 함수를 허용하므로, 원하는 경우 cors 처리 외에도 사용할 수 있습니다. 그러나 이는 단순한 탈출구를 의도한 것이므로, 단독으로 여러 미들웨어를 조합할 수 없습니다. 이를 수행하려면 다음을 할 수 있습니다:

  1. Express 어댑터와 같이 더 포괄적인 미들웨어 지원을 제공하는 대체 어댑터 사용
  2. connect와 같은 미들웨어 조합 솔루션 사용
  3. 스탠드얼론 createHTTPHandler를 커스텀 HTTP 서버로 확장 (아래 참조)

커스텀 HTTP 서버에 핸들러 추가

createHTTPServer는 Node의 내장 http.Server 인스턴스를 반환하므로, 해당 인스턴스의 모든 속성과 API에 접근할 수 있습니다. 그러나 createHTTPServer만으로는 사용 사례에 충분하지 않은 경우, 스탠드얼론 어댑터의 createHTTPHandler 함수를 사용하여 자체 HTTP 서버를 만들 수도 있습니다. 예를 들어:

server.ts
ts
import { createServer } from 'http';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
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 { createHTTPHandler } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
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 옵션도 지원하며, 이 옵션은 요청 경로의 앞부분에서 basePath를 잘라냅니다.

server.ts
ts
import { createServer } from 'http';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
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 { createHTTPHandler } from '@trpc/server/adapters/standalone';
import { appRouter } from './appRouter';
 
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);

HTTP2

스탠드얼론 어댑터는 HTTP/2도 지원합니다.

server.ts
ts
import http2 from 'http2';
import { createHTTP2Handler } from '@trpc/server/adapters/standalone';
import { appRouter } from './_app';
import { createContext } from './context';
 
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';
import { createContext } from './context';
 
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>>;