Skip to content

Commit 51764e8

Browse files
committed
feat(openapi-vue-query): Add vue-query suport
1 parent f151f44 commit 51764e8

27 files changed

+5392
-213
lines changed

docs/openapi-vue-query/about.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: About openapi-vue-query
3+
description: openapi-vue-query Project Goals and contributors
4+
---
5+
<script setup>
6+
import { VPTeamMembers } from 'vitepress/theme';
7+
import contributors from '../data/contributors.json';
8+
</script>
9+
10+
# About
11+
12+
## Project Goals
13+
14+
1. Types should be strict and inferred automatically from OpenAPI schemas with the absolute minimum number of generics needed.
15+
2. Respect the original `@tanstack/vue-query` APIs while reducing boilerplate.
16+
3. Be as light and performant as possible.
17+
18+
## Contributors
19+
20+
This library wouldn’t be possible without all these amazing contributors:
21+
22+
<VPTeamMembers size="small" :members="contributors['openapi-vue-query']" />

docs/openapi-vue-query/index.md

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
title: openapi-vue-query
3+
---
4+
# Introduction
5+
6+
openapi-vue-query is a type-safe tiny wrapper (1 kb) around [@tanstack/vue-query](https://tanstack.com/query/latest/docs/framework/vue/overview) to work with OpenAPI schema.
7+
8+
It works by using [openapi-fetch](../openapi-fetch/) and [openapi-typescript](../introduction) so you get all the following features:
9+
10+
- ✅ No typos in URLs or params.
11+
- ✅ All parameters, request bodies, and responses are type-checked and 100% match your schema
12+
- ✅ No manual typing of your API
13+
- ✅ Eliminates `any` types that hide bugs
14+
- ✅ Also eliminates `as` type overrides that can also hide bugs
15+
16+
::: code-group
17+
18+
```vue [src/my-component.vue]
19+
<script setup lang="ts">
20+
import createFetchClient from "openapi-fetch";
21+
import createClient from "openapi-vue-query";
22+
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript
23+
24+
const fetchClient = createFetchClient<paths>({
25+
baseUrl: "https://myapi.dev/v1/",
26+
});
27+
const $api = createClient(fetchClient);
28+
29+
const { data, error, isLoading } = $api.useQuery(
30+
"get",
31+
"/blogposts/{post_id}",
32+
{
33+
params: {
34+
path: { post_id: 5 },
35+
},
36+
}
37+
)
38+
</script>
39+
40+
<template>
41+
<div>
42+
<template v-if="isLoading || !data">
43+
Loading...
44+
</template>
45+
<template v-else-if="error">
46+
An error occurred: {{ error.message }}
47+
</template>
48+
<template v-else>
49+
{{ data.title }}
50+
</template>
51+
</div>
52+
</template>
53+
```
54+
55+
:::
56+
57+
## Setup
58+
59+
Install this library along with [openapi-fetch](../openapi-fetch/) and [openapi-typescript](../introduction):
60+
61+
```bash
62+
npm i openapi-vue-query openapi-fetch
63+
npm i -D openapi-typescript typescript
64+
```
65+
66+
::: tip Highly recommended
67+
68+
Enable [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in your `tsconfig.json` ([docs](/advanced#enable-nouncheckedindexedaccess-in-tsconfig))
69+
70+
:::
71+
72+
Next, generate TypeScript types from your OpenAPI schema using openapi-typescript:
73+
74+
```bash
75+
npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts
76+
```
77+
78+
## Basic usage
79+
80+
Once your types has been generated from your schema, you can create a [fetch client](../introduction.md), a vue-query client and start querying your API.
81+
82+
::: code-group
83+
84+
```vue [src/my-component.vue]
85+
<script setup lang="ts">
86+
import createFetchClient from "openapi-fetch";
87+
import createClient from "openapi-vue-query";
88+
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript
89+
90+
const fetchClient = createFetchClient<paths>({
91+
baseUrl: "https://myapi.dev/v1/",
92+
});
93+
const $api = createClient(fetchClient);
94+
95+
const { data, error, isLoading } = $api.useQuery(
96+
"get",
97+
"/blogposts/{post_id}",
98+
{
99+
params: {
100+
path: { post_id: 5 },
101+
},
102+
}
103+
)
104+
</script>
105+
106+
<template>
107+
<div>
108+
<template v-if="isLoading || !data">
109+
Loading...
110+
</template>
111+
<template v-else-if="error">
112+
An error occurred: {{ error.message }}
113+
</template>
114+
<template v-else>
115+
{{ data.title }}
116+
</template>
117+
</div>
118+
</template>
119+
```
120+
121+
:::
122+
123+
::: tip
124+
You can find more information about `createFetchClient` on the [openapi-fetch documentation](../openapi-fetch/index.md).
125+
:::
+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: queryOptions
3+
---
4+
# {{ $frontmatter.title }}
5+
6+
The `queryOptions` method allows you to construct type-safe [Query Options](https://tanstack.com/query/latest/docs/framework/vue/guides/query-options).
7+
8+
`queryOptions` can be used together with `@tanstack/vue-query` APIs that take query options, such as
9+
[useQuery](https://tanstack.com/query/latest/docs/framework/vue/reference/useQuery),
10+
[useQueries](https://tanstack.com/query/latest/docs/framework/vue/reference/useQueries) and
11+
[QueryClient.fetchQuery](https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientfetchquery)
12+
among many others.
13+
14+
If you would like to use a query API that is not explicitly supported by `openapi-vue-query`, this is the way to go.
15+
16+
## Examples
17+
18+
[useQuery example](use-query#example) rewritten using `queryOptions`.
19+
20+
::: code-group
21+
22+
```vue [src/App.vue]
23+
<script setup lang="ts">
24+
import { useQuery } from "@tanstack/vue-query";
25+
import { $api } from "./api";
26+
27+
const { data, error, isLoading } = useQuery(
28+
$api.queryOptions("get", "/users/{user_id}", {
29+
params: {
30+
path: { user_id: 5 },
31+
},
32+
}),
33+
);
34+
</script>
35+
36+
<template>
37+
<div>
38+
<template v-if="!data || isLoading">
39+
Loading...
40+
</template>
41+
<template v-else-if="error">
42+
An error occured: {{ error.message }}
43+
</template>
44+
<template v-else>
45+
{{ data.firstname }}
46+
</template>
47+
</div>
48+
</template>
49+
```
50+
51+
```ts [src/api.ts]
52+
import createFetchClient from "openapi-fetch";
53+
import createClient from "openapi-vue-query";
54+
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript
55+
56+
const fetchClient = createFetchClient<paths>({
57+
baseUrl: "https://myapi.dev/v1/",
58+
});
59+
export const $api = createClient(fetchClient);
60+
```
61+
62+
:::
63+
64+
::: info Good to Know
65+
66+
[useQuery](use-query) uses `queryOptions` under the hood.
67+
68+
:::
69+
70+
Usage with [useQueries](https://tanstack.com/query/latest/docs/framework/vue/reference/useQueries).
71+
72+
::: code-group
73+
74+
```tsx [src/use-users-by-id.ts]
75+
import { useQueries } from '@tanstack/vue-query';
76+
import { $api } from "./api";
77+
78+
export const useUsersById = (userIds: number[]) => (
79+
useQueries({
80+
queries: userIds.map((userId) => (
81+
$api.queryOptions("get", "/users/{user_id}", {
82+
params: {
83+
path: { user_id: userId },
84+
},
85+
})
86+
))
87+
})
88+
);
89+
```
90+
91+
```ts [src/api.ts]
92+
import createFetchClient from "openapi-fetch";
93+
import createClient from "openapi-vue-query";
94+
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript
95+
96+
const fetchClient = createFetchClient<paths>({
97+
baseUrl: "https://myapi.dev/v1/",
98+
});
99+
export const $api = createClient(fetchClient);
100+
```
101+
102+
:::
103+
104+
## Api
105+
106+
```tsx
107+
const queryOptions = $api.queryOptions(method, path, options, queryOptions);
108+
```
109+
110+
**Arguments**
111+
112+
- `method` **(required)**
113+
- The HTTP method to use for the request.
114+
- The method is used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
115+
- `path` **(required)**
116+
- The pathname to use for the request.
117+
- Must be an available path for the given method in your schema.
118+
- The pathname is used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
119+
- `options`
120+
- The fetch options to use for the request.
121+
- Only required if the OpenApi schema requires parameters.
122+
- The options `params` are used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
123+
- `queryOptions`
124+
- Additional query options to pass through.
125+
126+
**Returns**
127+
128+
- [Query Options](https://tanstack.com/query/latest/docs/framework/vue/guides/query-options)
129+
- Fully typed thus `data` and `error` will be correctly deducted.
130+
- `queryKey` is `[method, path, params]`.
131+
- `queryFn` is set to a fetcher function.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
title: useInfiniteQuery
3+
---
4+
5+
# {{ $frontmatter.title }}
6+
7+
The `useInfiniteQuery` method allows you to use the original [useInfiniteQuery](https://tanstack.com/query/latest/docs/framework/vue/guides/infinite-queries)
8+
9+
- The result is the same as the original function.
10+
- The `queryKey` is `[method, path, params]`.
11+
- `data` and `error` are fully typed.
12+
- You can pass infinite query options as fourth parameter.
13+
14+
::: tip
15+
You can find more information about `useInfiniteQuery` on the [@tanstack/vue-query documentation](https://tanstack.com/query/latest/docs/framework/vue/guides/infinite-queries).
16+
:::
17+
18+
## Example
19+
20+
::: code-group
21+
22+
```vue [src/App.vue]
23+
<script setup lang="ts">
24+
import { $api } from "./api";
25+
const { data, error, fetchNextPage, hasNextPage, isFetching, isError, isFetchingNextPage } = $api.useInfiniteQuery(
26+
"get",
27+
"/posts",
28+
{
29+
params: {
30+
query: {
31+
limit: 10,
32+
},
33+
},
34+
},
35+
{
36+
getNextPageParam: (lastPage) => lastPage.nextPage,
37+
initialPageParam: 0,
38+
},
39+
);
40+
</script>
41+
42+
<template>
43+
<span v-if="isFetching">Loading...</span>
44+
<span v-else-if="isError">Error: {{ error?.message }}</span>
45+
<div v-else-if="data">
46+
<span v-if="isFetching && !isFetchingNextPage">Fetching...</span>
47+
<ul v-for="(group, index) in data.pages" :key="index">
48+
<li v-for="post in group.posts" :key="post.id">
49+
{{ post.name }}
50+
</li>
51+
</ul>
52+
<button
53+
@click="() => fetchNextPage()"
54+
:disabled="!hasNextPage || isFetchingNextPage"
55+
>
56+
<span v-if="isFetchingNextPage">Loading more...</span>
57+
<span v-else-if="hasNextPage">Load More</span>
58+
<span v-else>Nothing more to load</span>
59+
</button>
60+
</div>
61+
</template>
62+
```
63+
64+
```ts [src/api.ts]
65+
import createFetchClient from "openapi-fetch";
66+
import createClient from "openapi-vue-query";
67+
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript
68+
69+
const fetchClient = createFetchClient<paths>({
70+
baseUrl: "https://myapi.dev/v1/",
71+
});
72+
export const $api = createClient(fetchClient);
73+
```
74+
75+
:::
76+
77+
## Api
78+
79+
```tsx
80+
const query = $api.useInfiniteQuery(
81+
method,
82+
path,
83+
options,
84+
infiniteQueryOptions,
85+
queryClient
86+
);
87+
```
88+
89+
**Arguments**
90+
91+
- `method` **(required)**
92+
- The HTTP method to use for the request.
93+
- The method is used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
94+
- `path` **(required)**
95+
- The pathname to use for the request.
96+
- Must be an available path for the given method in your schema.
97+
- The pathname is used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
98+
- `options`
99+
- The fetch options to use for the request.
100+
- Only required if the OpenApi schema requires parameters.
101+
- The options `params` are used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/vue/guides/query-keys) for more information.
102+
- `infiniteQueryOptions`
103+
- The original `useInfiniteQuery` options.
104+
- [See more information](https://tanstack.com/query/latest/docs/framework/vue/reference/useInfiniteQuery)
105+
- `queryClient`
106+
- The original `queryClient` option.
107+
- [See more information](https://tanstack.com/query/latest/docs/framework/vue/reference/useInfiniteQuery)

0 commit comments

Comments
 (0)