React Query

Learn how to use CallApi with React Query

This guide covers the essential patterns and best practices for using CallApi within React Query, allowing you to use CallApi's many features alongside React Query's caching and synchronization capabilities.

Quick Start

By default, CallApi returns errors as values in the result object instead of throwing them. However, React Query expects either a resolved promise with data or a rejected promise with an error.

You configure callApi to align with that expectation:

api/todos.ts
import { useQuery } from "@tanstack/react-query";
import { callApi } from "@zayne-labs/callapi";

type Todo = {
	completed: boolean;
	id: number;
	title: string;
};

export const useTodos = () => {
	return useQuery({
		queryKey: ["todos"],
		queryFn: () => {
			return callApi<Todo[], false>("/todos", {
				throwOnError: true,
				resultMode: "onlyData",
			});
		},
	});
};

Configuration Options

The key options for React Query integration include:

  • throwOnError: true - Makes CallApi throw errors instead of returning them in the result object
  • resultMode: "onlyData" - Returns just the data property with its exact type, perfect for React Query

These settings ensure CallApi behaves exactly like React Query expects: throwing errors for failures and returning clean data for successes.

Centralized Configuration

api/client.ts
import { createFetchClient } from "@zayne-labs/callapi";

export const callApiForQuery = createFetchClient({
	baseURL: "https://api.example.com",
	// Default to React Query compatible settings
	throwOnError: true,
	resultMode: "onlyData",
});

// Use the configured client in queries
export const useTodos = () => {
	return useQuery({
		queryKey: ["todos"],
		queryFn: () => callApiForQuery<Todo[]>("/todos"),
	});
};

Data Inference via typescript

Using validation libraries like Zod provides both runtime safety and automatic type inference:

hooks/useTodos.ts
import { useQuery } from "@tanstack/react-query";
import { callApi } from "@zayne-labs/callapi";
import { z } from "zod";

const todosSchema = z.array(
	z.object({
		id: z.number(),
		title: z.string(),
		completed: z.boolean(),
	})
);

export const useTodos = () => {
	return useQuery({
		queryKey: ["todos"],
		queryFn: () => {
			return callApi("/todos", {
				schema: { data: todosSchema },
				throwOnError: true,
				resultMode: "onlyData",
			});
		},
	});
};

Option 2: Manual Type Specification

hooks/useTodos.ts
import { useQuery } from "@tanstack/react-query";
import { callApi } from "@zayne-labs/callapi";

type Todo = {
	completed: boolean;
	id: number;
	title: string;
};

export const useTodos = () => {
	return useQuery({
		queryKey: ["todos"],
		queryFn: () => {
			// Pass `false` as second generic to signal errors will be thrown allow callApi to return the expected type
			// This is needed due to TypeScript limitations with partial generic inference
			// See: https://github.com/microsoft/TypeScript/issues/26242
			return callApi<Todo[], false>("@get/todos", {
				throwOnError: true,
				resultMode: "onlyData",
			});
		},
	});
};
Edit on GitHub

Last updated on

On this page