Skip to content

Commit 5aa0e05

Browse files
committed
feat: initialize ofetch example project
1 parent a5ea50e commit 5aa0e05

29 files changed

+3838
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Hey API — ofetch example</title>
7+
</head>
8+
<body>
9+
<div id="app"></div>
10+
<script type="module" src="/src/main.ts"></script>
11+
</body>
12+
</html>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { defineConfig } from '@hey-api/openapi-ts';
2+
3+
export default defineConfig({
4+
input:
5+
'https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml',
6+
output: {
7+
format: 'prettier',
8+
lint: 'eslint',
9+
path: './src/client',
10+
},
11+
plugins: [
12+
'@hey-api/client-ofetch',
13+
'@hey-api/schemas',
14+
'@hey-api/sdk',
15+
{
16+
enums: 'javascript',
17+
name: '@hey-api/typescript',
18+
},
19+
],
20+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "@example/openapi-ts-ofetch",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"scripts": {
7+
"build": "vite build",
8+
"dev": "vite",
9+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx --fix --ignore-path .gitignore",
10+
"openapi-ts": "openapi-ts",
11+
"preview": "vite preview",
12+
"typecheck": "vue-tsc --build --force"
13+
},
14+
"dependencies": {
15+
"ofetch": "1.4.1",
16+
"vue": "3.5.21"
17+
},
18+
"devDependencies": {
19+
"@config/vite-base": "workspace:*",
20+
"@hey-api/openapi-ts": "workspace:*",
21+
"@rushstack/eslint-patch": "1.10.5",
22+
"@tsconfig/node20": "20.1.4",
23+
"@types/jsdom": "21.1.7",
24+
"@types/node": "22.10.5",
25+
"@vitejs/plugin-vue": "5.2.1",
26+
"@vitejs/plugin-vue-jsx": "4.1.1",
27+
"@vue/eslint-config-prettier": "10.1.0",
28+
"@vue/eslint-config-typescript": "14.2.0",
29+
"@vue/test-utils": "2.4.6",
30+
"@vue/tsconfig": "0.7.0",
31+
"autoprefixer": "10.4.20",
32+
"eslint": "9.17.0",
33+
"eslint-plugin-vue": "9.32.0",
34+
"jsdom": "23.0.0",
35+
"npm-run-all2": "6.2.0",
36+
"postcss": "8.4.41",
37+
"prettier": "3.4.2",
38+
"tailwindcss": "3.4.9",
39+
"typescript": "5.8.3",
40+
"vite": "7.1.2",
41+
"vite-plugin-vue-devtools": "7.7.0",
42+
"vitest": "3.1.1",
43+
"vue-tsc": "2.2.0"
44+
}
45+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
autoprefixer: {},
4+
tailwindcss: {},
5+
},
6+
};
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
4+
import { createClient } from './client/client';
5+
import { PetSchema } from './client/schemas.gen';
6+
import { addPet, getPetById, updatePet } from './client/sdk.gen';
7+
import type { Pet } from './client/types.gen';
8+
9+
const pet = ref<Pet | undefined>();
10+
const petInput = ref({ name: '', category: '' });
11+
const isPetNameRequired = PetSchema.required.includes('name');
12+
13+
const localClient = createClient({
14+
baseUrl: 'https://petstore3.swagger.io/api/v3',
15+
headers: {
16+
Authorization: 'Bearer <token_from_local_client>',
17+
},
18+
});
19+
20+
localClient.interceptors.request.use((request, options) => {
21+
if (
22+
options.url === '/pet/{petId}' &&
23+
options.method === 'GET' &&
24+
Math.random() < 0.5
25+
) {
26+
request.headers.set('Authorization', 'Bearer <token_from_interceptor>');
27+
}
28+
return request;
29+
});
30+
31+
localClient.interceptors.error.use((error) => {
32+
console.error(error);
33+
return error;
34+
});
35+
36+
function randomInt(min: number, max: number) {
37+
return Math.floor(Math.random() * (max - min + 1) + min);
38+
}
39+
40+
async function setRandomPetId() {
41+
const id = randomInt(1, 10);
42+
const { data, error } = await getPetById({
43+
client: localClient,
44+
path: { petId: id },
45+
});
46+
if (error) {
47+
console.error(error);
48+
return;
49+
}
50+
pet.value = data!;
51+
}
52+
53+
function buildPetBody(base?: Partial<Pet>) {
54+
return {
55+
category: {
56+
id: base?.category?.id ?? 0,
57+
name: petInput.value.category,
58+
},
59+
id: base?.id ?? 0,
60+
name: petInput.value.name,
61+
photoUrls: ['string'],
62+
status: 'available' as const,
63+
tags: [
64+
{
65+
id: 0,
66+
name: 'string',
67+
},
68+
],
69+
};
70+
}
71+
72+
async function handleAddPet() {
73+
if (isPetNameRequired && !petInput.value.name) return;
74+
const { data, error } = await addPet({ body: buildPetBody() });
75+
if (error) {
76+
console.error(error);
77+
return;
78+
}
79+
pet.value = data!;
80+
}
81+
82+
async function handleUpdatePet() {
83+
if (!pet.value) return;
84+
const { data, error } = await updatePet({
85+
body: buildPetBody(pet.value),
86+
headers: { Authorization: 'Bearer <token_from_method>' },
87+
});
88+
if (error) {
89+
console.error(error);
90+
return;
91+
}
92+
pet.value = data!;
93+
}
94+
</script>
95+
96+
<template>
97+
<div class="bg-[#18191b] py-12">
98+
<div class="mx-auto flex max-w-md flex-col gap-12">
99+
<div class="flex items-center">
100+
<a class="shrink-0" href="https://heyapi.dev/" target="_blank">
101+
<img
102+
alt="Hey API logo"
103+
class="size-16 transition duration-300 will-change-auto"
104+
src="https://heyapi.dev/logo.png"
105+
/>
106+
</a>
107+
108+
<h1 class="text-2xl font-bold text-white">
109+
@hey-api/openapi-ts 🤝 ofetch
110+
</h1>
111+
</div>
112+
113+
<div class="flex flex-col gap-2">
114+
<div
115+
class="flex max-w-60 items-center gap-3 rounded border border-[#575e64] bg-[#1f2123] p-4"
116+
>
117+
<div
118+
class="flex size-10 place-content-center place-items-center rounded-full bg-[#233057] text-lg font-medium text-[#9eb1ff]"
119+
>
120+
<span>
121+
{{ pet?.name?.slice(0, 1) || 'N' }}
122+
</span>
123+
</div>
124+
125+
<div>
126+
<p class="text-sm font-bold text-white">
127+
Name: {{ pet?.name || 'N/A' }}
128+
</p>
129+
130+
<p class="text-sm text-[#f1f7feb5]">
131+
Category: {{ pet?.category?.name || 'N/A' }}
132+
</p>
133+
</div>
134+
</div>
135+
136+
<button
137+
class="rounded bg-[#3e63dd] p-1 text-sm font-medium text-white"
138+
type="button"
139+
@click="setRandomPetId"
140+
>
141+
Get Random Pet
142+
</button>
143+
</div>
144+
145+
<form class="flex flex-col gap-3" @submit.prevent="handleAddPet">
146+
<div class="flex w-64 flex-col gap-1">
147+
<label class="font-medium text-white" for="name">Name</label>
148+
149+
<input
150+
v-model="petInput.name"
151+
class="rounded border border-[#575e64] bg-[#121314] p-1 text-sm text-white placeholder:text-[#575e64]"
152+
name="name"
153+
placeholder="Kitty"
154+
:required="isPetNameRequired"
155+
/>
156+
</div>
157+
158+
<div class="flex w-64 flex-col gap-1">
159+
<label class="font-medium text-white" for="category">Category</label>
160+
161+
<input
162+
v-model="petInput.category"
163+
class="rounded border border-[#575e64] bg-[#121314] p-1 text-sm text-white placeholder:text-[#575e64]"
164+
name="category"
165+
placeholder="Cats"
166+
required
167+
/>
168+
</div>
169+
170+
<div class="flex gap-2">
171+
<button
172+
class="rounded bg-[#3e63dd] p-2 text-sm font-medium text-white"
173+
type="submit"
174+
>
175+
Add Pet
176+
</button>
177+
178+
<button
179+
class="rounded bg-[#3e63dd] p-2 text-sm font-medium text-white disabled:cursor-not-allowed"
180+
:disabled="!pet"
181+
type="button"
182+
@click="handleUpdatePet"
183+
>
184+
Update Pet
185+
</button>
186+
</div>
187+
</form>
188+
</div>
189+
</div>
190+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
body {
6+
@apply bg-[#111113];
7+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import {
4+
type ClientOptions as DefaultClientOptions,
5+
type Config,
6+
createClient,
7+
createConfig,
8+
} from './client';
9+
import type { ClientOptions } from './types.gen';
10+
11+
/**
12+
* The `createClientConfig()` function will be called on client initialization
13+
* and the returned object will become the client's initial configuration.
14+
*
15+
* You may want to initialize your client this way instead of calling
16+
* `setConfig()`. This is useful for example if you're using Next.js
17+
* to ensure your client always has the correct values.
18+
*/
19+
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> =
20+
(
21+
override?: Config<DefaultClientOptions & T>,
22+
) => Config<Required<DefaultClientOptions> & T>;
23+
24+
export const client = createClient(
25+
createConfig<ClientOptions>({
26+
baseUrl: 'https://petstore3.swagger.io/api/v3',
27+
}),
28+
);

0 commit comments

Comments
 (0)