Skip to content

Commit 96aaa7f

Browse files
committed
docs: usage examples
1 parent aba7866 commit 96aaa7f

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

README.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,166 @@ Options:
7474

7575
Basically, let's focus on having a fast and typesafe API client generation instead.
7676

77+
## Usage Examples
78+
79+
### API Client Setup
80+
81+
The generated client is headless - you need to provide your own fetcher. Here are ready-to-use examples:
82+
83+
- **[Basic API Client](packages/typed-openapi/API_CLIENT_EXAMPLES.md#basic-api-client-api-client-examplets)** - Simple, dependency-free wrapper
84+
- **[Validating API Client](packages/typed-openapi/API_CLIENT_EXAMPLES.md#validating-api-client-api-client-with-validationts)** - With request/response validation
85+
86+
### Type-Safe Error Handling
87+
88+
The generated client includes discriminated union types for handling both success and error responses:
89+
90+
```typescript
91+
// With withResponse: true, get full response details
92+
const result = await api.get("/users/{id}", {
93+
path: { id: "123" },
94+
withResponse: true
95+
});
96+
97+
if (result.ok) {
98+
// result.data is typed as the success response
99+
console.log("User:", result.data.name);
100+
// result.status is typed as success status codes (200, 201, etc.)
101+
} else {
102+
// result.error is typed based on documented error responses
103+
if (result.status === 404) {
104+
console.log("User not found:", result.error.message);
105+
} else if (result.status === 401) {
106+
console.log("Unauthorized:", result.error.details);
107+
}
108+
}
109+
```
110+
111+
### Success Response Type-Narrowing
112+
113+
When endpoints have multiple success responses (200, 201, etc.), the type is automatically narrowed based on status:
114+
115+
```typescript
116+
const result = await api.post("/users", {
117+
body: { name: "John" },
118+
withResponse: true
119+
});
120+
121+
if (result.ok) {
122+
if (result.status === 201) {
123+
// result.data typed as CreateUserResponse (201)
124+
console.log("Created user:", result.data.id);
125+
} else if (result.status === 200) {
126+
// result.data typed as ExistingUserResponse (200)
127+
console.log("Existing user:", result.data.email);
128+
}
129+
}
130+
```
131+
132+
### Generic Request Method
133+
134+
For dynamic endpoint calls or when you need more control:
135+
136+
```typescript
137+
// Type-safe generic request method
138+
const response = await api.request("GET", "/users/{id}", {
139+
path: { id: "123" },
140+
query: { include: ["profile", "settings"] }
141+
});
142+
143+
const user = await response.json(); // Fully typed based on endpoint
144+
```
145+
146+
### TanStack Query Integration
147+
148+
Generate TanStack Query wrappers for your endpoints:
149+
150+
```bash
151+
npx typed-openapi api.yaml --runtime zod --tanstack
152+
```
153+
154+
## useQuery / fetchQuery / ensureQueryData
155+
156+
```ts
157+
// Basic query
158+
const accessiblePagesQuery = useQuery(
159+
tanstackApi.get('/authorization/accessible-pages').queryOptions
160+
);
161+
162+
// Query with query parameters
163+
const membersQuery = useQuery(
164+
tanstackApi.get('/authorization/organizations/:organizationId/members/search', {
165+
path: { organizationId: 'org123' },
166+
query: { searchQuery: 'john' }
167+
}).queryOptions
168+
);
169+
170+
// With additional query options
171+
const departmentCostsQuery = useQuery({
172+
...tanstackApi.get('/organizations/:organizationId/department-costs', {
173+
path: { organizationId: params.orgId },
174+
query: { period: selectedPeriod },
175+
}).queryOptions,
176+
staleTime: 30 * 1000,
177+
// placeholderData: keepPreviousData,
178+
// etc
179+
});
180+
```
181+
182+
or if you need it in a router `beforeLoad` / `loader`:
183+
184+
```ts
185+
import { tanstackApi } from '#api';
186+
187+
await queryClient.fetchQuery(
188+
tanstackApi.get('/:organizationId/remediation/accounting-lines/metrics', {
189+
path: { organizationId: params.orgId },
190+
}).queryOptions,
191+
);
192+
```
193+
194+
## useMutation
195+
196+
the API slightly differs as you do not need to pass any parameters initially but only when using the `mutate` method:
197+
198+
```ts
199+
// Basic mutation
200+
const mutation = useMutation(
201+
tanstackApi.mutation("post", '/authorization/organizations/:organizationId/invitations').mutationOptions
202+
);
203+
204+
// Usage:
205+
mutation.mutate({
206+
body: {
207+
emailAddress: 'user@example.com',
208+
department: 'engineering',
209+
roleName: 'admin'
210+
}
211+
});
212+
```
213+
214+
## useMutation without the tanstack api
215+
216+
If you need to make a custom mutation you could use the `api` directly:
217+
218+
```ts
219+
const { mutate: login, isPending } = useMutation({
220+
mutationFn: async (type: 'google' | 'microsoft') => {
221+
return api.post(`/authentication/${type}`, { body: { redirectUri: search.redirect } });
222+
},
223+
onSuccess: (data) => {
224+
window.location.replace(data.url);
225+
},
226+
onError: (error, type) => {
227+
console.error(error);
228+
toast({
229+
title: t(`toast.login.${type}.error`),
230+
icon: 'warning',
231+
variant: 'critical',
232+
});
233+
},
234+
});
235+
```
236+
77237
## Alternatives
78238

79239
[openapi-zod-client](https://github.com/astahmer/openapi-zod-client), which generates a

0 commit comments

Comments
 (0)