Error Handling
Error Object Shape
When a request returns a non-2xx status, endpoint-fetcher throws:
{
status: number; // HTTP status code (404, 500, …)
statusText: string; // HTTP status text ("Not Found", …)
error: TError; // Parsed response body, typed by your TError generic
}Typing Errors with TError
Pass your expected error shape as the third generic parameter to any endpoint helper:
type ApiError = { message: string; code: string };
const api = createApiClient({
createUser: post<CreateUserInput, User, ApiError>('/users'),
}, { baseUrl: 'https://api.example.com' });
try {
await api.createUser({ name: 'Jane', email: 'bad-email' });
} catch (err: unknown) {
const error = err as { status: number; statusText: string; error: ApiError };
console.log(error.status); // 400
console.log(error.error.code); // 'VALIDATION_ERROR'
console.log(error.error.message); // 'Invalid email'
}TypeScript doesn’t enforce types in
catchblocks — you must useasto get typed access.
Status-Based Handling
try {
await api.createUser(data);
} catch (err: unknown) {
const error = err as { status: number; error: ApiError };
if (error.status === 400) {
console.error('Validation error:', error.error.message);
} else if (error.status === 401) {
window.location.href = '/login';
} else if (error.status >= 500) {
console.error('Server error — try again later');
} else {
throw err;
}
}Global Error Handling
Use the onError hook to handle or log all errors in one place:
const api = createApiClient(endpoints, {
baseUrl: 'https://api.example.com',
hooks: {
onError: async (error) => {
// Sentry.captureException(error);
console.error('API error:', error);
},
},
});Type Guard
A type guard avoids repeated assertions in catch blocks:
type ApiError = { message: string; code: string };
function isApiError(err: unknown): err is { status: number; statusText: string; error: ApiError } {
return typeof err === 'object' && err !== null && 'status' in err && 'error' in err;
}
try {
await api.users.getById({ id: '123' });
} catch (err) {
if (isApiError(err)) {
console.error(`${err.status}: ${err.error.message}`);
} else {
throw err; // network error or unexpected
}
}Different Error Types Per Endpoint
Each endpoint can have its own TError:
type ValidationError = { message: string; errors: Array<{ field: string; message: string }> };
type NotFoundError = { message: string; resourceId: string };
type AuthError = { message: string; code: 'UNAUTHORIZED' | 'FORBIDDEN' };
const api = createApiClient({
createUser: post<CreateUserInput, User, ValidationError>('/users'),
getUser: get<{ id: string }, User, NotFoundError>((input) => `/users/${input.id}`),
login: post<LoginInput, AuthTokens, AuthError>('/auth/login'),
}, { baseUrl: 'https://api.example.com' });