Skip to content

With openapi-fetch

openapi-fetch returns { data, error, response } — not a status-discriminated union. Use the adapter to normalize it.

lib/expect-status.ts
import { createExpectStatus, adapters } from "expect-status";
export const expectStatus = createExpectStatus({
adapter: adapters.openapiClient,
fallbackMessage: "Request failed.",
defaults: {
401: "Please sign in.",
"5xx": "Service unavailable.",
},
});
import createClient from "openapi-fetch";
import type { paths } from "./api/schema";
import { expectStatus } from "@/lib/expect-status";
const client = createClient<paths>({ baseUrl: "https://api.example.com" });
const user = await expectStatus(
200,
client.GET("/users/{id}", { params: { path: { id: "1" } } }),
);
const org = await expectStatus(
201,
client.POST("/orgs", { body: { name: "Acme" } }),
{
409: "Organisation already exists.",
422: "Please check your input.",
},
);
function useUser(id: string) {
return useQuery({
queryKey: ["user", id],
queryFn: () =>
expectStatus(
200,
client.GET("/users/{id}", { params: { path: { id } } }),
),
});
}
function useCreateOrg() {
return useMutation({
mutationFn: (data: { name: string }) =>
expectStatus(201, client.POST("/orgs", { body: data }), {
409: ({ message }) => ({ error: message }),
422: "Invalid input.",
}),
});
}
const result = await expectStatus(
200,
client.GET("/users/{id}", { params: { path: { id } } }),
{ throws: false },
);
if (result.ok) {
renderUser(result.data);
} else {
showError(result.error.message);
}

If you don’t want an adapter instance, wrap per-call:

import { expectStatus } from "expect-status";
const { data, error, response } = await client.GET("/users/{id}", {
params: { path: { id: "1" } },
});
const user = await expectStatus(200, {
status: response.status,
body: data ?? error,
});