如何使用 fetch 对 tRPC 查询的查询参数进行编码

Mic*_*ael 5 rpc typescript next.js trpc.io

根据tRPC文档,查询参数必须遵循此格式

myQuery?input=${encodeURIComponent(JSON.stringify(input))}
Run Code Online (Sandbox Code Playgroud)

我有这个程序:

  hello: publicProcedure
    .input(z.object({ text: z.string() }))
    .output(z.object({ greeting: z.string() }))
    .query(({ input }) => {
      return {
        greeting: `Hello ${input.text}`,
      };
    }),
Run Code Online (Sandbox Code Playgroud)

手动构造的 URL 返回错误:

const data = {text: "my message"}
const res = await fetch('http://localhost:3000/api/trpc/example.hello?batch=1&input='+encodeURIComponent(JSON.stringify(data)), { method: 'GET' });
const body = await res.json();
console.log(body);
Run Code Online (Sandbox Code Playgroud)

该错误表明查询参数编码不正确?知道出了什么问题吗?使用客户端,它的工作原理:const test = api.example.hello.useQuery({ text: "my message" });

{
    "error": {
        "json": {
            "message": "[\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"object\",\n    \"received\": \"undefined\",\n    \"path\": [],\n    \"message\": \"Required\"\n  }\n]",
            "code": -32600,
            "data": {
                "code": "BAD_REQUEST",
                "httpStatus": 400,
                "stack": "TRPCError: [\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"object\",\n    \"received\": \"undefined\",\n    \"path\": [],\n    \"message\": \"Required\"\n  }\n]\n    at inputMiddleware (file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/index.mjs:252:19)\n    at runMicrotasks (<anonymous>)\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n    at async callRecursive (file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/index.mjs:419:32)\n    at async resolve (file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/index.mjs:447:24)\n    at async file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/resolveHTTPResponse-a3869d43.mjs:123:32\n    at async Promise.all (index 0)\n    at async resolveHTTPResponse (file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/resolveHTTPResponse-a3869d43.mjs:120:28)\n    at async nodeHTTPRequestHandler (file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/nodeHTTPRequestHandler-e46cee59.mjs:51:20)\n    at async file:///Users/michael/Projects/t3/test/my-t3-app/node_modules/@trpc/server/dist/adapters/next.mjs:40:9\n    at async Object.apiResolver (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/api-utils/node.js:363:9)\n    at async DevServer.runApi (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/next-server.js:487:9)\n    at async Object.fn (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/next-server.js:749:37)\n    at async Router.execute (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/router.js:253:36)\n    at async DevServer.run (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/base-server.js:384:29)\n    at async DevServer.run (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/dev/next-dev-server.js:741:20)\n    at async DevServer.handleRequest (/Users/michael/Projects/t3/test/my-t3-app/node_modules/next/dist/server/base-server.js:322:20)",
                "path": "example.hello"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我检查了使用客户端 ( ) 时浏览器发送的查询const test = api.example.hello.useQuery({ text: "my message" });。如下查询,成功

http://localhost:3000/api/trpc/example.hello?batch=1&input=%7B%220%22%3A%7B%22json%22%3A%7B%22text%22%3A%22my%20message%22%7D%7D%7D
Run Code Online (Sandbox Code Playgroud)

如果我解码输入查询参数,我会看到{"0":{"json":{"text":"my message"}}}

如果我以相同的方式对构造数据对象进行编码,查询仍然会失败:

const data = {"0":{"json":{"text":"my message"}}}
const res = await fetch('http://localhost:3000/api/trpc/example.hello?batch=1&input='+encodeURIComponent(JSON.stringify(data)), { method: 'GET' });
const body = await res.json();
console.log(body);
Run Code Online (Sandbox Code Playgroud)

似乎0有必要启用 b/c 批处理?但这个json领域似乎很奇怪。

{"0":{"json":{"text":"my message"}}}
Run Code Online (Sandbox Code Playgroud)

知道为什么我构造的获取失败吗?对象的编码/结构的正确格式是什么?

Chr*_*ich 6

不可能告诉您请求需要具有的确切结构,因为这取决于您如何设置 tRPC,特别是您的链接和转换器。data我也无法判断您的请求结构是否正确,因为您没有显示每个请求的内部内容。

话虽这么说,让我们以更一般的方式来看待它。

json您的请求中所需的密钥几乎可以肯定是因为您已将superjson set设置为转换器。这是大多数使用 tRPC 的模板(例如 Create T3 App 或 tRPC 的 GitHub 中的示例项目)中的标准,因此除非您从头开始构建应用程序,否则您可能会启用此功能。superjson 的目的是让发送一些常规 JSON 难以处理的数据类型变得更加容易,例如日期。

关于batch,您写的所有内容都是正确的。但是您也可以修改此行为。由结束链接决定。如果不想批处理,可以使用httpLink代替httpBatchLink(但大多数情况下建议使用批处理链接)。

现在让我们看一些示例请求(我在这里没有对它们进行 URI 编码,以便更容易阅读)

superjson,httpBatchLink:

http://localhost:3000/api/trpc/example.hello?batch=1&input={"0":{"json":{"text":"from tRPC"}}}

superjson,http链接:

http://localhost:3000/api/trpc/example.hello?input={"json":{"text":"from tRPC"}}

没有 superjson,httpBatchLink:

http://localhost:3000/api/trpc/example.hello?batch=1&input={"0":{"text":"from tRPC"}}

没有 superjson,httpLink:

http://localhost:3000/api/trpc/example.hello?input={"text":"from tRPC"}

如果您想以更“标准 REST”的方式与 tRPC API 进行通信,可以使用trpc-openapi

  • 嗨克里斯托弗 - 这非常有帮助!我没有意识到变压器会影响请求结构 (2认同)