Import
import { HTTPError, isHTTPError } from "@noverax/courier"HTTPError Class
import { CourierError, type HttpResponse } from "@noverax/courier"
declare class HTTPError<TData = unknown> extends CourierError<"HTTP_ERROR"> {
readonly status: number
readonly headers: Headers
readonly data: TData
constructor(response: HttpResponse<TData>, options?: { cause?: unknown; message?: string })
}Properties
error.name // "HTTPError"
error.code // "HTTP_ERROR"
error.message // "HTTP {status}" (e.g., "HTTP 404")
error.status // HTTP status code (e.g., 404)
error.headers // Response headers (Headers object)
error.data // Parsed response body (typed as R)status— the HTTP status code.0for network errors (DNS failure, connection refused).headers— the responseHeadersobject. EmptyHeadersfor network errors.data— the parsed response body. Typed asTData(defaults tounknown).name— always"HTTPError";code— always"HTTP_ERROR".message—"HTTP {status}"(e.g.,"HTTP 404"), or, when there was no answer,"Network request failed"or"Request timed out".
isHTTPError
Type guard function to check if an error is an HTTPError:
import type { HTTPError } from "@noverax/courier"
declare function isHTTPError<TData = unknown>(error: unknown): error is HTTPError<TData>isHTTPError types the error's data
isHTTPError(error) checks what error instanceof HTTPError checks, and takes a type parameter for the error's data: isHTTPError<ErrorResponse>(error) — see Typed Error Data.
Basic Usage
import { isHTTPError } from "@noverax/courier"
try {
const user = await caller.users.getById({ id: "999" })
} catch (error) {
if (isHTTPError(error)) {
console.error(`HTTP ${error.status}:`, error.data)
}
}Typed Error Data
Pass a type parameter to isHTTPError to type the error's data:
import { isHTTPError } from "@noverax/courier"
type ErrorResponse = {
success: false
message: string
code?: string
}
try {
await caller.users.getById({ id: "999" })
} catch (error) {
if (isHTTPError<ErrorResponse>(error)) {
console.error(error.data.message) // "User not found"
console.error(error.data.code) // "USER_NOT_FOUND"
}
}Status Code Handling
import { isHTTPError } from "@noverax/courier"
try {
await caller.users.getAll()
} catch (error) {
if (isHTTPError(error)) {
switch (error.status) {
case 400: console.error("Bad request:", error.data); break
case 401: redirectToLogin(); break
case 403: showForbiddenMessage(); break
case 404: showNotFound(); break
case 429: console.warn("Rate limited, retry later"); break
default:
if (error.status >= 500) console.error("Server error:", error.data)
}
}
}Middleware-Based Error Handling
Use middleware to handle errors globally across all requests:
import { defineMiddleware } from "@noverax/courier/middleware"
import { isHTTPError } from "@noverax/courier"
const errorMiddleware = defineMiddleware("errors", "wrap", async (ctx, next) => {
try {
return await next()
} catch (error) {
if (isHTTPError(error) && error.status === 401) {
// redirect to login, refresh token, etc.
}
throw error
}
})Network Errors
Network-level errors (DNS failures, connection refused, timeouts) are converted to HTTPError with status: 0. A timeout says so: its message is "Request timed out" and error.data.code is "TIMEOUT". Through the proxy, a timeout on the server's side arrives as a 504 with code: "UPSTREAM_TIMEOUT":
import { isHTTPError } from "@noverax/courier"
try {
await caller.users.getAll()
} catch (error) {
if (isHTTPError(error) && error.status === 0) {
console.error("Network error:", error.data)
}
}Related
- Error Handling Guide — in-depth error handling patterns
- Middleware — middleware chain for error interception
- HttpClient — where HTTPError is thrown
- Types — HttpResponse and related types