Skip to content

Commit 6eb5b71

Browse files
Merge pull request #12 from speakeasy-api/chase/updates
feat: improve error handling interface + react query
2 parents 46df984 + afe16f2 commit 6eb5b71

File tree

309 files changed

+13679
-5280
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

309 files changed

+13679
-5280
lines changed

.idea/.gitignore

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.speakeasy/gen.lock

Lines changed: 85 additions & 65 deletions
Large diffs are not rendered by default.

.speakeasy/workflow.lock

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ speakeasyVersion: 1.533.0
22
sources:
33
my-source:
44
sourceNamespace: my-source
5-
sourceRevisionDigest: sha256:60981650084fdd89829a7b84dd87e31a97789af8e5af9c431e925f342e1bc19e
5+
sourceRevisionDigest: sha256:a7553f9cadf93d6dec407cf1be5ba62d2dc356c0880236f05599b421725c1871
66
sourceBlobDigest: sha256:f9444653744aa4a4ca763e60284ec246889d5345d43d6544058196709ead8a39
77
tags:
88
- latest
9-
- speakeasy-sdk-regen-1744244404
109
- 0.4.0
1110
targets:
1211
speakeasy-client-sdk-typescript:
1312
source: my-source
1413
sourceNamespace: my-source
15-
sourceRevisionDigest: sha256:60981650084fdd89829a7b84dd87e31a97789af8e5af9c431e925f342e1bc19e
14+
sourceRevisionDigest: sha256:a7553f9cadf93d6dec407cf1be5ba62d2dc356c0880236f05599b421725c1871
1615
sourceBlobDigest: sha256:f9444653744aa4a4ca763e60284ec246889d5345d43d6544058196709ead8a39
1716
codeSamplesNamespace: my-source-typescript-code-samples
18-
codeSamplesRevisionDigest: sha256:d18a7cac504b265381c2db149e634e5b489f3c747e4a4b4f9eb2e84cee2e3c55
17+
codeSamplesRevisionDigest: sha256:376dffcbce175d84d133f8db2cfe690c1c855afaceb847b61254f129a34b49cd
1918
workflow:
2019
workflowVersion: 1.0.0
2120
speakeasyVersion: latest

FUNCTIONS.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ async function run() {
5353

5454
const { value: result } = res;
5555

56-
// Handle the result
57-
console.log(result);
56+
5857
}
5958

6059
run();

