HttpClient
The HttpClient class provides a lightweight HTTP client built on the Fetch API. It supports JSON serialization, configurable base URLs, default headers, and request/response interceptors.
Import
import { HttpClient } from '@atrotos/vio'Signature
class HttpClient {
constructor(options?: HttpClientOptions)
get<T = unknown>(url: string, headers?: Record<string, string>): Promise<HttpResponse<T>>
post<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<HttpResponse<T>>
put<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<HttpResponse<T>>
delete<T = unknown>(url: string, headers?: Record<string, string>): Promise<HttpResponse<T>>
interceptors: {
request: { use(fn: RequestInterceptor): void }
response: { use(fn: ResponseInterceptor): void }
}
}Constructor
new HttpClient(options?: HttpClientOptions)HttpClientOptions
interface HttpClientOptions {
baseURL?: string
headers?: Record<string, string>
}| Property | Type | Default | Description |
|---|---|---|---|
baseURL | string | '' | Prefix prepended to all request URLs |
headers | Record<string, string> | {} | Default headers included in every request |
const client = new HttpClient({
baseURL: 'https://api.example.com',
headers: {
Authorization: 'Bearer my-token'
}
})Response Type
All HTTP methods return a Promise<HttpResponse<T>>:
interface HttpResponse<T = unknown> {
data: T
status: number
headers: Headers
}| Property | Type | Description |
|---|---|---|
data | T | Parsed response body. JSON responses are parsed automatically; other content types are returned as strings. |
status | number | HTTP status code |
headers | Headers | Response headers (standard Headers object) |
Methods
get(url, headers?)
Sends a GET request.
get<T = unknown>(url: string, headers?: Record<string, string>): Promise<HttpResponse<T>>| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Request path (appended to baseURL) |
headers | Record<string, string> | No | Additional headers for this request |
const { data, status } = await client.get<User[]>('/users')
console.log(data) // User[]post(url, body?, headers?)
Sends a POST request. The body is JSON-serialized automatically.
post<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<HttpResponse<T>>| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Request path |
body | unknown | No | Request body (will be JSON.stringify-ed) |
headers | Record<string, string> | No | Additional headers |
const { data } = await client.post<User>('/users', {
name: 'Alice',
email: '[email protected]'
})put(url, body?, headers?)
Sends a PUT request. The body is JSON-serialized automatically.
put<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<HttpResponse<T>>| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Request path |
body | unknown | No | Request body |
headers | Record<string, string> | No | Additional headers |
await client.put('/users/42', { name: 'Alice Updated' })delete(url, headers?)
Sends a DELETE request.
delete<T = unknown>(url: string, headers?: Record<string, string>): Promise<HttpResponse<T>>| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Request path |
headers | Record<string, string> | No | Additional headers |
await client.delete('/users/42')Error Handling
All methods throw an Error if the response status is not OK (i.e., response.ok is false). The error message includes the status code and status text: "HTTP 404: Not Found".
Interceptors
Interceptors allow you to transform requests before they are sent and responses before they are returned.
Request Interceptors
type RequestInterceptor = (config: RequestConfig) => RequestConfig
interface RequestConfig {
method: string
headers: Record<string, string>
body?: string
}client.interceptors.request.use((config) => {
config.headers['X-Request-ID'] = crypto.randomUUID()
return config
})Response Interceptors
type ResponseInterceptor = (response: HttpResponse) => HttpResponseclient.interceptors.response.use((response) => {
console.log(`Response ${response.status}`)
return response
})Multiple interceptors are applied in the order they are registered. Each interceptor receives the output of the previous one.
Request Flow
- Merge default headers, per-request headers, and set
Content-Type: application/json - JSON-serialize the body (if present)
- Run all request interceptors in order
- Send the request via
fetch(baseURL + url, config) - If
response.okisfalse, throw an error - Parse the response body (JSON if
Content-Typeincludesapplication/json, otherwise text) - Run all response interceptors in order
- Return the
HttpResponse
Full Example
import { HttpClient } from '@atrotos/vio'
interface Todo {
id: number
title: string
completed: boolean
}
const api = new HttpClient({
baseURL: 'https://jsonplaceholder.typicode.com',
headers: {
Accept: 'application/json'
}
})
// Add auth token to every request
api.interceptors.request.use((config) => {
const token = localStorage.getItem('auth_token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
})
// Log all responses
api.interceptors.response.use((response) => {
console.log(`[HTTP ${response.status}]`, response.data)
return response
})
// Usage
async function loadTodos() {
const { data } = await api.get<Todo[]>('/todos')
return data
}
async function createTodo(title: string) {
const { data } = await api.post<Todo>('/todos', {
title,
completed: false
})
return data
}
async function deleteTodo(id: number) {
await api.delete(`/todos/${id}`)
}