useQuery(...)
The Hook enables you to perform asynchronous data fetching operations. It automatically handles loading states, caching, and data invalidation, significantly simplifying request in React. See the TanStack useQuery(...) 🌴 documentation for more details.
const query = api.<service>.<operation>.useQuery(
parameters,
queryOptions
)
Returns
UseQueryResult
object, see the TanStack UseQueryResult 🌴
Arguments
-
parameters: { path, query, header, body? } | QueryKey | void
- Required only if OpenAPI specification defines required parameters
- If the operation has no required parameters according to OpenAPI, you can omit this argument
parameters
will be used to generate theQueryKey
- For write operations (when using
--queryable-write-operations
), you can include abody
parameter - Instead of an object with
{ path, query, header, body }
, you can pass aQueryKey
as an array which is also strictly-typed
-
queryOptions?: UseQueryOptions
- Optional, represents the options of the useQuery(...) 🌴 Hook
queryOptions.queryFn
could be provided to override the defaultqueryFn
used by Qraft
- Optional, represents the options of the useQuery(...) 🌴 Hook
By default, useQuery
hooks are only generated for read operations (GET method). If you want to use query
hooks for write operations (POST, PUT, PATCH methods), use the --queryable-write-operations
CLI option
during code generation.
Example
- by
parameters
- by
QueryKey
- with
body
- with
--create-api-client-fn
option
import { createAPIClient } from './api'; // generated by OpenAPI Qraft CLI
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://api.sandbox.monite.com/v1',
});
function ApprovalPolicyName() {
/**
* `<service>.<operation>.useQuery(...)` initiates the request to retrieve data:
* ###
* GET /approval_policies/321?items_order=asc&items_order=desc
* x-monite-version: 1.0.0
*/
const { data, error, isPending } =
api.approvalPolicies.getApprovalPoliciesId.useQuery(
{
header: {
"x-monite-version": "1.0.0",
},
path: {
approval_policy_id: "123",
},
query: {
items_order: ["asc", "desc"],
},
},
);
if (isPending) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return <div>Approval Policy: {data?.name}</div>;
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ApprovalPolicyName />
</QueryClientProvider>
);
}
Using the Query Key (array) as an arguments for the useQuery
is useful
with combination of api.<service>.<operation>.getQueryKey(...)
method
when shared Query Key is needed.
import { createAPIClient } from './api'; // generated by OpenAPI Qraft CLI
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://api.sandbox.monite.com/v1',
});
function ApprovalPolicyName() {
/**
* `<service>.<operation>.useQuery(...)` initiates the request to retrieve data:
* ###
* GET /approval_policies/123?items_order=asc&items_order=desc
* x-monite-version: 2.0.0
*/
const { data, error, isPending } =
api.approvalPolicies.getApprovalPoliciesId.useQuery(
[
{
method: "get",
url: "/approval_policies/{approval_policy_id}",
},
{
header: {
"x-monite-version": "2.0.0",
},
path: {
approval_policy_id: "321",
},
query: {
items_order: ["asc", "desc"],
},
},
],
);
if (isPending) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return <div>Approval Policy: {data?.name}</div>;
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ApprovalPolicyName />
</QueryClientProvider>
);
}
When using the --queryable-write-operations
option, you can use useQuery
with write operations like POST, PUT, PATCH, etc.
This is particularly useful for APIs that use POST for read operations (like GraphQL or some RPC-style APIs).
Why POST for reading data?
Some APIs, particularly GraphQL, use POST requests for reading data instead of GET. This design is often chosen for several reasons:
- Complex query structures are better sent in a request body than in a URL
- Query strings have length limitations in some browsers and servers
In this example, we're using POST to fetch product data by sending search criteria in the request body
:
import { createAPIClient } from './api'; // generated by OpenAPI Qraft CLI
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://api.sandbox.monite.com/v1',
});
function SearchProducts() {
/**
* `<service>.<operation>.useQuery(...)` initiates a POST request for searching products:
* ###
* POST /products/search
*
* {
* "query": "laptop",
* "filters": {
* "minPrice": 500,
* "category": "electronics"
* }
* }
*/
const { data, error, isPending } =
api.products.postProductsSearch.useQuery({
body: {
query: "laptop",
filters: {
minPrice: 500,
category: "electronics"
}
},
});
if (isPending) {
return <div>Loading products...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<div>
<h2>Search Results</h2>
<ul>
{data?.products.map(product => (
<li key={product.id}>
{product.name} - ${product.price}
</li>
))}
</ul>
</div>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<SearchProducts />
</QueryClientProvider>
);
}
‼️ Non-serializable values in body
If you plan to use non-serializable values (like FormData
, Blob
, File
) in the body
parameter, be aware that
they cannot be reliably used to form QueryKey
. TanStack Query requires Query Keys to be serializable primitives.
In such cases, it's better to use useMutation
instead of useQuery
.
If you really need to use useQuery
with non-serializable values, you can customize the query key hash function:
const queryClient = new QueryClient({
defaultOptions: { queries: { queryKeyHashFn: myCustomQueryKeyHashFn } }
});
Using the --create-api-client-fn
option allows you to customize the API client creation function with specific parameters.
You can specify which services and callback functions should be included in the client by default.
💡 When generating multiple API client functions with different parameters, it might be more convenient to use a configuration file instead of command-line parameters. See the Redocly configuration documentation for more details on how to configure multiple create API client functions in a YAML file.
Example 1: All services but no callbacks by default
Generate a client with all services but no callbacks by default
--create-api-client-fn createServicesOnlyClient services:all callbacks:none
import { createServicesOnlyClient } from './api/create-services-only-client';
import { requestFn } from '@openapi-qraft/react';
import { useQuery } from '@openapi-qraft/react/callbacks';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
// Create a client with all services but we need to explicitly specify which callbacks to use
const api = createServicesOnlyClient(
{
requestFn,
queryClient,
baseUrl: 'https://api.example.com/v1',
},
// All services are available by default
// We only need to specify the callbacks we want to use
{
// 1️⃣ Specify which callbacks we want to include
useQuery,
}
});
function UserProfile() {
// We can use the useQuery hook because we explicitly enabled it
const { data, error, isPending } =
api.users.getUserById.useQuery({
path: { userId: "123" },
});
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>User name: {data?.name}</div>;
}
Example 2: Specific callbacks but no services by default
Generate a client with specific callbacks but no services by default
--create-api-client-fn createCallbacksOnlyClient services:none callbacks:useQuery,useMutation
import { createCallbacksOnlyClient } from './api/create-callbacks-only-client';
import { users } from './api/services/Users'; // Import only needed service (‼️)
import { requestFn } from '@openapi-qraft/react';
import { useSuspenseQuery } from '@openapi-qraft/react/callbacks';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
// Create a client with useQuery and useMutation callbacks but we need to explicitly specify which services to use
const usersAPI = createCallbacksOnlyClient(
// 1️⃣ Specify which service (‼️) we want to include
users,
{
requestFn,
queryClient,
baseUrl: 'https://api.example.com/v1',
},
// 2️⃣ Specify which callbacks we want to include
// ✔︎ useQuery and useMutation callbacks are already included by default
{
useSuspenseQuery,
}
);
function UserProfile() {
// 💡 We can use the useQuery hook as it's included by default
const { data, error, isPending } =
usersAPI.getUserById.useQuery({
path: { userId: "123" },
});
// 💎 We can also use the useSuspenseQuery hook because we explicitly enabled it
const { data: allUsers } = usersAPI.allUserList.useSuspenseQuery();
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<>
<div>User name: {data?.name}</div>
<h4>All users:</h4>
<ul>{allUsers.map(user => <li key={user.id}>{user.name}</li>)}</ul>
</>
);
}
Example 3: Minimal API client (no services, no callbacks by default)
Generate a completely minimal client with nothing included by default
--create-api-client-fn createMinimalAPIClient services:none callbacks:none
import { createMinimalAPIClient } from './api/create-minimal-api-client';
import { requestFn } from '@openapi-qraft/react';
import { getUserById } from './api/services/Users'; // Import only needed operation (❗)
import { useQuery } from '@openapi-qraft/react/callbacks';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
// Create a minimal client by explicitly specifying only the necessary operation (❗) and callbacks
const getUserByIdAPI = createMinimalAPIClient(
// 1️⃣ Explicitly specify which operation(❗) or service(‼️) we need
getUserById, // You could also use `users`, `{ users, files }`.
{
requestFn,
queryClient,
baseUrl: 'https://api.example.com/v1',
},
// 2️⃣ Explicitly specify which callbacks we need
{
useQuery,
}
});
function UserProfile() {
const { data, error, isPending } =
getUserByIdAPI.useQuery({
path: { userId: "123" },
});
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>User name: {data?.name}</div>;
}