REACT_QUERY.md

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
# React hooks
2+
3+
This SDK provides React hooks and utilies for making queries and mutations that
4+
can take the pain out of building front-end applications for the web or React
5+
Native.
6+
7+
They are built as a thin wrapper around [TanStack Query for React v5][rq], a
8+
powerful, asynchronous state management library. A good understanding of that
9+
library will be very helpful while using them. In addition to hooks, there are
10+
several helper functions that can be used for cache management and data fetching
11+
during server-rendering and in React Server Components.
12+
13+
## Getting started
14+
15+
To get started using React hooks, you will need to inject TanStack query and an
16+
SDK instance into your application. Typically, this will be done high up in
17+
your React app at the root or layout component. For example:
18+
19+
```tsx
20+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
21+
import { SpeakeasyCore } from "@speakeasy-api/speakeasy-client-sdk-typescript";
22+
import { SpeakeasyProvider } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query";
23+
24+
const queryClient = new QueryClient();
25+
const speakeasy = new SpeakeasyCore({
26+
security: {
27+
apiKey: "<YOUR_API_KEY_HERE>",
28+
},
29+
});
30+
31+
// Retries are handled by the underlying SDK.
32+
queryClient.setQueryDefaults(["@speakeasy-api/speakeasy-client-sdk-typescript"], { retry: false });
33+
queryClient.setMutationDefaults(["@speakeasy-api/speakeasy-client-sdk-typescript"], { retry: false });
34+
35+
export function App() {
36+
return (
37+
<QueryClientProvider client={queryClient}>
38+
<SpeakeasyProvider client={speakeasy}>
39+
{/* Your app logic starts here */}
40+
</SpeakeasyProvider>
41+
</QueryClientProvider>
42+
);
43+
}
44+
```
45+
46+
## Queries
47+
48+
Query hooks are the basic building block for fetching data. In addition to
49+
request data, they take the same options as the [`useQuery` hook][use-query]
50+
from TanStack Query.
51+
52+
[use-query]: https://tanstack.com/query/v5/docs/framework/react/reference/useQuery
53+
54+
```tsx
55+
import { useArtifactsGetBlob } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsGetBlob.js";
56+
57+
export function Example() {
58+
const { data, error, status } = useArtifactsGetBlob({
59+
organizationSlug: "<value>",
60+
workspaceSlug: "<value>",
61+
namespaceName: "<value>",
62+
digest: "<value>",
63+
});
64+
65+
// Render the UI here...
66+
}
67+
```
68+
69+
### Query timeouts and retries
70+
71+
Since the underlying SDK handles request timeouts and retries, there are a few
72+
more options provided by the query hooks to control these behaviors.
73+
74+
```tsx
75+
import { useState } from "react";
76+
import { useArtifactsGetBlob } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsGetBlob.js";
77+
78+
export function ExampleWithOptions() {
79+
const [enabled, setEnabled] = useState(true);
80+
const { data, error, status } = useArtifactsGetBlob(
81+
{
82+
organizationSlug: "<value>",
83+
workspaceSlug: "<value>",
84+
namespaceName: "<value>",
85+
digest: "<value>",
86+
},
87+
{
88+
// TanStack Query options:
89+
enabled,
90+
staleTime: 60 * 1000, // 1 minute
91+
gcTime: 5 * 60 * 1000, // 5 minutes
92+
93+
// Request options for the underlying API call:
94+
timeoutMs: 1000,
95+
retryCodes: ["5XX"],
96+
retries: {
97+
strategy: "backoff",
98+
backoff: {
99+
initialInterval: 500,
100+
maxInterval: 10 * 1000, // 10 seconds
101+
exponent: 1.5,
102+
maxElapsedTime: 60 * 1000, // 1 minute
103+
},
104+
},
105+
}
106+
);
107+
108+
// Render the UI here...
109+
}
110+
```
111+
112+
113+
## Mutations
114+
115+
Operations that can have side-effects in this SDK are exposed as mutation hooks.
116+
These can be integrated into HTML forms to submit data to the API. They also
117+
take the same options as the [`useMutation` hook][use-mutation] from TanStack
118+
Query.
119+
120+
[use-mutation]: https://tanstack.com/query/v5/docs/framework/react/reference/useMutation
121+
122+
```tsx
123+
import { useArtifactsCreateRemoteSourceMutation } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsCreateRemoteSource.js";
124+
125+
export function Example() {
126+
const { mutate, status } = useArtifactsCreateRemoteSourceMutation();
127+
128+
return (
129+
<form
130+
onSubmit={(e) => {
131+
e.preventDefault();
132+
133+
// Read form data here...
134+
135+
mutate();
136+
}}
137+
>
138+
{/* Form fields go here... */}
139+
<button type="submit" disabled={status === "pending"}>Submit</button>
140+
</form>
141+
);
142+
}
143+
```
144+
145+
### Mutation timeouts and retries
146+
147+
Since the underlying SDK handles request timeouts and retries, there are a few
148+
more options provided by the mutation hooks to control these behaviors.
149+
150+
```tsx
151+
import { useArtifactsCreateRemoteSourceMutation } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsCreateRemoteSource.js";
152+
153+
export function ExampleWithOptions() {
154+
const { mutate, status } = useArtifactsCreateRemoteSourceMutation({
155+
// TanStack Query options:
156+
networkMode: "online",
157+
gcTime: 5 * 60 * 1000, // 5 minutes
158+
159+
// Request options for the underlying API call:
160+
timeoutMs: 1000,
161+
retryCodes: ["5XX"],
162+
retries: {
163+
strategy: "backoff",
164+
backoff: {
165+
initialInterval: 500,
166+
maxInterval: 10 * 1000, // 10 seconds
167+
exponent: 1.5,
168+
maxElapsedTime: 60 * 1000, // 1 minute
169+
},
170+
},
171+
});
172+
173+
// Render the UI here...
174+
}
175+
```
176+
177+
178+
## Cache invalidation
179+
180+
In many instances, triggering a mutation hook requires invalidating specific
181+
query data currently residing in the TanStack Query's cache. Alongside every
182+
query hook there are two functions that help invalidate cached data:
183+
184+
```tsx
185+
import { useQueryClient } from "@tanstack/react-query";
186+
import { invalidateArtifactsGetBlob, invalidateAllArtifactsGetBlob } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsGetBlob.js";
187+
// Replace this with a real mutation
188+
import { useExampleMutation } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/example.js";
189+
190+
export function Example() {
191+
const { queryClient } = useQueryClient();
192+
const { mutate, status } = useExampleMutation();
193+
194+
return (
195+
<form
196+
onSubmit={(e) => {
197+
e.preventDefault();
198+
199+
const formData = new FormData(e.target);
200+
201+
mutate(formData, {
202+
onSuccess: () => {
203+
// Invalidate a single cache entry:
204+
invalidateArtifactsGetBlob(queryClient, /* ... arguments ... */);
205+
// OR, invalidate all cache entries for the query targets:
206+
invalidateAllArtifactsGetBlob(queryClient);
207+
},
208+
});
209+
}}
210+
>
211+
{/* Form fields go here... */}
212+
213+
<button type="submit" disabled={status === "pending"}>Submit</button>
214+
</form>
215+
);
216+
}
217+
```
218+
219+
220+
## Integration with React Suspense
221+
222+
TanStack Query predates React Suspense and out of the box it does a great job at
223+
exposing the lifecycle of asynchronous tasks. However, if you are already using
224+
Suspense in your app, the default hooks will not trigger suspense boundaries.
225+
This is why the library and, by extension, this SDK also provide equivalent
226+
hooks that integrate neatly with React Suspense.
227+
228+
```tsx
229+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
230+
import { ErrorBoundary } from "react-error-boundary";
231+
232+
import { SpeakeasyCore } from "@speakeasy-api/speakeasy-client-sdk-typescript";
233+
import { SpeakeasyProvider } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query";
234+
import { useArtifactsGetBlobSuspense } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsGetBlob.js";
235+
236+
const queryClient = new QueryClient();
237+
const speakeasy = new SpeakeasyCore({
238+
security: {
239+
apiKey: "<YOUR_API_KEY_HERE>",
240+
},
241+
});
242+
243+
export function App() {
244+
return (
245+
<QueryClientProvider client={queryClient}>
246+
<SpeakeasyProvider client={speakeasy}>
247+
<QueryErrorResetBoundary>
248+
{({ reset }) => (
249+
<ErrorBoundary
250+
fallbackRender={({ error, resetErrorBoundary }) => (
251+
<div>
252+
There was an error!{' '}
253+
<Button onClick={() => resetErrorBoundary()}>Try again</Button>
254+
<pre>{error.message}</pre>
255+
</div>
256+
)}
257+
onReset={reset}
258+
>
259+
<React.Suspense fallback={<h1>Loading...</h1>}>
260+
<Example />
261+
</React.Suspense>
262+
</ErrorBoundary>
263+
)}
264+
</QueryErrorResetBoundary>
265+
</SpeakeasyProvider>
266+
</QueryClientProvider>
267+
);
268+
}
269+
270+
function Example() {
271+
const { data } = useArtifactsGetBlobSuspense({
272+
organizationSlug: "<value>",
273+
workspaceSlug: "<value>",
274+
namespaceName: "<value>",
275+
digest: "<value>",
276+
});
277+
278+
// Render the UI here...
279+
}
280+
```
281+
282+
283+
## Server-rendering and React Server Components
284+
285+
Query hooks are also side-loaded with prefetch helper functions. These functions
286+
can be used to fetch data from the API during server-rendering and in React
287+
Server Components so that it can be available immediately on page load to any
288+
components that use the corresponding hooks:
289+
```tsx
290+
import {
291+
dehydrate,
292+
HydrationBoundary,
293+
QueryClient,
294+
} from "@tanstack/react-query";
295+
import { SpeakeasyCore } from "@speakeasy-api/speakeasy-client-sdk-typescript";
296+
import { prefetchArtifactsGetBlob } from "@speakeasy-api/speakeasy-client-sdk-typescript/react-query/artifactsGetBlob.js";
297+
298+
export default async function Page() {
299+
const queryClient = new QueryClient();
300+
const speakeasy = new SpeakeasyCore({
301+
security: {
302+
apiKey: "<YOUR_API_KEY_HERE>",
303+
},
304+
});
305+
306+
await prefetchArtifactsGetBlob(queryClient, speakeasy, {
307+
organizationSlug: "<value>",
308+
workspaceSlug: "<value>",
309+
namespaceName: "<value>",
310+
digest: "<value>",
311+
});
312+
313+
return (
314+
// HydrationBoundary is a Client Component, so hydration will happen there.
315+
<HydrationBoundary state={dehydrate(queryClient)}>
316+
{/* Client components under this point will also have data on page load. */}
317+
</HydrationBoundary>
318+
);
319+
}
320+
```
321+
322+
323+
[rq]: https://tanstack.com/query/v5/docs/framework/react/overview

0 commit comments

Comments
 (0)