Skip to content

With Axios

Axios responses have { status, data } instead of { status, body }. Use the adapter option to normalize them at the instance level.

import axios from "axios";
import { createExpectStatus, adapters } from "expect-status";
const api = axios.create({
baseURL: "https://api.example.com",
validateStatus: () => true, // don't throw on non-2xx
});
const expectStatus = createExpectStatus({
adapter: adapters.axios,
fallbackMessage: "Request failed.",
defaults: {
401: "Please sign in.",
403: "You do not have permission.",
"5xx": "Service unavailable. Please try again.",
},
onError: (err, response) => {
Sentry.captureException(err, { extra: { status: response.status } });
},
});
// No manual wrapping needed — adapter handles it
const org = await expectStatus(201, api.post("/orgs", data));

Tip: Pass validateStatus: () => true so Axios doesn’t throw on non-2xx statuses — let expectStatus handle them instead.

const org = await expectStatus(201, api.post("/orgs", data), {
409: (body) => redirect(`/org/${body.organisationId}`),
422: "Please check your input.",
"5xx": "Service unavailable.",
});
function useCreateOrganisation() {
return useMutation({
mutationFn: async (data: CreateOrgInput) =>
expectStatus(201, api.post("/orgs", data), {
409: "Organisation already exists.",
}),
});
}
const result = await expectStatus(200, api.get("/items/1"), {
throws: false,
});
if (result.ok) {
console.log(result.data);
} else {
console.error(result.error.message, result.status);
}

If you only need expect-status for a few calls, flatten manually:

import { expectStatus } from "expect-status";
const res = await api.get("/items/1");
const item = await expectStatus(200, { status: res.status, body: res.data });

adapters.axios is just (res) => ({ status: res.status, body: res.data }) — a built-in preset so you don’t have to look it up.