# Queries This guide covers how to use queries for GET, HEAD, and OPTIONS operations with `@qualisero/openapi-endpoint`. ## What is a Query? Queries are used for fetching data from your API. They wrap TanStack Query's `useQuery` composable with type safety based on your OpenAPI specification. ## Basic Query Usage ### Query Without Parameters ```typescript import { api } from './api/init' // Simple query that fetches data on mount const { data: pets, isLoading, error, refetch } = api.listPets.useQuery() console.log(pets.value) // Array of pets console.log(isLoading.value) // true while fetching console.log(error.value) // Error object if request failed ``` ### Query With Path Parameters ```typescript import { api } from './api/init' // Query with required path parameter const { data: pet } = api.getPet.useQuery({ petId: '123' }) console.log(pet.value) // Pet with id '123' ``` ### Query With Query Parameters ```typescript import { api } from './api/init' import { PetStatus } from './api/generated/api-enums' // Query with query parameters - use enum for type safety const { data: pets } = api.listPets.useQuery({ queryParams: { limit: 10, status: PetStatus.Available }, }) // Results in: GET /pets?limit=10&status=available ``` ## Query Options You can pass additional options to customize query behavior: ### Enabled/Disabled Queries ```typescript const { data: pet } = api.getPet.useQuery( { petId: '123' }, { enabled: computed(() => Boolean(selectedPetId.value)), }, ) // Query only runs when selectedPetId has a value ``` ### Stale Time ```typescript const { data: pets } = api.listPets.useQuery( {}, { staleTime: 60 * 1000, // 1 minute }, ) // Data is considered fresh for 1 minute, no refetch within that time ``` ### Garbage Collection Time (gcTime) ```typescript const { data: pets } = api.listPets.useQuery( {}, { gcTime: 5 * 60 * 1000, // 5 minutes }, ) // Data stays in cache for 5 minutes after becoming inactive ``` ### Retry Behavior ```typescript const { data: pets } = api.listPets.useQuery( {}, { retry: 3, // Retry failed requests 3 times retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }, ) ``` ### Custom Success/Error Handlers ```typescript const { data: pets } = api.listPets.useQuery( {}, { onSuccess: (data) => { console.log('Pets loaded:', data) // Update local state, show notification, etc. }, onError: (error) => { console.error('Failed to load pets:', error) // Show error message to user }, }, ) ``` ## Axios Configuration The `axiosOptions` parameter lets you pass custom Axios configuration options to queries. This is useful for authentication headers, timeout settings, request/response transformations, and more. ### Custom Headers ```typescript const { data } = api.listPets.useQuery({ axiosOptions: { headers: { 'X-Custom-Header': 'custom-value', Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', }, }, }) ``` ### Timeout Configuration ```typescript const { data } = api.getPet.useQuery( { petId: '123' }, { axiosOptions: { timeout: 5000, // 5 second timeout }, }, ) ``` ### Request/Response Transformation ```typescript const { data } = api.listPets.useQuery({ axiosOptions: { transformResponse: [ (data) => { const parsed = JSON.parse(data) // Apply custom transformation return parsed }, ], }, }) ``` ### Request Cancellation ```typescript import { ref, onUnmounted } from 'vue' const controller = new AbortController() const { data } = api.listPets.useQuery({ axiosOptions: { signal: controller.signal, }, }) // Cancel request on unmount onUnmounted(() => { controller.abort() }) ``` ### Custom Properties The `AxiosRequestConfigExtended` type supports arbitrary custom properties beyond standard Axios options: ```typescript const { data } = api.listPets.useQuery({ axiosOptions: { // Standard Axios options timeout: 5000, headers: { 'X-Custom-Header': 'value' }, // Custom properties for interceptors or middleware manualErrorHandling: true, handledByAxios: false, customRetryCount: 3, debugMode: true, requestMetadata: { requestId: 'req-123', source: 'list-pets', }, }, }) ``` ### Common Axios Options | Option | Type | Description | | -------------------- | ------------- | --------------------------------------------- | | `headers` | `object` | Custom request headers | | `timeout` | `number` | Request timeout in milliseconds | | `baseURL` | `string` | Override base URL for this request | | `auth` | `object` | Basic authentication `{ username, password }` | | `withCredentials` | `boolean` | Include cookies in cross-origin requests | | `params` | `object` | URL parameters (merged with queryParams) | | `paramsSerializer` | `function` | Custom parameter serializer | | `transformRequest` | `array` | Request data transformers | | `transformResponse` | `array` | Response data transformers | | `onUploadProgress` | `function` | Upload progress callback | | `onDownloadProgress` | `function` | Download progress callback | | `signal` | `AbortSignal` | Request cancellation | | `validateStatus` | `function` | Custom status code validation | For more advanced Axios configuration patterns, see [Axios Configuration guide](./08-axios-configuration.md). ## Query Return Values The `useQuery` hook returns a reactive object with the following properties: ```typescript interface QueryResult { data: ComputedRef // The fetched data isLoading: ComputedRef // True while initial fetch is in progress isFetching: ComputedRef // True while any fetch is in progress (including refetches) isError: ComputedRef // True if an error occurred error: ComputedRef // Error object if query failed refetch: () => Promise // Manually trigger refetch invalidate: () => Promise // Invalidate cache and refetch } ``` ## Lazy Queries Use `useLazyQuery` when you want to control execution imperatively rather than reactively — for example, when query params are not known at component mount time: ```typescript const availabilityQuery = api.getAvailabilityQuery.useLazyQuery() const fetchAvailability = (params: ApiQueryParams<'getAvailabilityQuery'>) => availabilityQuery.fetch({ queryParams: params }) ``` - No request fires on mount - `fetch()` accepts query params at call time and returns `Promise` - Result is cached — subsequent calls with the same params use `staleTime: Infinity` by default - `data`, `isPending`, `isError` are all reactive and update after each `fetch()` **When to use lazy queries:** - Search on button click (not on each keystroke) - Prefetch data on hover - Pagination with explicit next/prev buttons - Any time you need full control over when a request is made See [Lazy Queries guide](./07-lazy-queries.md) for full details. ## Common Query Patterns ### Loading Skeleton ```vue ``` ### Pull-to-Refresh ```vue ``` ### Dependent Queries ```typescript // First query const { data: user } = api.getUser.useQuery({ userId: '123' }) // Second query depends on first query's result const { data: userPets } = api.listUserPets.useQuery( { userId: user.value?.id }, // Only fetches when user is loaded { enabled: computed(() => Boolean(user.value)), }, ) ``` ## What's Next? - [Mutations](./03-mutations.md) - Learn about mutations for POST/PUT/PATCH/DELETE operations - [Reactive Parameters](./04-reactive-parameters.md) - Learn about reactive query and path parameters