Skip to content

Commit 2fd0f0e

Browse files
hungifydrwpow
andauthored
docs: Add Vue 3 example for openapi-fetch (#1654)
Co-authored-by: Drew Powers <[email protected]>
1 parent 32647c8 commit 2fd0f0e

File tree

21 files changed

+8376
-547
lines changed

21 files changed

+8376
-547
lines changed

docs/openapi-fetch/examples.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ _Note: if you’re using Svelte without SvelteKit, the root example in `src/rout
2626

2727
[View a code example in GitHub](https://github.com/drwpow/openapi-typescript/tree/main/packages/openapi-fetch/examples/sveltekit)
2828

29-
## Vue
29+
## Vue 3
3030

31-
There isn’t an example app in Vue yet. Are you using it in Vue? Please [open a PR to add it!](https://github.com/drwpow/openapi-typescript/pulls)
31+
[Vue 3](https://vuejs.org/) is a popular framework with a large ecosystem. Vue 3’s Composition API is a perfect match for openapi-fetch, as it allows for easy separation of concerns and reactivity.
3232

33-
---
33+
## [View a code example in GitHub](https://github.com/drwpow/openapi-typescript/tree/main/packages/openapi-fetch/examples/vue-3)
3434

3535
Additional examples are always welcome! Please [open a PR](https://github.com/drwpow/openapi-typescript/pulls) with your examples.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
.DS_Store
12+
dist
13+
dist-ssr
14+
coverage
15+
*.local
16+
17+
/cypress/videos/
18+
/cypress/screenshots/
19+
20+
# Editor directories and files
21+
.vscode/*
22+
!.vscode/extensions.json
23+
.idea
24+
*.suo
25+
*.ntvs*
26+
*.njsproj
27+
*.sln
28+
*.sw?
29+
30+
*.tsbuildinfo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# openapi-fetch + Vue
2+
3+
Example of using openapi-fetch with [Vue](https://vuejs.org/).
4+
5+
## Setup
6+
7+
```sh
8+
pnpm i
9+
pnpm run dev
10+
```
11+
12+
You’ll see the server running at `localhost:5173`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<link rel="icon" href="/favicon.ico">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Vite App</title>
8+
</head>
9+
<body>
10+
<div id="app"></div>
11+
<script type="module" src="/src/main.ts"></script>
12+
</body>
13+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "vue",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "run-p type-check \"build-only {@}\" --",
9+
"preview": "vite preview",
10+
"build-only": "vite build",
11+
"type-check": "vue-tsc --build --force",
12+
"generate": "openapi-typescript src/schema/catfact.json -o src/generated/catfact.d.ts"
13+
},
14+
"dependencies": {
15+
"npm-run-all": "^4.1.5",
16+
"openapi-fetch": "workspace:^",
17+
"vue": "^3.4.21"
18+
},
19+
"devDependencies": {
20+
"@tsconfig/node20": "^20.1.4",
21+
"@types/node": "^20.12.5",
22+
"@vitejs/plugin-vue": "^5.0.4",
23+
"@vue/tsconfig": "^0.5.1",
24+
"openapi-typescript": "workspace:^",
25+
"typescript": "~5.4.0",
26+
"vite": "^5.2.8",
27+
"vue-tsc": "^2.0.11"
28+
}
29+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<script setup lang="ts">
2+
import { useCatFactQuery } from "./composables/catfact-query";
3+
4+
const { error, isFetching, isReady, state, execute } = useCatFactQuery({
5+
params: {
6+
query: {
7+
max_length: 140,
8+
},
9+
},
10+
});
11+
</script>
12+
13+
<template>
14+
<div class="demo">
15+
<button @click="execute">Execute</button>
16+
<pre class="code-block">{{
17+
JSON.stringify(
18+
{
19+
isReady,
20+
isFetching,
21+
error,
22+
state,
23+
},
24+
undefined,
25+
2
26+
)
27+
}}</pre>
28+
</div>
29+
</template>
30+
31+
<style scoped>
32+
.demo {
33+
padding: 16px;
34+
margin: 0 auto;
35+
width: 800px;
36+
}
37+
.demo .code-block {
38+
background-color: #202127;
39+
padding: 4px 8px;
40+
margin: 12px 0;
41+
border-radius: 4px;
42+
word-break: break-all;
43+
white-space: pre-wrap;
44+
word-wrap: break-word;
45+
}
46+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* color palette from <https://github.com/vuejs/theme> */
2+
:root {
3+
--vt-c-white: #ffffff;
4+
--vt-c-white-soft: #f8f8f8;
5+
--vt-c-white-mute: #f2f2f2;
6+
7+
--vt-c-black: #181818;
8+
--vt-c-black-soft: #222222;
9+
--vt-c-black-mute: #282828;
10+
11+
--vt-c-indigo: #2c3e50;
12+
13+
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
14+
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
15+
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
16+
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
17+
18+
--vt-c-text-light-1: var(--vt-c-indigo);
19+
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
20+
--vt-c-text-dark-1: var(--vt-c-white);
21+
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
22+
}
23+
24+
/* semantic color variables for this project */
25+
:root {
26+
--color-background: var(--vt-c-white);
27+
--color-background-soft: var(--vt-c-white-soft);
28+
--color-background-mute: var(--vt-c-white-mute);
29+
30+
--color-border: var(--vt-c-divider-light-2);
31+
--color-border-hover: var(--vt-c-divider-light-1);
32+
33+
--color-heading: var(--vt-c-text-light-1);
34+
--color-text: var(--vt-c-text-light-1);
35+
36+
--section-gap: 160px;
37+
}
38+
39+
@media (prefers-color-scheme: dark) {
40+
:root {
41+
--color-background: var(--vt-c-black);
42+
--color-background-soft: var(--vt-c-black-soft);
43+
--color-background-mute: var(--vt-c-black-mute);
44+
45+
--color-border: var(--vt-c-divider-dark-2);
46+
--color-border-hover: var(--vt-c-divider-dark-1);
47+
48+
--color-heading: var(--vt-c-text-dark-1);
49+
--color-text: var(--vt-c-text-dark-2);
50+
}
51+
}
52+
53+
*,
54+
*::before,
55+
*::after {
56+
box-sizing: border-box;
57+
margin: 0;
58+
font-weight: normal;
59+
}
60+
61+
body {
62+
min-height: 100vh;
63+
color: var(--color-text);
64+
background: var(--color-background);
65+
transition:
66+
color 0.5s,
67+
background-color 0.5s;
68+
line-height: 1.6;
69+
font-family:
70+
Inter,
71+
-apple-system,
72+
BlinkMacSystemFont,
73+
'Segoe UI',
74+
Roboto,
75+
Oxygen,
76+
Ubuntu,
77+
Cantarell,
78+
'Fira Sans',
79+
'Droid Sans',
80+
'Helvetica Neue',
81+
sans-serif;
82+
font-size: 15px;
83+
text-rendering: optimizeLegibility;
84+
-webkit-font-smoothing: antialiased;
85+
-moz-osx-font-smoothing: grayscale;
86+
}
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@import './base.css';
2+
3+
#app {
4+
max-width: 1280px;
5+
margin: 0 auto;
6+
padding: 2rem;
7+
font-weight: normal;
8+
}
9+
10+
@media (min-width: 1024px) {
11+
body {
12+
display: flex;
13+
place-items: center;
14+
}
15+
16+
#app {
17+
display: grid;
18+
grid-template-columns: 1fr;
19+
padding: 0 2rem;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import client from "#/lib";
2+
import { ref } from "vue";
3+
import type { ParamsOption, RequestBodyOption } from "openapi-fetch";
4+
import type { paths } from "#/generated/catfact";
5+
6+
interface AppError {
7+
code: number;
8+
message: string;
9+
}
10+
11+
type FactCatQueryOptions<T> = ParamsOption<T> & RequestBodyOption<T>;
12+
13+
type CatFactResponse =
14+
paths["/fact"]["get"]["responses"]["200"]["content"]["application/json"];
15+
16+
export const useCatFactQuery = (
17+
fetchOptions: FactCatQueryOptions<paths["/fact"]["get"]>
18+
) => {
19+
const state = ref<CatFactResponse>();
20+
const isReady = ref(false);
21+
const isFetching = ref(false);
22+
const error = ref<AppError | undefined>(undefined);
23+
24+
async function execute() {
25+
error.value = undefined;
26+
isReady.value = false;
27+
isFetching.value = true;
28+
29+
const { data, error: fetchError } = await client.GET("/fact", fetchOptions);
30+
31+
if (fetchError) {
32+
error.value = fetchError;
33+
} else {
34+
state.value = data;
35+
isReady.value = true;
36+
}
37+
38+
isFetching.value = false;
39+
}
40+
41+
execute();
42+
43+
return {
44+
state,
45+
isReady,
46+
isFetching,
47+
error,
48+
execute,
49+
};
50+
};

0 commit comments

Comments
 (0)