fork of hey-api/openapi-ts because I need some additional things
at main 238 lines 6.9 kB view raw
1import './App.css'; 2 3import * as Form from '@radix-ui/react-form'; 4import { DownloadIcon, PlusIcon, ReloadIcon } from '@radix-ui/react-icons'; 5import { 6 Avatar, 7 Box, 8 Button, 9 Card, 10 Container, 11 Flex, 12 Heading, 13 Section, 14 Text, 15 TextField, 16} from '@radix-ui/themes'; 17import { useState } from 'react'; 18 19import { createClient } from './client/client'; 20import { PetSchema } from './client/schemas.gen'; 21import { addPet, getPetById, updatePet } from './client/sdk.gen'; 22import type { Pet } from './client/types.gen'; 23 24const localClient = createClient({ 25 // set default base url for requests made by this client 26 baseURL: 'https://petstore3.swagger.io/api/v3', 27 /** 28 * Set default headers only for requests made by this client. This is to 29 * demonstrate local clients and their configuration taking precedence over 30 * global configuration. 31 */ 32 headers: { 33 Authorization: 'Bearer <token_from_local_client>', 34 }, 35}); 36 37localClient.instance.interceptors.request.use((config) => { 38 // Middleware is great for adding authorization tokens to requests made to 39 // protected paths. Headers are set randomly here to allow surfacing the 40 // default headers, too. 41 if ( 42 config.url?.startsWith('/pet/') && 43 config.method === 'get' && 44 Math.random() < 0.5 45 ) { 46 config.headers.set('Authorization', 'Bearer <token_from_interceptor>'); 47 } 48 return config; 49}); 50 51function App() { 52 const [pet, setPet] = useState<Pet>(); 53 const [isRequiredNameError, setIsRequiredNameError] = useState(false); 54 55 const onAddPet = async (formData: FormData) => { 56 // simple form field validation to demonstrate using schemas 57 if (PetSchema.required.includes('name') && !formData.get('name')) { 58 setIsRequiredNameError(true); 59 return; 60 } 61 62 const { data, error } = await addPet({ 63 body: { 64 category: { 65 id: 0, 66 name: formData.get('category') as string, 67 }, 68 id: 0, 69 name: formData.get('name') as string, 70 photoUrls: ['string'], 71 status: 'available', 72 tags: [ 73 { 74 id: 0, 75 name: 'string', 76 }, 77 ], 78 }, 79 }); 80 if (error) { 81 console.log(error); 82 return; 83 } 84 setPet(data!); 85 setIsRequiredNameError(false); 86 }; 87 88 const onGetPetById = async () => { 89 const { data, error } = await getPetById({ 90 client: localClient, 91 path: { 92 // random id 1-10 93 petId: Math.floor(Math.random() * (10 - 1 + 1) + 1), 94 }, 95 }); 96 if (error) { 97 console.log(error); 98 return; 99 } 100 setPet(data!); 101 }; 102 103 const onUpdatePet = async () => { 104 const { data, error } = await updatePet({ 105 body: { 106 category: { 107 id: 0, 108 name: 'Cats', 109 }, 110 id: 2, 111 name: 'Updated Kitty', 112 photoUrls: ['string'], 113 status: 'available', 114 tags: [ 115 { 116 id: 0, 117 name: 'string', 118 }, 119 ], 120 }, 121 // setting headers per request 122 headers: { 123 Authorization: 'Bearer <token_from_method>', 124 }, 125 }); 126 if (error) { 127 console.log(error); 128 return; 129 } 130 setPet(data!); 131 }; 132 133 return ( 134 <Box 135 style={{ background: 'var(--gray-a2)', borderRadius: 'var(--radius-3)' }} 136 > 137 <Container size="1"> 138 <Section size="1" /> 139 <Flex align="center"> 140 <a className="shrink-0" href="https://heyapi.dev/" target="_blank"> 141 <img 142 src="https://heyapi.dev/assets/raw/logo.png" 143 className="h-16 w-16 transition duration-300 will-change-auto" 144 alt="Hey API logo" 145 /> 146 </a> 147 <Heading>@hey-api/openapi-ts 🤝 Axios</Heading> 148 </Flex> 149 <Section size="1" /> 150 <Flex direction="column" gapY="2"> 151 <Box maxWidth="240px"> 152 <Card> 153 <Flex gap="3" align="center"> 154 <Avatar 155 size="3" 156 src={pet?.photoUrls[0]} 157 radius="full" 158 fallback={pet?.name.slice(0, 1) ?? 'N'} 159 /> 160 <Box> 161 <Text as="div" size="2" weight="bold"> 162 Name: {pet?.name ?? 'N/A'} 163 </Text> 164 <Text as="div" size="2" color="gray"> 165 Category: {pet?.category?.name ?? 'N/A'} 166 </Text> 167 </Box> 168 </Flex> 169 </Card> 170 </Box> 171 <Button onClick={onGetPetById}> 172 <DownloadIcon /> Get Random Pet 173 </Button> 174 </Flex> 175 <Section size="1" /> 176 <Flex direction="column" gapY="2"> 177 <Form.Root 178 className="w-[260px]" 179 onSubmit={(event) => { 180 event.preventDefault(); 181 onAddPet(new FormData(event.currentTarget)); 182 }} 183 > 184 <Form.Field className="grid mb-[10px]" name="email"> 185 <div className="flex items-baseline justify-between"> 186 <Form.Label className="text-[15px] font-medium leading-[35px] text-white"> 187 Name 188 </Form.Label> 189 {isRequiredNameError && ( 190 <Form.Message className="text-[13px] text-white opacity-[0.8]"> 191 Please enter a name 192 </Form.Message> 193 )} 194 </div> 195 <Form.Control asChild> 196 <TextField.Root placeholder="Kitty" name="name" type="text" /> 197 </Form.Control> 198 </Form.Field> 199 <Form.Field className="grid mb-[10px]" name="question"> 200 <div className="flex items-baseline justify-between"> 201 <Form.Label className="text-[15px] font-medium leading-[35px] text-white"> 202 Category 203 </Form.Label> 204 <Form.Message 205 className="text-[13px] text-white opacity-[0.8]" 206 match="valueMissing" 207 > 208 Please enter a category 209 </Form.Message> 210 </div> 211 <Form.Control asChild> 212 <TextField.Root 213 placeholder="Cats" 214 name="category" 215 type="text" 216 required 217 /> 218 </Form.Control> 219 </Form.Field> 220 <Flex gapX="2"> 221 <Form.Submit asChild> 222 <Button type="submit"> 223 <PlusIcon /> Add Pet 224 </Button> 225 </Form.Submit> 226 <Button onClick={onUpdatePet} type="button"> 227 <ReloadIcon /> Update Pet 228 </Button> 229 </Flex> 230 </Form.Root> 231 </Flex> 232 <Section size="1" /> 233 </Container> 234 </Box> 235 ); 236} 237 238export default App;