# React Query Setup

Integrate Courier with @tanstack/react-query for automatic caching, refetching, and type-safe hooks.

## Overview

`createProxyQueryCaller` creates a type-safe query client with dot-notation access to all your endpoint groups. Each group exposes `useQuery`, `useMutation`, `useSuspenseQuery`, `useInfiniteQuery`, and `prefetchQuery`.

Hooks exist per group only: endpoints declared at the top level of `defineApi({ endpoints })` have none, so declare the endpoints your components use inside a group.

### Step 1: Install @tanstack/react-query

React Query is a peer dependency, version 5.80 or later — install it alongside Courier:

**npm**

```bash
npm install @tanstack/react-query
```

**pnpm**

```bash
pnpm add @tanstack/react-query
```

**yarn**

```bash
yarn add @tanstack/react-query
```

**bun**

```bash
bun add @tanstack/react-query
```

### Step 2: Set up QueryClientProvider

React Query requires a `QueryClientProvider` at the root of your app. Create a client component that wraps your layout:

```ts title="app/providers.tsx"
// app/providers.tsx
"use client"

import { QueryClient, QueryClientProvider } from "@noverax/courier-react"
import { useState, type ReactNode } from "react"

export function Providers({ children }: { children: ReactNode }) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            staleTime: 60 * 1000,
            retry: 1,
          },
        },
      })
  )

  return (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  )
}
```

```ts title="app/layout.tsx"
// app/layout.tsx
import { Providers } from "./providers"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}
```

### Step 3: Create the Courier query caller

Call `createProxyQueryCaller` with your API's routes: the endpoints a page may call and how it reaches each, which Courier writes into `courier.routes.ts` from the endpoints you marked `.expose()` — see [Exposing Endpoints](/docs/proxy-mode/expose). Export the query client from a single file so every component imports from the same place:

```ts title="lib/query.ts"
// lib/query.ts
import { createProxyQueryCaller } from "@noverax/courier-react"
import { apiRoutes } from "@/courier.routes"

export const q = createProxyQueryCaller(apiRoutes)
```

Then use it in your components with dot-notation:

```ts title="components/user-list.tsx"
"use client"

import { q } from "@/lib/query"

export function UserList() {
  const { data, isLoading } = q.users.useQuery("getAll")
  // ...
}
```

> **Single export file**
>
> Keep the query caller in one file. This ensures all components share the same client instance and defaults.

## Configuring defaults

`createProxyQueryCaller` accepts optional options to configure the underlying proxy caller. They apply to every request:

```ts title="lib/query.ts"
// lib/query.ts
import { createProxyQueryCaller } from "@noverax/courier-react"
import { apiRoutes } from "@/courier.routes"

export const q = createProxyQueryCaller(apiRoutes, {
  // Custom proxy route URL (default: "/api/request")
  proxyPath: { http: "/api/my-proxy" },

  // Request timeout in milliseconds
  timeout: 10000,

  // Include cookies in proxy requests
  credentials: "include",

  // Default headers for all requests
  headers: {
    "X-App-Version": "1.0.0",
  },

  // Global error handler
  onError: async (error) => {
    if (error.status === 401) {
      window.location.href = "/login"
    }
  },

  // Global success handler
  onSuccess: (data) => {
    console.log("Request succeeded:", data)
  },
})
```

## Next steps

- [useQuery](/docs/react-query/use-query) — fetch data with type-safe queries
- [useMutation](/docs/react-query/use-mutation) — create, update, and delete with typed mutations
- [Proxy Caller](/docs/proxy-mode/proxy-caller) — the underlying proxy caller API
