Guidelines on encoding query parameters for a tRPC query with the fetch function

As stated in the tRPCs official documentation, the query parameters must adhere to this specific format:

myQuery?input=${encodeURIComponent(JSON.stringify(input))}

Here is an example of a procedure:

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

An attempt to manually create a URL results in an error:

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);

The error suggests that there might be an issue with the encoding of the query parameters. Any insights on what could be going wrong here? Interestingly, it works using the client:

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 and more details..."
                "path": "example.hello"
            }
        }
    }
}

I examined the query sent by the client (

const test = api.example.hello.useQuery({ text: "my message" });
) through my browser, which resulted in success.

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

If I decode the input query parameter, I get

{"0":{"json":{"text":"my message"}}}

Even when I structure my data object in the same manner and encode it accordingly, the query still fails:

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);

The presence of the 0 seems to be necessary due to batching being enabled. However, the inclusion of the json field seems peculiar.

{"0":{"json":{"text":"my message"}}}

Any thoughts on why my constructed fetch request is failing? What would be the correct format for encoding or structuring the object?

Answer №1

It's important to note that the specific structure required for your request will vary depending on how tRPC is configured in your setup, including your links and transformer settings. Without seeing the contents of data for each request, it's difficult to determine if your request is structured correctly.

With that in mind, let's approach this from a more generalized perspective.

The presence of the json key in your requests likely stems from using superjson as your transformer, which is common in many tRPC templates like Create T3 App or example projects on tRPC's GitHub. Superjson simplifies sending complex data types, such as Dates, that can be challenging with standard JSON.

Regarding the batch functionality, your understanding is correct. However, you have the flexibility to adjust this behavior based on the ending link. If batching isn't desired, using httpLink instead of httpBatchLink is an option (though batch linking is generally recommended).

Here are some sample requests, presented in a readable format without URI encoding:

Using superjson with httpBatchLink:

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

Using superjson with httpLink:

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

Without superjson using httpBatchLink:

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

Without superjson using httpLink:

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

If you prefer a more traditional REST-style communication with your tRPC API, consider exploring trpc-openapi.

Answer №2

Remember to include the transformer as superjson when setting up your tRPC client with superjson.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When using Next.js, embedded Gist code blocks in markdown files may only appear after the entire page has finished loading, rather than loading immediately when navigating to a new React route

I am encountering an issue with embedding Gist scripts in my blog posts that are stored in MD files. The problem arises when navigating to the page using the app's routing system without triggering a full page refresh, resulting in the script tags bei ...

How can I position ports on the right side of a graph element in JointJS?

I'm in the process of developing an Angular application that allows users to dynamically create graphs. Currently, I am working on a function that adds ports to vertices and I want the user to be able to select the position of the port (right, left, t ...

Steps for incorporating a type declaration for an array of objects in a React application with TypeScript

How can I specify the type for an array of objects in React using TypeScript? Here is the code snippet: const SomeComponent = (item: string, children: any) => { //some logic } In this code, you can see that I am currently using 'any' as ...

Leveraging Angular 2 to retrieve information from mongoDB

I recently finished setting up my nodejs project which includes a database and some data. The database was created using the following URL: mongodb://localhost:27017/ Check out the code snippet below: var MongoClient = require('mongodb').MongoC ...

Navigating through a JSON dictionary in Svelte: A step-by-step guide

When working with Svelte, the #each construct allows for easy iteration over array-like objects. But what if you have a JSON dictionary object instead? Is there a way in Svelte to iterate over this type of object in order to populate a dropdown menu? The ...

The error is popping up as I try to deploy my Next.js application on Vercel

warning " > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7d0f181c1e095009120d5011121c1914131a501f1c0f3d4f534c534d">[email protected]</a>" has an incorrect peer dependency "react@^16 || ^17" ...

What are the best practices for protecting a web application with login and database in the year 2022?

My knowledge of security is outdated and I am looking to update my skills in full stack development. Currently, I am exploring Oauth2, JWT, Next.JS, Auth0, and more, but I am struggling to integrate all these components together. Please bear with me as I m ...

How can I invoke a TypeScript function within HTML code?

Currently, I am working on an Angular project where I have implemented two straightforward methods in a TypeScript file: findForm(text: string, forms: Array<string>) { for (let form of this.forms) { if (text.includes(form)) { retur ...

Performing a series of HTTP requests within a single @ngrx/effect

I need some guidance as I am new to @ngrx and feeling a bit lost in understanding how it should be used. Let's assume we have an effect named PlaceOrderEffect In this effect, my goal is to handle each request in a specific order. processOrder$ = cre ...

Guide to retrieving Azure web app application settings in a TypeScript file

I recently created an Angular 2 application using Visual Studio 2015. After that, I successfully published my Angular 2 web app to Azure Web App and everything seems to be working fine. However, I am facing a challenge in accessing the application setting ...

Exploring deeplinking capabilities in Next.js

My current method involves using window.assign(bundlename://linkname) to deeplink users into the app if it's already installed on their device. However, I keep encountering an error message in Safari stating "Safari cannot open page because the addres ...

Utilizing TypeScript union types in React: A step-by-step guide

I'm currently working on applying types to ReactJS props using an interface that includes a union type. In the example below, you can see that the tags type is a union type. export interface TagInterface { id: number; name: string; } export inter ...

Router failure resulted in an internal server error

When navigating to a page in my router, I make a REST API request to retrieve data from the server in the beforeEnter clause as shown below: beforeEnter: (to, form, next) => { getData().then( (response) => { ...

Does Next js Backend support multithreading as a default feature?

As I begin my project, I am utilizing the built-in Node js server within Next js by running the next start command. However, I am uncertain as to whether it has multithreading capabilities. My inquiry is this: Would you suggest sticking with the built-in ...

Managing registration with an existing email address in Supabase

Currently, I am working on implementing a sign-up functionality using Supabase and I want to be able to inform the user if they try to sign up with an email that already exists in the system. However, I am facing a challenge in identifying this particular ...

Error: module 'next/react' not found

Recently delving into next.js, I encountered an error after creating a project with npx create-next-app. Oddly enough, the app still runs despite this issue. { "resource": "/E:/codes/news-website/news-website/pages/index.js", ...

Fields may be designated as either optional or required depending on the type parameters that

I am attempting to specify that the payload field should be mandatory only when T is defined: export interface Action<T = any> { readonly type: string; readonly payload?: T; } // The payload field must be included const actionWithPayload: Act ...

Angular - Implementing a debounce feature for event handling

Currently, I am utilizing the mouseenter and mouseleave events to control the opening and closing of my sidenav within the app. However, I have encountered issues because when hovering over the container quickly, these events are triggered multiple times ...

The error message "TypeScript is showing 'yield not assignable' error when using Apollo GraphQL with node-fetch

Currently, I am in the process of implementing schema stitching within a NodeJS/Apollo/GraphQL project that I am actively developing. The implementation is done using TypeScript. The code snippet is as follows: import { makeRemoteExecutableSchema, ...

Make sure the auto import feature in TypeScript Visual Studio Code Editor is set to always use the ".js" extension

At times, the auto-import completion feature includes the .js extension, but inconsistently. When this extension is missing in the TypeScript source, the emitted JavaScript file may encounter runtime issues like module not found error since the tsc compile ...