Skip to content

Latest commit

 

History

History
426 lines (353 loc) · 14.3 KB

File metadata and controls

426 lines (353 loc) · 14.3 KB
sidebar_position 2
sidebar_label useQuery()

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

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

  1. 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 the QueryKey
    • For operations generated with --queryable-write-operations, query parameters may also include body
    • In that mode, body is part of the query key and cache identity for query hooks and query-client methods
    • Mutation calls keep body as a separate top-level argument
    • Instead of an object with { path, query, header, body }, you can pass a QueryKey as an array which is also strictly-typed
  2. queryOptions?: UseQueryOptions

    • Optional, represents the options of the useQuery(...) 🌴 Hook
      • queryOptions.queryFn could be provided to override the default queryFn used by Qraft

:::tip 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} default> ```tsx title="src/ApprovalPolicyName.tsx" 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>
  );
}
```
by QueryKey}> Using the Query Key (array) as an arguments for the `useQuery` is useful with combination of [`api...getQueryKey(...)`](../query-client/getQueryKey.mdx) method when shared Query Key is needed.
```tsx title="src/ApprovalPolicyName.tsx"
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>
  );
}
```
with body}> 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`:

```tsx title="src/SearchProducts.tsx"
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:

```tsx
const queryClient = new QueryClient({
  defaultOptions: { queries: { queryKeyHashFn: myCustomQueryKeyHashFn } }
});
```
with --create-api-client-fn option}> 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](../codegen/cli/redocly-config.mdx#generating-multiple-api-client-functions)
> 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_

```bash
--create-api-client-fn createServicesOnlyClient services:all callbacks:none
```

```tsx title="src/ServicesOnlyClient.tsx"
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_

```bash
--create-api-client-fn createCallbacksOnlyClient services:none callbacks:useQuery,useMutation
```

```tsx title="src/CallbacksOnlyClient.tsx"
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_

```bash
--create-api-client-fn createMinimalAPIClient services:none callbacks:none
```

```tsx title="src/MinimalApiClient.tsx"
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>;
}
```