@openapi-qraft/react
Version:
OpenAPI client for React, providing type-safe requests and dynamic TanStack Query React Hooks via a modular, Proxy-based architecture.
289 lines (238 loc) • 10.6 kB
Markdown
# @openapi-qraft/react
`@openapi-qraft/react` is a modular TypeScript client designed to facilitate type-safe API requests in React
applications,
leveraging the power of **TanStack Query v5**. It utilizes a Proxy-based architecture to dynamically generate
hooks with typed parameters, ensuring that your API requests are both type-safe and efficient.
Read the full documentation at [openapi-qraft.github.io/openapi-qraft](https://openapi-qraft.github.io/openapi-qraft/).
## Features
- **Type-safe API Requests:** Utilize TypeScript for type-safe API requests, reducing runtime errors and improving
developer experience.
- **Modular Design:** Customize the utility with a set of callbacks to handle API calls according to your project's
needs.
- **Integration with [TanStack Query v5](https://tanstack.com/query/v5):** Seamlessly integrate with _TanStack Query_
for handling server state, caching, and data synchronization.
- **Dynamic Proxy-Based Hooks:** Automatically generate React Query hooks for your API endpoints without manual
boilerplate.
## Installation
First, install the core package for your project:
```bash
npm install @openapi-qraft/react
```
If your project doesn't already include `@tanstack/react-query`, you'll also need to install it. This package is
essential for handling server state in React applications:
```bash
npm install @tanstack/react-query
```
## Getting Started
To get started with OpenAPI Qraft, you need to generate types and service definitions from your OpenAPI Document.
These are used to create type-safe hooks and interact with your API.
### 1. Generate OpenAPI Types & Services
Run the following command in the root directory of your project using your package manager:
```bash
npx @openapi-qraft/cli --plugin tanstack-query-react --plugin openapi-typescript \
--output-dir src/api https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml
```
> 💡 For stable project maintenance, it's recommended to install the CLI generator as a dev dependency.
> Read more about installation in the [documentation](https://openapi-qraft.github.io/openapi-qraft/docs/getting-started/installation).
### 2. Use the generated services in your React application
Below are examples demonstrating how to use the generated services in your React application with
`useQuery`, `useMutation`, and `useInfiniteQuery` hooks from [TanStack Query](https://tanstack.com/query/latest).
#### Example with `useQuery()`
```tsx title="src/App.tsx"
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createAPIClient } from './api'; // generated by OpenAPI Qraft
const queryClient = new QueryClient();
// Use `createAPIClient(...)` to initialize the API client as needed.
// It's a lightweight 🪶 shortcut for working with TanStack Query 🌴
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://petstore3.swagger.io/api/v3',
});
function ExamplePetDetails({ petId }: { petId: number }) {
/**
* Executes the request to the API on mount:
* ###
* GET /pet/123456
**/
const {
data: pet,
isPending,
error,
} = api.pet.getPetById.useQuery({
path: { petId },
});
if (isPending) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return <div>Pet Name: {pet?.name}</div>;
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ExamplePetDetails petId={123456} />
</QueryClientProvider>
);
}
```
#### Example with `useMutation()`
```tsx title="src/App.tsx"
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createAPIClient } from './api'; // generated by OpenAPI Qraft
const queryClient = new QueryClient();
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://petstore3.swagger.io/api/v3',
});
function EntityForm({ entityId }: { entityId: string }) {
const mutation = api.entities.postEntitiesIdDocuments.useMutation({
// ☝️ useMutation() can be used with `undefined` parameters
path: {
entity_id: entityId,
},
header: {
'x-monite-version': '2023-09-01',
},
});
return (
<form
onSubmit={(event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
/**
* Executes the request`:
* ###
* POST /entities/3e3e-3e3e-3e3e/documents
* x-monite-version: 2023-09-01
*
* {"company_tax_id_verification": ["verification-id"]}
**/
mutation.mutate({
company_tax_id_verification: [
String(formData.get('company_tax_id_verification')),
],
});
}}
>
<input name="company_tax_id_verification" />
<button>Submit</button>
</form>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<EntityForm entityId="3e3e-3e3e-3e3e" />
</QueryClientProvider>
);
}
```
#### Example with `useInfiniteQuery()`
```tsx title="src/PostList.tsx"
import { requestFn } from '@openapi-qraft/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createAPIClient } from './api'; // generated by OpenAPI Qraft
const queryClient = new QueryClient();
const api = createAPIClient({
requestFn,
queryClient,
baseUrl: 'https://petstore3.swagger.io/api/v3',
});
/**
* Executes the initial request:
* ###
* GET /posts?limit=10&page=1
**/
function PostList() {
const infiniteQuery = api.posts.getPosts.useInfiniteQuery(
{ query: { limit: 10 } },
{
getNextPageParam: (lastPage, allPages, lastPageParams) => {
if (lastPage.length < 10) return; // if less than 10 items, there are no more pages
return {
query: {
page: Number(lastPageParams.query?.page) + 1,
},
};
},
initialPageParam: {
query: {
page: 1, // will be used in initial request
},
},
}
);
return (
<div>
{infiniteQuery.data?.pages.map((page, pageIndex) => (
<ul key={pageIndex}>
{page.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
))}
<button
onClick={() => {
// ⬇︎ Executes GET /posts?limit=10&page=2
infiniteQuery.fetchNextPage();
}}
>
Load More
</button>
</div>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<PostList />
</QueryClientProvider>
);
}
```
## Supported Hooks
- [x] [`useQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useQuery)
- [x] [`useMutation(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useMutation)
- [x] [`useInfiniteQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useInfiniteQuery)
- [x] [`useQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useQueries)
- [x] [`useSuspenseQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useSuspenseQuery)
- [x] [`useSuspenseInfiniteQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useSuspenseInfiniteQuery)
- [x] [`useSuspenseQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useSuspenseQueries)
- [x] [`useIsFetching(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useIsFetching)
- [x] [`useMutationState(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useMutationState)
- [x] [`useIsMutating(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/hooks/useIsMutating)
## `QueryClient` methods
- [x] [`fetchQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/fetchQuery)
- [x] [`fetchInfiniteQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/fetchInfiniteQuery)
- [x] [`prefetchQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/prefetchQuery)
- [x] [`prefetchInfiniteQuery(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/prefetchInfiniteQuery)
- [x] [`getQueryData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getQueryData)
- [x] [`getQueriesData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getQueriesData)
- [x] [`setQueryData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/setQueryData)
- [x] [`getQueryState(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getQueryState)
- [x] [`setQueriesData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/setQueriesData)
- [x] [`invalidateQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/invalidateQueries)
- [x] [`refetchQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/refetchQueries)
- [x] [`cancelQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/cancelQueries)
- [x] [`removeQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/removeQueries)
- [x] [`resetQueries(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/resetQueries)
- [x] [`isFetching(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/isFetching)
- [x] [`isMutating(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/isMutating)
## Qraft Utility Functions
- [x] [`getQueryKey(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getQueryKey)
- [x] [`setInfiniteQueryData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/setInfiniteQueryData)
- [x] [`getInfiniteQueryKey(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getInfiniteQueryKey)
- [x] [`getInfiniteQueryData(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getInfiniteQueryData)
- [x] [`getInfiniteQueryState(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getInfiniteQueryState)
- [x] [`getMutationKey(...)`](https://openapi-qraft.github.io/openapi-qraft/docs/query-client/getMutationKey)
## Contributing
Contributions are welcome! If you have suggestions or want to improve `@openapi-qraft/react`, please feel free to submit
a pull request or open an issue.
## License
`@openapi-qraft/react` is licensed under the MIT License. See the LICENSE file for more details.