Skip to content

Commit c25360e

Browse files
committed
Update README
1 parent 0c58131 commit c25360e

File tree

1 file changed

+180
-48
lines changed

1 file changed

+180
-48
lines changed

README.md

Lines changed: 180 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,91 +16,223 @@
1616
## Installation
1717

1818
```sh
19-
npm install swr openapi-fetch swr-openapi
20-
npm install --save-dev openapi-typescript
19+
npm install swr-openapi swr openapi-fetch
20+
npm install --save-dev openapi-typescript typescript
2121
```
2222

2323
## Setup
2424

25-
For each Open API schema you want to use, run the following command to transform each schema into TypeScript types:
25+
Follow [openapi-typescript](https://openapi-ts.pages.dev/) directions to generate TypeScript definitions for each service being used.
26+
27+
Here is an example of types being generated for a service via the command line:
2628

2729
```sh
2830
npx openapi-typescript "https://sandwiches.example/openapi/json" --output ./types/sandwich-schema.ts
2931
```
3032

31-
Once you have types for your API saved, create an API client:
33+
Then, create an [openapi-fetch](https://openapi-ts.pages.dev/openapi-fetch/) client and initialize [swr](https://swr.vercel.app/) hooks for the API:
3234

35+
<!-- prettier-ignore -->
3336
```ts
3437
// sandwich-api.ts
35-
import type * as SandwichSchema from "./types/sandwich-schema";
38+
import { createClient } from "openapi-fetch";
39+
import { createHooks } from "swr-openapi";
40+
import type * as SandwichesSchema from "./types/sandwich-schema";
3641

37-
export const sandwichAPI = createClient<SandwichSchema.paths>({
42+
export const sandwichesApi = createClient<SandwichesSchema.paths>({
3843
baseUrl: "https://sandwiches.example",
3944
});
45+
46+
export const {
47+
use: useSandwiches,
48+
useInfinite: useSandwichesInfinite,
49+
} = createHooks<SandwichesSchema.paths>(sandwichesApi, "sandwich-api");
50+
```
51+
52+
## Usage
53+
54+
```tsx
55+
import { useSandwiches } from "./sandwich-api";
56+
57+
export function MySandwiches() {
58+
// Fetch a single sandwich (uses useSWR)
59+
const { data: sandwiches } = useSandwiches("/sandwiches/{sandwichId}", {
60+
params: {
61+
path: {
62+
sandwichId: "sandwich-123",
63+
},
64+
},
65+
});
66+
67+
// Fetch multiple pages of sandwiches (uses useSWRInfinite)
68+
const {
69+
data: pages,
70+
size,
71+
setSize,
72+
} = useSandwichesInfinite("/sandwiches", (index, previous) => {
73+
if (!previous.hasMore) {
74+
return null;
75+
}
76+
77+
return {
78+
params: {
79+
query: {
80+
limit: 25,
81+
offset: 25 * index,
82+
},
83+
},
84+
};
85+
});
86+
}
4087
```
4188

42-
Now, initialize a hook factory for that API:
89+
## API Reference
4390

91+
### `createHooks<Paths>(api, keyPrefix)`
92+
93+
- Parameters:
94+
- `<Paths>`: An OpenAPI schema paths object generated by openapi-typescript.
95+
- `api`: An openapi-fetch client.
96+
- `keyPrefix`: A string to differentiate this API from others. This helps avoid swr cache collisions when using multiple APIs that may have identical paths.
97+
- Returns:
98+
- [`use`](#usepath-options-swrconfig): A wrapper over [`useSWR`][swr-api] bound to the given api.
99+
- [`useInfinite`](#useinfinitepath-getoptionsfn-swrconfig): A wrapper over [`useSWRInfinite`][swr-infinite-api] bound to the given api.
100+
101+
Depending on your project preferences, there are different ways to export the return value of `createHooks`. Here are two examples:
102+
103+
<details>
104+
<summary><b>Option 1: Destructure the return value and rename the destructured properties</b></summary>
105+
106+
<!-- prettier-ignore -->
44107
```ts
45108
// sandwich-api.ts
46-
import { makeHookFactory } from "swr-openapi";
47-
import type * as SandwichSchema from "./types/sandwich-schema";
109+
export const {
110+
use: useSandwiches,
111+
useInfinite: useSandwichesInfinite
112+
} = createHooks<SandwichesSchema.paths>(sandwichesApi, "sandwich-api");
113+
```
48114

49-
export const sandwichAPI = createClient<SandwichSchema.paths>({
50-
baseUrl: "https://sandwiches.example",
51-
});
115+
```ts
116+
// some-component.tsx
117+
import { useSandwiches } from "./sandwich-api";
52118

53-
// 👇👇👇
54-
const makeHook = makeHookFactory<SandwichSchema.paths>(sandwichAPI);
119+
export function SomeComponent() {
120+
const { data, error, isLoading } = useSandwiches("/sandwiches/{sandwichId}", {
121+
params: {
122+
path: {
123+
sandwichId: "sandwich-123",
124+
},
125+
},
126+
});
127+
}
55128
```
56129

57-
> **Info**
58-
> When working with multiple APIs, you can customize the name of each hook factory to suite your application:
59-
>
60-
> ```ts
61-
> const fooAPI = createClient(...);
62-
> const makeFooHook = makeHookFactory(fooAPI);
63-
>
64-
> const barAPI = createClient(...);
65-
> const makeBarHook = makeHookFactory(barAPI);
66-
> ```
130+
</details>
67131

68-
With setup now out of the way, you can define the actual hooks used by your application:
132+
<details>
133+
<summary><b>Option 2: Don't destructure the return value</b></summary>
69134

70135
```ts
71136
// sandwich-api.ts
72-
import { makeHookFactory } from "swr-openapi";
73-
import type * as SandwichSchema from "./types/sandwich-schema";
137+
export const sandwiches = createHooks<SandwichesSchema.paths>(
138+
sandwichesApi,
139+
"sandwich-api",
140+
);
141+
```
74142

75-
export const sandwichAPI = createClient<SandwichSchema.paths>({
76-
baseUrl: "https://sandwiches.example",
77-
});
143+
```ts
144+
// some-component.tsx
145+
import { sandwiches } from "./sandwich-api";
146+
147+
export function SomeComponent() {
148+
const { data, error, isLoading } = sandwiches.use(
149+
"/sandwiches/{sandwichId}",
150+
{
151+
params: {
152+
path: {
153+
sandwichId: "sandwich-123",
154+
},
155+
},
156+
},
157+
);
158+
}
159+
```
78160

79-
const makeHook = makeHookFactory<SandwichSchema.paths>(sandwichAPI);
161+
</details>
80162

81-
// 👇👇👇
82-
export const useSandwichesForUser = makeHook("/user/{userId}/sandwiches");
83-
export const useSandwiches = makeHook("/sandwiches");
84-
```
163+
### `use(path, options, swrConfig)`
85164

86-
Now, you can call the hooks elsewhere in your application:
165+
```ts
166+
function use(
167+
path: Path,
168+
options: Options | null,
169+
swrConfig?: Config,
170+
): SWRResponse;
171+
```
87172

88-
```tsx
89-
import { useSandwiches, useSandwichesForUser } from "./sandwich-api";
173+
- Parameters:
174+
- `path`: The GET endpoint to request.
175+
- `options`: Either
176+
1. An openapi-fetch [`FetchOptions`](https://openapi-ts.pages.dev/openapi-fetch/api#fetch-options) object for the given path.
177+
2. `null` to support [conditional fetching](https://swr.vercel.app/docs/conditional-fetching).
178+
- `swrConfig` (optional): [Configuration options](https://swr.vercel.app/docs/api#options) for `useSWR`.
179+
- Returns:
180+
- A [`useSWR` response](https://swr.vercel.app/docs/api#return-values).
90181

91-
export function UserSandwiches() {
92-
const { data: sandwiches } = useSandwiches({
182+
```ts
183+
const { data, error, isLoading, mutate, revalidate } = use(
184+
"/sandwiches/{sandwichId}",
185+
{
93186
params: {
94-
query: { limit: 10 },
187+
path: {
188+
sandwichId: "sandwich-123",
189+
},
95190
},
96-
});
191+
},
192+
);
193+
```
194+
195+
### `useInfinite(path, getOptionsFn, swrConfig)`
196+
197+
```ts
198+
function useInfinite(
199+
path: Path,
200+
getOptionsFn: SWRInfiniteKeyLoader<Data, Options | null>,
201+
swrConfig?: Config,
202+
): SWRInfiniteResponse;
203+
```
204+
205+
- Parameters:
206+
- `path`: The GET endpoint to request.
207+
- `getOptionsFn`: An swr [`getKey` function](https://swr.vercel.app/docs/pagination#parameters) that accepts the index and the previous page data, returning either an openapi-fetch [`FetchOptions`](https://openapi-ts.pages.dev/openapi-fetch/api#fetch-options) object for loading the next page or `null`, once there are no more pages.
208+
- `swrConfig` (optional): [Configuration options](https://swr.vercel.app/docs/pagination#parameters) for `useSWRInfinite`.
209+
- Returns:
210+
- A [`useSWRInfinite` response](https://swr.vercel.app/docs/pagination#return-values).
97211

98-
const { data: userSandwiches } = useSandwichesForUser({
212+
```ts
213+
const {
214+
data: sandwichPages,
215+
error,
216+
isLoading,
217+
isValidating,
218+
mutate,
219+
size,
220+
setSize,
221+
} = useInfinite("/sandwiches", (index, previousPage) => {
222+
if (!previousPage.hasMore) {
223+
return null;
224+
}
225+
226+
return {
99227
params: {
100-
path: { userId: "user-123" },
228+
query: {
229+
limit: 25,
230+
offset: 25 * index,
231+
},
101232
},
102-
});
103-
104-
// ...
105-
}
233+
};
234+
});
106235
```
236+
237+
[swr-api]: https://swr.vercel.app/docs/api
238+
[swr-infinite-api]: https://swr.vercel.app/docs/pagination#useswrinfinite

0 commit comments

Comments
 (0)