Skip to content

createExpectStatus

createExpectStatus creates a custom expectStatus instance with project-wide configuration.

import { createExpectStatus } from "expect-status";
class RequestError extends Error {}
export const expectStatus = createExpectStatus({
errorFactory: (message) => new RequestError(message),
fallbackMessage: "Something went wrong. Please try again.",
groups: {
auth: [401, 403],
retryable: [408, 429, 503],
},
defaults: {
auth: "Please sign in or check your permissions.",
"5xx": "Service is temporarily unavailable.",
},
onError: (err, response) => {
Sentry.captureException(err, {
extra: { status: response.status, body: response.body },
});
},
});
createExpectStatus<StatusField, BodyField>(
options: ExpectStatusOptions<StatusField, BodyField>
): ExpectStatusFn<StatusField, BodyField>;

Custom error class or factory function for creating errors.

class RequestError extends Error {
constructor(
message: string,
public status: number,
public body: unknown,
) {
super(message);
}
}
const expectStatus = createExpectStatus({
errorFactory: (message, response) =>
new RequestError(message, response.status, response.body),
});

Optional response normalizer. When provided, the raw response is passed through the adapter before status/body are read. Replaces statusField/bodyField for non-standard shapes.

// Axios
const expectStatus = createExpectStatus({
adapter: (res) => ({ status: res.status, body: res.data }),
});
// Custom envelope
const expectStatus = createExpectStatus({
adapter: (res) => ({ status: res.meta.httpStatus, body: res.result.data }),
});
// Async adapter (e.g. native fetch)
const expectStatus = createExpectStatus({
adapter: async (res) => ({ status: res.status, body: await res.json() }),
});

When adapter is provided, statusField and bodyField are ignored.

Custom message extraction function from response bodies.

const expectStatus = createExpectStatus({
extractMessage: (body) => {
if (typeof body === "object" && body !== null) {
return (body as { detail?: string }).detail;
}
return undefined;
},
});

Default message when no other message source matches.

const expectStatus = createExpectStatus({
fallbackMessage: "Something went wrong. Please try again.",
});

Custom named status groups. Usable as expected status arguments or dispatch keys.

const expectStatus = createExpectStatus({
groups: {
auth: [401, 403],
retryable: [408, 429, 500, 502, 503, 504],
cacheable: [200, 203, 300, 301],
},
});
// Use as expected status
await expectStatus("auth", response);
// Use in dispatch
await expectStatus(200, response, {
auth: "Please sign in.",
retryable: (body) => retryQueue.add(body),
});

Instance-wide default flat dispatch entries. Per-call dispatch shadows these.

const expectStatus = createExpectStatus({
defaults: {
401: "Please sign in.",
403: "You do not have permission.",
"5xx": "Service is temporarily unavailable.",
429: (body) => {
// Global handler for rate limiting
throw new Error("Too many requests. Please slow down.");
},
},
});

Defaults use the same flat dispatch convention as per-call dispatch.

Instance-wide observability hook for errors.

const expectStatus = createExpectStatus({
onError: (err, response) => {
Sentry.captureException(err, {
extra: { status: response.status, body: response.body },
});
},
});

Instance-wide observability hook for success.

const expectStatus = createExpectStatus({
onSuccess: (response) => {
analytics.track("api_success", { status: response.status });
},
});

Custom field name for the status discriminator. Defaults to 'status'.

const expectCode = createExpectStatus({
statusField: "code",
bodyField: "payload",
});
type Response =
| { code: 200; payload: { id: string } }
| { code: 404; payload: { message: string } };
const body = await expectCode(200, response);

Custom field name for the body. Defaults to 'body'.

const expectStatus = createExpectStatus({
bodyField: "data",
});
type Response =
| { status: 200; data: { id: string } }
| { status: 404; data: { message: string } };

Returns a configured expectStatus function with the same signature as the default instance.

Per-call dispatch entries shadow instance defaults:

const expectStatus = createExpectStatus({
defaults: {
404: "Not found (default)",
},
});
// Per-call entry takes precedence
await expectStatus(200, response, {
404: "Custom not found message",
});