With Native Fetch
Two approaches: fetchExpect (one-liner helper) or the async adapter (instance-level, full control).
fetchExpect — the quick way
Section titled “fetchExpect — the quick way”fetchExpect calls fetch, parses JSON, and validates the status in one call:
import { fetchExpect } from "expect-status/fetch";
type UserResponse = | { status: 200; body: { id: string; name: string } } | { status: 404; body: { message: string } };
const user = await fetchExpect<UserResponse>( "https://api.example.com/users/1", 200,);// ^? { id: string; name: string }With headers and dispatch
Section titled “With headers and dispatch”const user = await fetchExpect<UserResponse>( "https://api.example.com/users/1", 200, { init: { headers: { Authorization: `Bearer ${token}` }, }, 404: "User not found.", "5xx": "Service unavailable.", },);type CreateUserResponse = | { status: 201; body: { id: string } } | { status: 409; body: { message: string } };
const created = await fetchExpect<CreateUserResponse>( "https://api.example.com/users", 201, { init: { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Alice" }), }, 409: "User already exists.", },);Async adapter — the instance way
Section titled “Async adapter — the instance way”For apps that use fetch everywhere, create a shared instance with an async adapter:
import { createExpectStatus, adapters } from "expect-status";
export const expectStatus = createExpectStatus({ adapter: adapters.fetch, fallbackMessage: "Request failed.", defaults: { 401: "Please sign in.", "5xx": "Service unavailable.", },});Then use it with bare fetch calls:
const user = await expectStatus(200, fetch("/api/users/1"));
const created = await expectStatus( 201, fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Alice" }), }), { 409: "User already exists.", },);Which approach to use?
Section titled “Which approach to use?”fetchExpect | Async adapter | |
|---|---|---|
| Setup | None — import and call | One-time instance config |
| Instance defaults | ❌ | ✅ (shared messages, hooks, groups) |
| Observability | Per-call only | Instance-wide onError / onSuccess |
| Best for | One-off calls, scripts | App-wide fetch usage |
SafeResult
Section titled “SafeResult”Works with both approaches:
const result = await fetchExpect<UserResponse>(url, 200, { throws: false });
if (result.ok) { renderUser(result.data);} else { showError(result.error.message);}See also
Section titled “See also”- fetchExpect API — full signature and options
- With Axios — Axios adapter details
- Custom Envelope — adapter for non-standard shapes