미들웨어
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
t.procedure.use() 메서드를 사용해 프로시저에 미들웨어를 추가할 수 있습니다. 미들웨어는 프로시저 호출을 래핑하며 반드시 반환 값을 전달해야 합니다.
인증
아래 예제에서 adminProcedure를 호출할 때는 실행 전 사용자가 "admin"인지 확인합니다.
tsimport {TRPCError ,initTRPC } from '@trpc/server';interfaceContext {user ?: {id : string;isAdmin : boolean;// [..]};}constt =initTRPC .context <Context >().create ();export constpublicProcedure =t .procedure ;export constrouter =t .router ;export constadminProcedure =publicProcedure .use (async (opts ) => {const {ctx } =opts ;if (!ctx .user ?.isAdmin ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {user :ctx .user ,},});});
tsimport {TRPCError ,initTRPC } from '@trpc/server';interfaceContext {user ?: {id : string;isAdmin : boolean;// [..]};}constt =initTRPC .context <Context >().create ();export constpublicProcedure =t .procedure ;export constrouter =t .router ;export constadminProcedure =publicProcedure .use (async (opts ) => {const {ctx } =opts ;if (!ctx .user ?.isAdmin ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {user :ctx .user ,},});});
tsimport {adminProcedure ,publicProcedure ,router } from './trpc';constadminRouter =router ({secretPlace :adminProcedure .query (() => 'a key'),});export constappRouter =router ({foo :publicProcedure .query (() => 'bar'),admin :adminRouter ,});
tsimport {adminProcedure ,publicProcedure ,router } from './trpc';constadminRouter =router ({secretPlace :adminProcedure .query (() => 'a key'),});export constappRouter =router ({foo :publicProcedure .query (() => 'bar'),admin :adminRouter ,});
위 예제에서 발생하는 TRPCError에 대해 자세히 알아보려면 오류 처리 문서를 참조하세요.
로깅
아래 예제에서는 쿼리 실행 시간이 자동으로 기록됩니다.
tsexport constloggedProcedure =publicProcedure .use (async (opts ) => {conststart =Date .now ();constresult = awaitopts .next ();constdurationMs =Date .now () -start ;constmeta = {path :opts .path ,type :opts .type ,durationMs };result .ok ?console .log ('OK request timing:',meta ):console .error ('Non-OK request timing',meta );returnresult ;});
tsexport constloggedProcedure =publicProcedure .use (async (opts ) => {conststart =Date .now ();constresult = awaitopts .next ();constdurationMs =Date .now () -start ;constmeta = {path :opts .path ,type :opts .type ,durationMs };result .ok ?console .log ('OK request timing:',meta ):console .error ('Non-OK request timing',meta );returnresult ;});
tsimport { loggedProcedure, router } from './trpc';export const appRouter= router({ foo: loggedProcedure.query(() => 'bar'),abc:loggedProcedure .query (() => 'def'), });
tsimport { loggedProcedure, router } from './trpc';export const appRouter= router({ foo: loggedProcedure.query(() => 'bar'),abc: loggedProcedure. query (() => 'def'), });
컨텍스트 확장
"컨텍스트 확장"을 통해 미들웨어는 타입 안전한 방식으로 기본 프로시저 컨텍스트의 키를 동적으로 추가하거나 재정의할 수 있습니다.
다음은 컨텍스트 속성을 변경하는 미들웨어 예시로, 변경 사항은 다른 미들웨어나 프로시저 같은 체인된 모든 소비자가 사용할 수 있습니다:
tstypeContext = {// user is nullableuser ?: {id : string;};};constprotectedProcedure =publicProcedure .use (async functionisAuthed (opts ) {const {ctx } =opts ;// `ctx.user` is nullableif (!ctx .user ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {// ✅ user value is known to be non-null nowuser :ctx .user ,},});});protectedProcedure .query ((opts ) => {const {ctx } =opts ;returnctx .user ;});
tstypeContext = {// user is nullableuser ?: {id : string;};};constprotectedProcedure =publicProcedure .use (async functionisAuthed (opts ) {const {ctx } =opts ;// `ctx.user` is nullableif (!ctx .user ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {// ✅ user value is known to be non-null nowuser :ctx .user ,},});});protectedProcedure .query ((opts ) => {const {ctx } =opts ;returnctx .user ;});
.concat()을 이용한 재사용 가능한 미들웨어와 플러그인 생성
t.middleware로 미들웨어 생성 시Context타입이 tRPC 인스턴스의Context타입에 종속된다는 제한이 있습니다.experimental_standaloneMiddleware()로 미들웨어 생성 시 모듈에 연결된 입력 파서 등을 정의할 수 없다는 제한이 있습니다.
tRPC는 .concat() API를 제공하며, 이를 통해 플러그인의 컨텍스트 및 메타데이터와 일치하는 모든 tRPC 인스턴스에서 사용할 수 있는 부분 프로시저를 독립적으로 정의할 수 있습니다.
이 헬퍼는 주로 tRPC로 플러그인과 라이브러리를 생성할 때 사용됩니다.
ts// ------------------------------------------------// 🧩🧩🧩 a library creating a reusable plugin 🧩🧩🧩// @filename: myPlugin.tsimport {initTRPC ,TRPCError } from '@trpc/server';export functioncreateMyPlugin () {// When creating a plugin for tRPC, you use the same API as creating any other tRPC-app// this is the plugin's root `t`-objectconstt =initTRPC .context <{// the procedure using the plugin will need to extend this context}>().meta <{// the base `initTRPC`-object of the application using this needs to extend this meta}>().create ();return {// you can also add `.input()` if you want your plugin to do input validationpluginProc :t .procedure .use ((opts ) => {returnopts .next ({ctx : {fromPlugin : 'hello from myPlugin' asconst ,},});}),};}// ------------------------------------// 🚀🚀🚀 the app using the plugin 🚀🚀🚀// @filename: app.tsimport {createMyPlugin } from './myPlugin';import {initTRPC ,TRPCError } from '@trpc/server';// the app's root `t`-objectconstt =initTRPC .context <{// ...}>().create ();export constpublicProcedure =t .procedure ;export constrouter =t .router ;// initialize the plugin (a real-world example would likely take options here)constplugin =createMyPlugin ();// create a base procedure using the pluginconstprocedureWithPlugin =publicProcedure .concat (plugin .pluginProc ,).use (opts => {const {ctx } =opts ;returnopts .next ()})export constappRouter =router ({hello :procedureWithPlugin .query (opts => {returnopts .ctx .fromPlugin ;})})
ts// ------------------------------------------------// 🧩🧩🧩 a library creating a reusable plugin 🧩🧩🧩// @filename: myPlugin.tsimport {initTRPC ,TRPCError } from '@trpc/server';export functioncreateMyPlugin () {// When creating a plugin for tRPC, you use the same API as creating any other tRPC-app// this is the plugin's root `t`-objectconstt =initTRPC .context <{// the procedure using the plugin will need to extend this context}>().meta <{// the base `initTRPC`-object of the application using this needs to extend this meta}>().create ();return {// you can also add `.input()` if you want your plugin to do input validationpluginProc :t .procedure .use ((opts ) => {returnopts .next ({ctx : {fromPlugin : 'hello from myPlugin' asconst ,},});}),};}// ------------------------------------// 🚀🚀🚀 the app using the plugin 🚀🚀🚀// @filename: app.tsimport {createMyPlugin } from './myPlugin';import {initTRPC ,TRPCError } from '@trpc/server';// the app's root `t`-objectconstt =initTRPC .context <{// ...}>().create ();export constpublicProcedure =t .procedure ;export constrouter =t .router ;// initialize the plugin (a real-world example would likely take options here)constplugin =createMyPlugin ();// create a base procedure using the pluginconstprocedureWithPlugin =publicProcedure .concat (plugin .pluginProc ,).use (opts => {const {ctx } =opts ;returnopts .next ()})export constappRouter =router ({hello :procedureWithPlugin .query (opts => {returnopts .ctx .fromPlugin ;})})
미들웨어 확장
이 API는 새로운 기능이므로 unstable_ 접두사를 붙였지만 안전하게 사용하셔도 됩니다! 자세히 알아보기.
.pipe()라는 강력한 기능을 통해 타입 안전한 방식으로 미들웨어를 확장할 수 있습니다.
다음은 기본 미들웨어(foo)를 확장하는 미들웨어 예시입니다. 앞서 살펴본 컨텍스트 확장 예시와 마찬가지로, 미들웨어를 파이핑하면 컨텍스트 속성이 변경되며 프로시저는 새로운 컨텍스트 값을 수신합니다.
tsconstfooMiddleware =t .middleware ((opts ) => {returnopts .next ({ctx : {foo : 'foo' asconst ,},});});constbarMiddleware =fooMiddleware .unstable_pipe ((opts ) => {const {ctx } =opts ;ctx .foo ;returnopts .next ({ctx : {bar : 'bar' asconst ,},});});constbarProcedure =publicProcedure .use (barMiddleware );barProcedure .query ((opts ) => {const {ctx } =opts ;returnctx .bar ;});
tsconstfooMiddleware =t .middleware ((opts ) => {returnopts .next ({ctx : {foo : 'foo' asconst ,},});});constbarMiddleware =fooMiddleware .unstable_pipe ((opts ) => {const {ctx } =opts ;ctx .foo ;returnopts .next ({ctx : {bar : 'bar' asconst ,},});});constbarProcedure =publicProcedure .use (barMiddleware );barProcedure .query ((opts ) => {const {ctx } =opts ;returnctx .bar ;});
미들웨어 파이핑 순서가 중요하며 컨텍스트가 반드시 중첩되어야 합니다. 아래는 허용되지 않는 파이프 예시입니다. 여기서 fooMiddleware는 ctx.a를 재정의하는 반면, barMiddleware는 initTRPC 초기화 시 설정된 루트 컨텍스트를 기대합니다. 따라서 fooMiddleware를 barMiddleware와 파이핑하면 작동하지 않으며, barMiddleware를 fooMiddleware와 파이핑하면 정상 작동합니다.
tsimport {initTRPC } from '@trpc/server';constt =initTRPC .context <{a : {b : 'a';};}>().create ();constfooMiddleware =t .middleware ((opts ) => {const {ctx } =opts ;ctx .a ; // 👈 fooMiddleware expects `ctx.a` to be an objectreturnopts .next ({ctx : {a : 'a' asconst , // 👈 `ctx.a` is no longer an object},});});constbarMiddleware =t .middleware ((opts ) => {const {ctx } =opts ;ctx .a ; // 👈 barMiddleware expects `ctx.a` to be an objectreturnopts .next ({ctx : {foo : 'foo' asconst ,},});});// ❌ `ctx.a` does not overlap from `fooMiddleware` to `barMiddleware`Argument of type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to parameter of type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { a: "a"; }, { foo: "foo"; }, unknown> | MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to type 'MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { a: { b: "a"; }; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { a: "a"; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.a' are incompatible between these types. Type '{ b: "a"; }' is not assignable to type '"a"'.2345Argument of type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to parameter of type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { a: "a"; }, { foo: "foo"; }, unknown> | MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to type 'MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { a: { b: "a"; }; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { a: "a"; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.a' are incompatible between these types. Type '{ b: "a"; }' is not assignable to type '"a"'.fooMiddleware .unstable_pipe (); barMiddleware // ✅ `ctx.a` overlaps from `barMiddleware` and `fooMiddleware`barMiddleware .unstable_pipe (fooMiddleware );
tsimport {initTRPC } from '@trpc/server';constt =initTRPC .context <{a : {b : 'a';};}>().create ();constfooMiddleware =t .middleware ((opts ) => {const {ctx } =opts ;ctx .a ; // 👈 fooMiddleware expects `ctx.a` to be an objectreturnopts .next ({ctx : {a : 'a' asconst , // 👈 `ctx.a` is no longer an object},});});constbarMiddleware =t .middleware ((opts ) => {const {ctx } =opts ;ctx .a ; // 👈 barMiddleware expects `ctx.a` to be an objectreturnopts .next ({ctx : {foo : 'foo' asconst ,},});});// ❌ `ctx.a` does not overlap from `fooMiddleware` to `barMiddleware`Argument of type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to parameter of type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { a: "a"; }, { foo: "foo"; }, unknown> | MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to type 'MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { a: { b: "a"; }; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { a: "a"; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.a' are incompatible between these types. Type '{ b: "a"; }' is not assignable to type '"a"'.2345Argument of type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to parameter of type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { a: "a"; }, { foo: "foo"; }, unknown> | MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Type 'MiddlewareBuilder<{ a: { b: "a"; }; }, object, { foo: "foo"; }, unknown>' is not assignable to type 'MiddlewareBuilder<{ a: "a"; }, object, { foo: "foo"; }, unknown>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, $ContextOverridesOut, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, $ContextOverridesOut, unknown>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: "a"; foo: "foo"; }, object, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown> | MiddlewareBuilder<{ a: { b: "a"; }; foo: "foo"; }, object, any, unknown>'. Type 'MiddlewareFunction<{ a: "a"; }, object, { foo: "foo"; }, any, unknown>' is not assignable to type 'MiddlewareFunction<{ a: { b: "a"; }; }, object, { foo: "foo"; }, any, unknown>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { a: { b: "a"; }; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { a: "a"; foo: "foo"; }; type: "query" | "mutation" | "subscription"; path: string; input: unknown; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.a' are incompatible between these types. Type '{ b: "a"; }' is not assignable to type '"a"'.fooMiddleware .unstable_pipe (); barMiddleware // ✅ `ctx.a` overlaps from `barMiddleware` and `fooMiddleware`barMiddleware .unstable_pipe (fooMiddleware );
실험적 기능: 독립형 미들웨어
이 기능은 .concat()으로 대체되었습니다.
tRPC는 experimental_standaloneMiddleware라는 실험적 API를 제공하며, 이를 통해 모든 tRPC 인스턴스에서 사용 가능한 미들웨어를 독립적으로 정의할 수 있습니다. t.middleware로 미들웨어를 생성할 때는
Context 타입이 tRPC 인스턴스의 Context 타입에 종속된다는 제한이 있습니다. 즉, 서로 다른 Context 타입을 가진 여러 tRPC 인스턴스에서 동일한 미들웨어를 사용할 수 없습니다.
experimental_standaloneMiddleware를 사용하면 Context, Input, Meta 타입 같은 요구 사항을 명시적으로 정의하는 미들웨어를 생성할 수 있습니다:
tsimport {experimental_standaloneMiddleware ,initTRPC ,TRPCError ,} from '@trpc/server';import * asz from 'zod';constprojectAccessMiddleware =experimental_standaloneMiddleware <{ctx : {allowedProjects : string[] }; // defaults to 'object' if not definedinput : {projectId : string }; // defaults to 'unknown' if not defined// 'meta', not defined here, defaults to 'object | undefined'}>().create ((opts ) => {if (!opts .ctx .allowedProjects .includes (opts .input .projectId )) {throw newTRPCError ({code : 'FORBIDDEN',message : 'Not allowed',});}returnopts .next ();});constt1 =initTRPC .context <{allowedProjects : string[];}>().create ();// ✅ `ctx.allowedProjects` satisfies "string[]" and `input.projectId` satisfies "string"constaccessControlledProcedure =t1 .procedure .input (z .object ({projectId :z .string () })).use (projectAccessMiddleware );// ❌ `ctx.allowedProjects` satisfies "string[]" but `input.projectId` does not satisfy "string"constaccessControlledProcedure2 =t1 .procedure .input (z .object ({projectId :z .number () })).Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }> | MiddlewareFunction<{ allowedProjects: string[]; }, object, object, object, { projectId: number; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: number; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'input.projectId' are incompatible between these types. Type 'string' is not assignable to type 'number'.2345Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }> | MiddlewareFunction<{ allowedProjects: string[]; }, object, object, object, { projectId: number; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: number; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'input.projectId' are incompatible between these types. Type 'string' is not assignable to type 'number'.use (); projectAccessMiddleware // ❌ `ctx.allowedProjects` does not satisfy "string[]" even though `input.projectId` satisfies "string"constt2 =initTRPC .context <{allowedProjects : number[];}>().create ();constaccessControlledProcedure3 =t2 .procedure .input (z .object ({projectId :z .string () })).Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }> | MiddlewareFunction<{ allowedProjects: number[]; }, object, object, object, { projectId: string; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: number[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: number[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.allowedProjects' are incompatible between these types. Type 'string[]' is not assignable to type 'number[]'. Type 'string' is not assignable to type 'number'.2345Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }> | MiddlewareFunction<{ allowedProjects: number[]; }, object, object, object, { projectId: string; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: number[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: number[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.allowedProjects' are incompatible between these types. Type 'string[]' is not assignable to type 'number[]'. Type 'string' is not assignable to type 'number'.use (); projectAccessMiddleware
tsimport {experimental_standaloneMiddleware ,initTRPC ,TRPCError ,} from '@trpc/server';import * asz from 'zod';constprojectAccessMiddleware =experimental_standaloneMiddleware <{ctx : {allowedProjects : string[] }; // defaults to 'object' if not definedinput : {projectId : string }; // defaults to 'unknown' if not defined// 'meta', not defined here, defaults to 'object | undefined'}>().create ((opts ) => {if (!opts .ctx .allowedProjects .includes (opts .input .projectId )) {throw newTRPCError ({code : 'FORBIDDEN',message : 'Not allowed',});}returnopts .next ();});constt1 =initTRPC .context <{allowedProjects : string[];}>().create ();// ✅ `ctx.allowedProjects` satisfies "string[]" and `input.projectId` satisfies "string"constaccessControlledProcedure =t1 .procedure .input (z .object ({projectId :z .string () })).use (projectAccessMiddleware );// ❌ `ctx.allowedProjects` satisfies "string[]" but `input.projectId` does not satisfy "string"constaccessControlledProcedure2 =t1 .procedure .input (z .object ({projectId :z .number () })).Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }> | MiddlewareFunction<{ allowedProjects: string[]; }, object, object, object, { projectId: number; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: number; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'input.projectId' are incompatible between these types. Type 'string' is not assignable to type 'number'.2345Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }> | MiddlewareFunction<{ allowedProjects: string[]; }, object, object, object, { projectId: number; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: number; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: number; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: number; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'input.projectId' are incompatible between these types. Type 'string' is not assignable to type 'number'.use (); projectAccessMiddleware // ❌ `ctx.allowedProjects` does not satisfy "string[]" even though `input.projectId` satisfies "string"constt2 =initTRPC .context <{allowedProjects : number[];}>().create ();constaccessControlledProcedure3 =t2 .procedure .input (z .object ({projectId :z .string () })).Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }> | MiddlewareFunction<{ allowedProjects: number[]; }, object, object, object, { projectId: string; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: number[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: number[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.allowedProjects' are incompatible between these types. Type 'string[]' is not assignable to type 'number[]'. Type 'string' is not assignable to type 'number'.2345Argument of type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to parameter of type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }> | MiddlewareFunction<{ allowedProjects: number[]; }, object, object, object, { projectId: string; }>'. Type 'MiddlewareBuilder<{ allowedProjects: string[]; }, object, object, { projectId: string; }>' is not assignable to type 'MiddlewareBuilder<{ allowedProjects: number[]; }, object, object, { projectId: string; }>'. Types of property 'unstable_pipe' are incompatible. Type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: string[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>' is not assignable to type '<$ContextOverridesOut>(fn: MiddlewareFunction<{ allowedProjects: number[]; }, object, object, $ContextOverridesOut, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, $ContextOverridesOut, { ...; }>) => MiddlewareBuilder<...>'. Types of parameters 'fn' and 'fn' are incompatible. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: number[]; }, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }> | MiddlewareBuilder<{ allowedProjects: string[]; }, object, any, { projectId: string; }>'. Type 'MiddlewareFunction<{ allowedProjects: number[]; }, object, object, any, { projectId: string; }>' is not assignable to type 'MiddlewareFunction<{ allowedProjects: string[]; }, object, object, any, { projectId: string; }>'. Types of parameters 'opts' and 'opts' are incompatible. Type '{ ctx: { allowedProjects: string[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }' is not assignable to type '{ ctx: { allowedProjects: number[]; }; type: "query" | "mutation" | "subscription"; path: string; input: { projectId: string; }; getRawInput: GetRawInputFn; meta: object | undefined; signal: AbortSignal | undefined; next: { ...; }; }'. The types of 'ctx.allowedProjects' are incompatible between these types. Type 'string[]' is not assignable to type 'number[]'. Type 'string' is not assignable to type 'number'.use (); projectAccessMiddleware
다음은 여러 독립형 미들웨어를 사용한 예시입니다:
tsimport {experimental_standaloneMiddleware ,initTRPC } from '@trpc/server';import * asz from 'zod';constt =initTRPC .create ();constschemaA =z .object ({valueA :z .string () });constschemaB =z .object ({valueB :z .string () });constvalueAUppercaserMiddleware =experimental_standaloneMiddleware <{input :z .infer <typeofschemaA >;}>().create ((opts ) => {returnopts .next ({ctx : {valueAUppercase :opts .input .valueA .toUpperCase () },});});constvalueBUppercaserMiddleware =experimental_standaloneMiddleware <{input :z .infer <typeofschemaB >;}>().create ((opts ) => {returnopts .next ({ctx : {valueBUppercase :opts .input .valueB .toUpperCase () },});});constcombinedInputThatSatisfiesBothMiddlewares =z .object ({valueA :z .string (),valueB :z .string (),extraProp :z .string (),});t .procedure .input (combinedInputThatSatisfiesBothMiddlewares ).use (valueAUppercaserMiddleware ).use (valueBUppercaserMiddleware ).query (({input : {valueA ,valueB ,extraProp },ctx : {valueAUppercase ,valueBUppercase },}) =>`valueA: ${valueA }, valueB: ${valueB }, extraProp: ${extraProp }, valueAUppercase: ${valueAUppercase }, valueBUppercase: ${valueBUppercase }`,);
tsimport {experimental_standaloneMiddleware ,initTRPC } from '@trpc/server';import * asz from 'zod';constt =initTRPC .create ();constschemaA =z .object ({valueA :z .string () });constschemaB =z .object ({valueB :z .string () });constvalueAUppercaserMiddleware =experimental_standaloneMiddleware <{input :z .infer <typeofschemaA >;}>().create ((opts ) => {returnopts .next ({ctx : {valueAUppercase :opts .input .valueA .toUpperCase () },});});constvalueBUppercaserMiddleware =experimental_standaloneMiddleware <{input :z .infer <typeofschemaB >;}>().create ((opts ) => {returnopts .next ({ctx : {valueBUppercase :opts .input .valueB .toUpperCase () },});});constcombinedInputThatSatisfiesBothMiddlewares =z .object ({valueA :z .string (),valueB :z .string (),extraProp :z .string (),});t .procedure .input (combinedInputThatSatisfiesBothMiddlewares ).use (valueAUppercaserMiddleware ).use (valueBUppercaserMiddleware ).query (({input : {valueA ,valueB ,extraProp },ctx : {valueAUppercase ,valueBUppercase },}) =>`valueA: ${valueA }, valueB: ${valueB }, extraProp: ${extraProp }, valueAUppercase: ${valueAUppercase }, valueBUppercase: ${valueBUppercase }`,);