fork of hey-api/openapi-ts because I need some additional things
at main 212 lines 6.1 kB view raw
1<script lang="ts" setup> 2import type { Pet } from '@/client' 3import type { RequestOptions } from '@/client/client' 4import { PiniaColadaDevtools } from '@pinia/colada-devtools' 5import { createClient } from '@/client/client' 6import { PetSchema } from '@/client/schemas.gen' 7import { addPetMutation, getPetByIdQuery, updatePetMutation } from '@/client/@pinia/colada.gen' 8import { useQuery, useMutation, useQueryCache } from '@pinia/colada' 9import { ref, watch } from 'vue' 10 11const localClient = createClient({ 12 // set default base url for requests made by this client 13 baseUrl: 'https://petstore3.swagger.io/api/v3', 14 /** 15 * Set default headers only for requests made by this client. This is to 16 * demonstrate local clients and their configuration taking precedence over 17 * internal service client. 18 */ 19 headers: { 20 Authorization: 'Bearer <token_from_local_client>' 21 } 22}) 23 24localClient.interceptors.request.use((request: Request, options: RequestOptions) => { 25 // Middleware is great for adding authorization tokens to requests made to 26 // protected paths. Headers are set randomly here to allow surfacing the 27 // default headers, too. 28 if (options.url === '/pet/{petId}' && options.method === 'GET' && Math.random() < 0.5) { 29 request.headers.set('Authorization', 'Bearer <token_from_interceptor>') 30 } 31 return request 32}) 33 34const isPetNameRequired = PetSchema.required.includes('name') 35 36const petId = ref<number | undefined>() 37const petInput = ref({ name: '', category: '' }) 38 39const { data: pet, error } = useQuery(() => ({ 40 ...getPetByIdQuery({ 41 path: { 42 petId: petId.value as number 43 } 44 }), 45 enabled: petId.value !== undefined 46})) 47const { mutateAsync: createPet } = useMutation(addPetMutation()) 48const { mutateAsync: updatePet } = useMutation(updatePetMutation()) 49 50const queryCache = useQueryCache() 51async function invalidateCurrentPet() { 52 const { key } = getPetByIdQuery({ 53 path: { 54 petId: petId.value as number 55 } 56 }) 57 await queryCache.invalidateQueries({ key, exact: true }) 58} 59 60async function updatePetIdAndInvalidate(newId: number | undefined) { 61 if (newId !== undefined) { 62 petId.value = newId 63 } 64 65 if (petId.value !== undefined) { 66 await invalidateCurrentPet() 67 } 68} 69 70async function handleAddPet() { 71 if (isPetNameRequired && !petInput.value.name) return 72 73 const result = await createPet({ body: buildPetBody() }) 74 if (!result) return 75 76 await updatePetIdAndInvalidate(result.id) 77} 78 79async function handleUpdatePet() { 80 if (!pet.value) return 81 82 const result = await updatePet({ 83 body: buildPetBody(pet.value), 84 headers: { 85 Authorization: 'Bearer <token_from_method>' 86 } 87 }) 88 if (!result) return 89 90 await updatePetIdAndInvalidate(result.id) 91} 92 93function randomInt(min: number, max: number) { 94 return Math.floor(Math.random() * (max - min + 1) + min) 95} 96 97function setRandomPetId() { 98 petId.value = randomInt(1, 10) 99} 100 101function buildPetBody(base?: Partial<Pet>) { 102 return { 103 category: { 104 id: base?.category?.id ?? 0, 105 name: petInput.value.category 106 }, 107 id: base?.id ?? 0, 108 name: petInput.value.name, 109 photoUrls: ['string'], 110 status: 'available' as const, 111 tags: [ 112 { 113 id: 0, 114 name: 'string' 115 } 116 ] 117 } 118} 119 120watch(error, (error) => { 121 console.error(error) 122}) 123</script> 124 125<template> 126 <div class="bg-[#18191b] py-12"> 127 <div class="mx-auto flex max-w-md flex-col gap-12"> 128 <div class="flex items-center"> 129 <a class="shrink-0" href="https://heyapi.dev/" target="_blank"> 130 <img 131 alt="Hey API logo" 132 class="size-16 transition duration-300 will-change-auto" 133 src="https://heyapi.dev/assets/raw/logo.png" 134 /> 135 </a> 136 137 <h1 class="text-2xl font-bold text-white">@hey-api/openapi-ts 🤝 Pinia Colada</h1> 138 </div> 139 140 <div class="flex flex-col gap-2"> 141 <div 142 class="flex max-w-60 items-center gap-3 rounded border border-[#575e64] bg-[#1f2123] p-4" 143 > 144 <div 145 class="flex size-10 place-content-center place-items-center rounded-full bg-[#233057] text-lg font-medium text-[#9eb1ff]" 146 > 147 <span> 148 {{ pet?.name?.slice(0, 1) || 'N' }} 149 </span> 150 </div> 151 152 <div> 153 <p class="text-sm font-bold text-white">Name: {{ pet?.name || 'N/A' }}</p> 154 155 <p class="text-sm text-[#f1f7feb5]">Category: {{ pet?.category?.name || 'N/A' }}</p> 156 </div> 157 </div> 158 159 <button 160 class="rounded bg-[#3e63dd] p-1 text-sm font-medium text-white" 161 type="button" 162 @click="setRandomPetId" 163 > 164 Get Random Pet 165 </button> 166 </div> 167 168 <form class="flex flex-col gap-3" @submit.prevent="handleAddPet"> 169 <div class="flex w-64 flex-col gap-1"> 170 <label class="font-medium text-white" for="name">Name</label> 171 172 <input 173 v-model="petInput.name" 174 class="rounded border border-[#575e64] bg-[#121314] p-1 text-sm text-white placeholder:text-[#575e64]" 175 name="name" 176 placeholder="Kitty" 177 required 178 /> 179 </div> 180 181 <div class="flex w-64 flex-col gap-1"> 182 <label class="font-medium text-white" for="category">Category</label> 183 184 <input 185 v-model="petInput.category" 186 class="rounded border border-[#575e64] bg-[#121314] p-1 text-sm text-white placeholder:text-[#575e64]" 187 name="category" 188 placeholder="Cats" 189 required 190 /> 191 </div> 192 193 <div class="flex gap-2"> 194 <button class="rounded bg-[#3e63dd] p-2 text-sm font-medium text-white" type="submit"> 195 Add Pet 196 </button> 197 198 <button 199 class="rounded bg-[#3e63dd] p-2 text-sm font-medium text-white disabled:cursor-not-allowed" 200 :disabled="!pet" 201 type="button" 202 @click="handleUpdatePet" 203 > 204 Update Pet 205 </button> 206 </div> 207 </form> 208 </div> 209 </div> 210 211 <pinia-colada-devtools /> 212</template>