Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions docs/swr-openapi/use-mutation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: useMutation
---

# {{ $frontmatter.title }}

`useMutation` is a wrapper around SWR's [useSWRMutation][swr-use-mutation] function. It provides a type-safe hook for remote mutations.

```tsx
import createClient from "openapi-fetch";
import type { paths } from "./my-openapi-3-schema"; // generated types

const client = createClient<paths>({ baseUrl: "https://my-api.com" });
const useMutation = createMutationHook(client, "my-api");

function MyComponent() {
const { trigger, data, isMutating } = useMutation("/users/{userId}", "post", {
params: {
userId: "123",
},
});

return (
<button
disabled={isMutating}
onClick={() => {
trigger({ body: { name: "New User Name" } });
}}
>
Update User Name
</button>
);
}
```

## API

### Parameters

- `key`:
- `path`: Any endpoint that supports `GET` requests.
- `init`: (_optional_) Partial fetch options for the chosen endpoint.
- `method`: HTTP method for the chosen endpoint.
- `options`: (_optional_) [SWR mutate options][swr-use-mutation-params].

### Returns

- Return of a [useSWRMutation][swr-mutation-response] including:

`data`: data for the given key returned from fetcher
`error`: error thrown by fetcher (or undefined)
`trigger(arg, options)`: a function to trigger a remote mutation
`reset`: a function to reset the state (data, error, isMutating)
`isMutating`: if there's an ongoing remote mutation

## How It Works

```ts
function useMutation(
path,
method,
config,
) {
const key = [prefix, path, method];

return useSWRMutation(
key,
async (_key, { arg }) => {
const m = method.toUpperCase();

const res = await client[m](path, arg);
if (res.error) {
throw res.error;
}
return res.data;
},
config,
);
};

```

[swr-mutate-params]: https://swr.vercel.app/docs/mutation#parameters
[swr-use-mutation]: https://swr.vercel.app/docs/mutation#useswrmutation
[swr-use-mutation-params]: https://swr.vercel.app/docs/mutation#useswrmutation-parameters
[swr-mutation-response]: https://swr.vercel.app/docs/mutation#useswrmutation-return-values
6 changes: 6 additions & 0 deletions packages/swr-openapi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# swr-openapi

## 5.5.0
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't sure if this and the version bump were meant to be done manually or if there is an automated process - I just saw the CI message about the changelog not being updated so I did it manually


### Minor Changes

- [#2552](https://github.com/openapi-ts/openapi-typescript/pull/2552) [`072543f`](https://github.com/openapi-ts/openapi-typescript/pull/2552/commits/072543fc1723b81eae2d99639d7c36bd8db94126) Thanks [@prescottprue](https://github.com/prescottprue)! - Add useMutation hook

## 5.4.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/swr-openapi/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "swr-openapi",
"description": "Generate SWR hooks from OpenAPI schemas",
"version": "5.4.2",
"version": "5.5.0",
"author": {
"name": "Hunter Tunnicliff",
"email": "hunter@tunnicliff.co"
Expand Down
1 change: 1 addition & 0 deletions packages/swr-openapi/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./immutable.js";
export * from "./infinite.js";
export * from "./mutate.js";
export * from "./mutation.js";
export * from "./query.js";
export * from "./types.js";
66 changes: 66 additions & 0 deletions packages/swr-openapi/src/mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { Client } from "openapi-fetch";
import type { HttpMethod, MediaType, PathsWithMethod } from "openapi-typescript-helpers";
import useSWRMutation, { type SWRMutationConfiguration, type SWRMutationResponse } from "swr/mutation";
import type { TypesForRequest } from "./types.js";
import { useMemo } from "react";

/**
* Produces a typed wrapper for [`useSWRMutation`](https://swr.vercel.app/docs/mutation).
*
* ```ts
* import createClient from "openapi-fetch";
* import type { paths } from "./my-openapi-3-schema"; // generated types
*
* const client = createClient<paths>({ baseUrl: "https://my-api.com" });
* const useMutation = createMutationHook(client, "my-api");
*
* function MyComponent() {
* const { trigger, data, isMutating } = useMutation("/users", "post");
*
* return (
* <button
* disabled={isMutating}
* onClick={() => {
* trigger({ body: { name: "New User" } });
* }}
* >
* Create User
* </button>
* );
* }
* ```
*/
export function createMutationHook<Paths extends {}, IMediaType extends MediaType>(
client: Client<Paths, IMediaType>,
prefix: string,
) {
return function useMutation<
Method extends Extract<HttpMethod, keyof Paths[keyof Paths]>,
Path extends PathsWithMethod<Paths, Method>,
T extends TypesForRequest<Paths, Method, Path> = TypesForRequest<Paths, Method, Path>,
Data = T["Data"],
Error = T["Error"],
Init = T["Init"],
>(
path: Path,
method: Method,
init: Init | null,
config?: SWRMutationConfiguration<Data, Error, readonly [string, Path, Init], Init>,
): SWRMutationResponse<Data, Error, readonly [string, Path, Init], Init> {
const key = useMemo(() => (init !== null ? ([prefix, path, init] as const) : null), [prefix, path, init]);

return useSWRMutation(
key,
async (_key, { arg }) => {
const m = method.toUpperCase() as Uppercase<Method>;

const res = await (client as any)[m](path, arg);
if (res.error) {
throw res.error;
}
return res.data;
},
config,
);
};
}
Loading