-
Lightweight HTTP client with interceptors, caching, and reactive data fetching.
-
install
hmmfirst.hmm i @minejs/http
-
import { HttpClient, http, configureHttp, useQuery, useMutation, retry, createAbortController } from '@minejs/http'
-
import { http } from '@minejs/http' // GET request const response = await http.get('/api/users') console.log(response.data) // POST request const created = await http.post('/api/users', { name: 'John' }) console.log(created.data) // PUT, PATCH, DELETE await http.put('/api/users/1', { name: 'Jane' }) await http.patch('/api/users/1', { age: 30 }) await http.delete('/api/users/1')
-
import { configureHttp, http } from '@minejs/http' // Configure global HTTP client configureHttp({ baseURL: 'https://api.example.com', headers: { 'Authorization': 'Bearer token' }, timeout: 5000 }) // Or create custom instance const client = new HttpClient({ baseURL: 'https://api.example.com' }) const response = await client.get('/users')
-
import { http } from '@minejs/http' // Add request interceptor http.interceptRequest({ onFulfilled: (config) => { config.headers = { ...config.headers, 'X-Request-ID': crypto.randomUUID() } return config } }) // Add response interceptor http.interceptResponse({ onFulfilled: (response) => { console.log('Response received:', response.status) return response }, onRejected: (error) => { console.error('Request failed:', error.message) throw error } })
-
import { useQuery } from '@minejs/http' const { data, error, isLoading, refetch } = useQuery( 'users', () => http.get('/api/users'), { enabled: true, refetchOnWindowFocus: true, refetchInterval: 30000 // Refetch every 30s } ) console.log(data()) // Signal<User[] | null> console.log(isLoading()) // Signal<boolean> console.log(error()) // Signal<HttpError | null>
-
import { useMutation } from '@minejs/http' const { mutate, data, error, isLoading, reset } = useMutation( (user) => http.post('/api/users', user), { onSuccess: (data) => { console.log('User created:', data) }, onError: (error) => { console.error('Failed to create user:', error) } } ) // Create user await mutate({ name: 'John', email: 'john@example.com' }) // Reset mutation state reset()
-
import { retry } from '@minejs/http' const response = await retry( () => http.get('/api/data'), { retries : 3, retryDelay : (attempt) => Math.min(1000 * 2 ** attempt, 30000), retryCondition : (error) => error.status >= 500 } )
-
import { createAbortController } from '@minejs/http' // Create abort controller with timeout const controller = createAbortController(5000) try { const response = await http.get('/api/long-running', { signal: controller.signal }) } catch (error) { if (error.name === 'AbortError') { console.log('Request was cancelled') } }
-
-
-
-
Core HTTP client class for making requests.
class HttpClient { constructor(config?: Partial<RequestConfig>) // Configuration setConfig(config: Partial<RequestConfig>): void // Interceptors interceptRequest(interceptor: Interceptor<RequestConfig>): () => void interceptResponse(interceptor: Interceptor<Response>): () => void // Request methods request<T>(config: RequestConfig): Promise<Response<T>> get<T>(url: string, config?: Partial<RequestConfig>): Promise<Response<T>> post<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<Response<T>> put<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<Response<T>> patch<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<Response<T>> delete<T>(url: string, config?: Partial<RequestConfig>): Promise<Response<T>> }
-
Pre-configured global HTTP client instance.
import { http } from '@minejs/http' // Use directly await http.get('/api/users') await http.post('/api/users', { name: 'John' })
-
Configure global HTTP client with default settings.
configureHttp({ baseURL: 'https://api.example.com', headers: { 'Authorization': 'Bearer token' }, timeout: 5000, withCredentials: true })
-
useQuery<T>(queryKey: string | string[], queryFn: () => Promise<Response<T>>, options?: Partial<QueryOptions<T>>): QueryResult<T>Create a reactive query with automatic caching and refetching.
interface QueryResult<T> { data: Signal<T | null> error: Signal<HttpError | null> isLoading: Signal<boolean> isError: Signal<boolean> isSuccess: Signal<boolean> refetch: () => Promise<void> } interface QueryOptions<T> { enabled?: boolean | Signal<boolean> refetchOnWindowFocus?: boolean refetchInterval?: number staleTime?: number cacheTime?: number retry?: RetryConfig onSuccess?: (data: T) => void onError?: (error: HttpError) => void } const { data, isLoading, error, refetch } = useQuery( 'users', () => http.get<User[]>('/api/users'), { refetchInterval: 30000 } )
-
useMutation<T, V>(mutationFn: (variables: V) => Promise<Response<T>>, options?: MutationOptions<T, V>): MutationResult<T, V>Create a reactive mutation for create/update/delete operations.
interface MutationResult<T, V> { data: Signal<T | null> error: Signal<HttpError | null> isLoading: Signal<boolean> mutate: (variables: V) => Promise<T> reset: () => void } interface MutationOptions<T, V> { onSuccess?: (data: T, variables: V) => void onError?: (error: HttpError, variables: V) => void onMutate?: (variables: V) => void } const { mutate, data, isLoading } = useMutation( (user) => http.post<User>('/api/users', user), { onSuccess: (user) => console.log('Created:', user) } ) await mutate({ name: 'John', email: 'john@example.com' })
-
Retry a promise-returning function with exponential backoff.
interface RetryConfig { retries?: number // Default: 3 retryDelay?: number | ((attempt: number) => number) retryCondition?: (error: HttpError) => boolean } const data = await retry( () => http.get('/api/data'), { retries: 5, retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000), retryCondition: (error) => error.status >= 500 } )
-
Create an AbortController with optional timeout.
// Without timeout const controller = createAbortController() // With 5 second timeout const controller = createAbortController(5000) // Use with request await http.get('/api/data', { signal: controller.signal }) // Manually abort controller.abort()
-
Configuration object for HTTP requests.
interface RequestConfig { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' url: string params?: Record<string, any> // Query parameters data?: any // Request body headers?: Record<string, string> // HTTP headers timeout?: number // Request timeout in ms baseURL?: string // Base URL prepended to url withCredentials?: boolean // Include credentials in request responseType?: 'json' | 'text' | 'blob' | 'arraybuffer' signal?: AbortSignal // Abort signal for cancellation onUploadProgress?: (progress: ProgressEvent) => void onDownloadProgress?: (progress: ProgressEvent) => void }
-
HTTP response object.
interface Response<T = any> { data: T // Response body status: number // HTTP status code statusText: string // HTTP status text headers: Headers // Response headers config: RequestConfig // Original request config }
-
HTTP error object.
interface HttpError extends Error { config: RequestConfig // Request config that caused the error response?: Response // Response from server status?: number // HTTP status code }
-
Request/response interceptor configuration.
interface Interceptor<T> { onFulfilled?: (value: T) => T | Promise<T> onRejected?: (error: any) => any } // Request interceptor http.interceptRequest({ onFulfilled: (config) => { config.headers = { ...config.headers, 'X-Custom': 'value' } return config }, onRejected: (error) => { console.error('Request error:', error) throw error } }) // Response interceptor http.interceptResponse({ onFulfilled: (response) => { console.log('Success:', response.status) return response }, onRejected: (error) => { if (error.status === 401) { // Handle auth error } throw error } })
-
-
-
import { useQuery } from '@minejs/http' import { computed } from '@minejs/signals' // Fetch users const { data: users, isLoading, error } = useQuery( 'users', () => http.get<User[]>('/api/users'), { refetchInterval: 30000 } ) // Transform data const userCount = computed(() => users()?.length ?? 0) const adminUsers = computed(() => users()?.filter(u => u.role === 'admin') ?? [] )
-
import { useMutation } from '@minejs/http' interface CreateUserInput { name: string email: string password: string } const { mutate: createUser, isLoading, error } = useMutation( (input: CreateUserInput) => http.post<User>('/api/users', input), { onSuccess: (user) => { console.log('User created:', user) // Refetch user list users.refetch() }, onError: (error) => { console.error('Failed to create user:', error.message) } } ) // Create user const handleCreate = async (formData: CreateUserInput) => { await createUser(formData) }
-
import { http, configureHttp } from '@minejs/http' // Setup global config configureHttp({ baseURL: 'https://api.example.com', headers: { 'Content-Type': 'application/json' } }) // Add auth header to all requests http.interceptRequest({ onFulfilled: (config) => { const token = localStorage.getItem('auth_token') if (token) { config.headers = { ...config.headers, 'Authorization': `Bearer ${token}` } } return config } }) // Handle auth errors http.interceptResponse({ onRejected: (error) => { if (error.status === 401) { localStorage.removeItem('auth_token') window.location.href = '/login' } throw error } }) // Now all requests have auth header automatically const users = await http.get('/users') const posts = await http.get('/posts')
-
import { retry, http } from '@minejs/http' // Retry with exponential backoff const data = await retry( () => http.get('/api/data'), { retries: 5, retryDelay: (attempt) => { // 1s, 2s, 4s, 8s, 16s return Math.min(1000 * Math.pow(2, attempt), 30000) }, retryCondition: (error) => { // Only retry on server errors or timeout return error.status >= 500 || !error.status } } )
-
import { http, createAbortController } from '@minejs/http' // Auto timeout after 5 seconds try { const response = await http.get('/api/long-running', { signal: createAbortController(5000).signal }) } catch (error) { if (error instanceof Error && error.name === 'AbortError') { console.log('Request timed out') } } // Manual cancellation const controller = createAbortController() const promise = http.get('/api/stream', { signal: controller.signal }) // Cancel after 10 seconds setTimeout(() => controller.abort(), 10000) try { const response = await promise } catch (error) { if (error instanceof Error && error.name === 'AbortError') { console.log('Request was cancelled') } }
-
import { useMutation } from '@minejs/http' import { signal } from '@minejs/signals' interface FormData { email: string password: string } const formData = signal<FormData>({ email: '', password: '' }) const { mutate: login, isLoading, error } = useMutation( (data: FormData) => http.post<{ token: string }>('/api/login', data), { onSuccess: (response) => { localStorage.setItem('auth_token', response.token) window.location.href = '/dashboard' }, onError: (error) => { console.error('Login failed:', error.message) } } ) const handleSubmit = async (e: Event) => { e.preventDefault() await login(formData()) }
-
import { useQuery } from '@minejs/http' // Refetch data every 5 seconds const { data: stats, isLoading } = useQuery( 'stats', () => http.get('/api/stats'), { refetchInterval: 5000, refetchOnWindowFocus: false } ) // Display updating stats console.log('Current stats:', stats()) console.log('Loading:', isLoading())
-

