Skip to main content
Version: v8.0.0

Query Params

Query parameters are a fundamental part of making dynamic API requests, allowing you to filter, sort, and paginate data. Hyper-Fetch provides a powerful and type-safe way to handle query parameters, ensuring that your requests are both flexible and robust.

What you'll learn
  1. How to add and type-safe query parameters, including optional ones.
  2. How to handle array values in query parameters.
  3. How to set query parameters with the .send() method.
  4. How to customize the serialization of query parameters for arrays, dates, and objects.
  5. What are the precedence rules when setting parameters in multiple ways.

Defining Query Params

To get started, you need to define the shape of your query parameters in the createRequest method. By specifying the queryParams type, you enable type-checking and autocompletion, which helps prevent common errors.

Basic Query Parameters

Once typed, use setQueryParams to add them to your request. Hyper Fetch automatically appends them to the URL.

// 1. Define the query parameters type
const searchRequest = client.createRequest<{ queryParams: { query: string; page: number } }>()({
endpoint: "/search",
});

// 2. Set the parameters
const request = searchRequest.setQueryParams({ query: "hyper-fetch", page: 1 });

// Query params are stored separately until the request is sent
console.log("Endpoint:", request.endpoint); // "/search"
console.log("Query Params:", request.queryParams); // { query: "hyper-fetch", page: 1 }

Optional Query Parameters

Real-world APIs often have optional parameters. You can define them using the ? syntax in the queryParams type. This allows you to omit them if they are not needed.

// `page` is now optional
const searchRequest = client.createRequest<{ queryParams: { query: string; page?: number } }>()({
endpoint: "/search",
});

// We can set only the required `query` parameter
const request = searchRequest.setQueryParams({ query: "hyper-fetch" });

console.log("Query Params:", request.queryParams); // { query: "hyper-fetch" }

// Or we can set both
const requestWithPage = searchRequest.setQueryParams({ query: "hyper-fetch", page: 2 });

console.log("Query Params with page:", requestWithPage.queryParams); // { query: "hyper-fetch", page: 2 }

Array Query Parameters

Hyper Fetch supports arrays in query parameters, which is common for multi-select filters. They are automatically serialized into a format the server can understand (e.g., ?tags=a&tags=b).

const searchByTags = client.createRequest<{ queryParams: { tags: string[] } }>()({
endpoint: "/articles",
});

const request = searchByTags.setQueryParams({ tags: ["typescript", "react", "hyper-fetch"] });

// The final URL will have `?tags[]=typescript&tags[]=react&tags[]=hyper-fetch`
console.log("Query Params:", request.queryParams); // { tags: ["typescript", "react", "hyper-fetch"] }

Setting with send

Just like URL parameters, query parameters can be passed to send. This is ideal for dynamic queries built from user input.

const searchRequest = client.createRequest<{ queryParams: { query: string; page?: number } }>()({
endpoint: "/search",
});

// Query parameters are passed inside `send`
const response = searchRequest.send({
queryParams: { query: "new search" },
});

Customizing Query Param Format

By default, Hyper-Fetch stringifies query parameters using standard conventions. However, some APIs may require a different format. You can easily customize this behavior using setQueryParamsConfig on the client's adapter instance.

This configuration is applied globally to all requests made with that client.

Here are some of the available options:

  • arrayFormat: Controls how arrays are formatted (e.g., bracket, comma, index).
  • skipNull: If true, parameters with null values are excluded.
  • skipEmptyString: If true, parameters with empty string values are excluded.
  • dateParser: A function to serialize Date objects.
  • objectParser: A function to serialize object values.

Custom Array Format

For example, if your backend expects comma-separated array values (?tags=one,two), you can set the arrayFormat to comma.

// 1. Set the array format on the adapter
client.adapter.setQueryParamsConfig({ arrayFormat: "comma" });

const searchByTags = client.createRequest<{ queryParams: { tags: string[] } }>()({
endpoint: "/articles",
});

// 2. The query params will be stringified using the new format
const request = searchByTags.setQueryParams({ tags: ["typescript", "react"] });

// The final URL will have `?tags=typescript,react`

Custom Data Serialization

You can also provide custom serialization functions for dates and objects.

Custom Date serialization

If your API requires dates to be sent as YYYY-MM-DD, you can provide a custom dateParser.

import { format } from "date-fns";

// 1. Provide a custom date parser
client.adapter.setQueryParamsConfig({
dateParser: (date) => format(date, "yyyy-MM-dd"),
});

const getArticles = client.createRequest<{ queryParams: { date: Date } }>()({
endpoint: "/articles",
});

// 2. Dates will now be serialized using the custom parser
const request = getArticles.setQueryParams({ date: new Date() });

// The final URL will have `?date=2023-10-27` (for example)

Custom object serialization

By default, objects are serialized using JSON.stringify. You can override this with objectParser if you need custom logic, such as converting an object to a stringified tuple.

// 1. Provide a custom object parser
client.adapter.setQueryParamsConfig({
objectParser: (obj) => `[${obj.value},${obj.id}]`,
});

const getArticles = client.createRequest<{ queryParams: { filter: { id: number; value: string } } }>()({
endpoint: "/articles",
});

// 2. Objects will be serialized using the custom parser
const request = getArticles.setQueryParams({ filter: { id: 1, value: "hyper-fetch" } });

// The final URL will have `?filter=[hyper-fetch,1]`

Parameter Precedence

It's important to understand what happens when you set parameters in multiple places. Hyper Fetch do not allow you to pass parameters that are already defined in the request.

If you ignore Typescript - parameters passed directly to send will always override those set with setParams or setQueryParams.

const request = client
.createRequest<{ queryParams: { page: number } }>()({ endpoint: "/users/:userId" })
.setParams({ userId: 1 })
.setQueryParams({ page: 1 });

console.log("Initial params:", request.params); // { userId: 1 }
console.log("Initial query params:", request.queryParams); // { page: 1 }

// Parameters given to `send` will override previously set ones.
request.send({
// Typescript will not allow you to pass a parameter that is already defined in the request
params: { userId: 2 },
// Typescript will not allow you to pass a query parameter that is already defined in the request
queryParams: { page: 2 },
});

Congratulations!

You've now mastered handling query parameters with Hyper-Fetch!

  • You can add Query Parameters using createRequest generics, supporting optional (?) and array ([]) types, and setting them with .setQueryParams({ ... }).
  • You can set query parameters dynamically within the .send() method.
  • You can customize query stringification for arrays, dates, and objects.
  • You know that parameters from the .send() method always override those set with .set...() methods.