Basic Usage
The library provides a simple and intuitive API for making HTTP requests. You can use the default reqo instance or create custom clients for different configurations, see more in the Instances.
Making Requests
import { reqo } from '@outloud/reqo'
// Get response with data
const response = await reqo.request({
url: 'https://api.example.com/users',
params: { limit: 10 }
})
console.log(response.data)
// Using method shortcuts
const users = await reqo.get('https://api.example.com/users', { limit: 10 })
console.log(users.data)
// Get data directly using $ prefix
const usersData = await reqo.$get('/users')
console.log(usersData)
// Type the response
interface User {
id: number
name: string
email: string
}
const typedData = await reqo.$get<User[]>('/users')
console.log(typedData) // User[]
Options
All request methods accept an options object:
const data = await reqo.request({
// Request URL
url: 'https://api.example.com/data',
// Query parameters
params: { q: 'search' },
// HTTP method
method: 'POST',
// Custom headers
headers: {
'Authorization': 'Bearer token',
'X-Custom-Header': 'value'
},
// Request body
data: { key: 'value' },
// Timeout in milliseconds
timeout: 5000,
// Retry configuration
retry: {
limit: 3,
delay: (count) => count * 1000
},
// Response type
responseType: 'json',
// Abort signal for cancellation
signal: controller.signal,
// Redirect behavior
redirect: 'follow',
// Credentials
credentials: 'include',
// Mode
mode: 'cors'
})
Method shortcuts
All HTTP methods have corresponding shortcuts and $ variants for direct data access.
GET
GET accepts parameters in following order: url, params, options:
const response = await reqo.get('/endpoint', { param1: 'value1' }, {
timeout: 3000
})
// data is the same as response.data
const data = await reqo.$get('/endpoint', { param1: 'value1' }, {
timeout: 3000
})
HEAD
HEAD accepts parameters in following order: url, params, options:
const response = await reqo.head('/endpoint')
// $ variant
const data = await reqo.$head('/endpoint')
POST
POST accepts parameters in following order: url, data, options:
const response = await reqo.post('/endpoint', { key: 'value' })
// $ variant
const data = await reqo.$post('/endpoint', { key: 'value' })
PUT
PUT accepts parameters in following order: url, data, options:
const response = await reqo.put('/endpoint', { key: 'value' })
// $ variant
const data = await reqo.$put('/endpoint', { key: 'value' })
PATCH
PATCH accepts parameters in following order: url, data, options:
const response = await reqo.patch('/endpoint', { key: 'value' })
// $ variant
const data = await reqo.$patch('/endpoint', { key: 'value' })
DELETE
DELETE accepts parameters in following order: url, options:
const response = await reqo.delete('/endpoint')
// $ variant
const data = await reqo.$delete('/endpoint')
Query Parameters
Use params option to send query parameters, it will be serialized automatically.
// Single values
const users = await reqo.$get('/users', { id: 123 })
// GET /users?id=123
// Arrays
const filtered = await reqo.$get('/users', {
id: [1, 2, 3],
status: 'active'
})
// GET /users?id=1&id=2&id=3&status=active
// Nested objects
const results = await reqo.$get('/search', {
filters: { name: 'John', age: 30 }
})
// GET /search?filters[name]=John&filters[age]=30
// POST with query params
const user = await reqo.$post('/users', { name: 'Jane' }, {
params: { ref: 'newsletter' }
})
// POST /users?ref=newsletter
Request Body
POST, PUT, and PATCH requests accept data as the second argument or you can use data option in request method.
// JSON body (automatically serialized)
await reqo.$post('/users', {
name: 'John',
email: 'john@example.com'
})
// FormData
const formData = new FormData()
formData.append('file', file)
formData.append('name', 'Document')
await reqo.$post('/upload', formData)
// URL-encoded (set content-type header)
const params = new URLSearchParams()
params.append('key', 'value')
await reqo.$post('/form', params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
Response Type
The response body is automatically parsed based on the Content-Type header by default. You can also explicitly set the expected response type using the responseType option.
// Automatically parsed as JSON if Content-Type is application/json, otherwise returns text, this is default behavior
const data = await reqo.$get('/data', {}, {
responseType: 'auto'
})
// JSON
const json = await reqo.$get('/data', {}, {
responseType: 'json'
})
console.log(json) // JSON object
// Plain text
const text = await reqo.$get('/file.txt', {}, {
responseType: 'text'
})
console.log(text) // string
// Binary data
const blob = await reqo.$get('/image.png', {}, {
responseType: 'blob'
})
console.log(blob) // Blob
// Array buffer
const buffer = await reqo.$get('/binary', {}, {
responseType: 'arrayBuffer'
})
console.log(buffer) // ArrayBuffer
// No parsing
const response = await reqo.get('/endpoint', {}, {
responseType: false
})
// Process body manually
const body = await response.body
const reader = body.getReader()
Working with Responses
When using methods without $ prefix, you get the full Response object.
const response = await reqo.get('/users')
// Access response data
console.log(response.data)
// Response metadata
console.log(response.status)
console.log(response.statusText)
console.log(response.headers)
console.log(response.ok)
// Check content type
const contentType = response.headers.get('content-type')
The $ prefix methods return only the data:
// Returns the data directly
const users = await reqo.$get('/users')
// Equivalent to:
const response = await reqo.get('/users')
const users = response.data
Timeouts
Set request timeouts to prevent hanging requests.
timeout option.try {
// 5 second timeout
const data = await reqo.$get('/slow-endpoint', {}, {
timeout: 5000
})
} catch (error) {
if (reqo.isError(error) && error.code === 'E_TIMEOUT') {
console.log('Request timed out')
}
}
Cancellation
Requests return a cancellable Future (extended Promise). You can cancel requests using the Future's cancel method or an AbortController.
Cancel method
// Start request
const request = reqo.get('/users')
// Cancel after 1 second
setTimeout(() => request.cancel(), 1000)
try {
const data = await promise
} catch (error) {
if (reqo.isError(error) && error.code === 'E_CANCELED') {
console.log('Request was canceled')
}
}
AbortController
// Or using AbortController
const controller = new AbortController()
// Start request
const promise = reqo.$get('/users', {}, {
signal: controller.signal
})
// Cancel after 1 second
setTimeout(() => controller.abort(), 1000)
try {
const data = await promise
} catch (error) {
if (reqo.isError(error) && error.code === 'E_CANCELED') {
console.log('Request was canceled')
}
}
Error Handling
All errors returned by the library are instances of RequestError, which provides useful properties for debugging and logging.
import { reqo, errors } from '@outloud/reqo'
try {
const data = await reqo.$get('/users/999')
} catch (error) {
// Type-safe error checking
if (reqo.isError(error)) {
console.log('Status:', error.status)
console.log('Code:', error.code)
console.log('Message:', error.message)
console.log('Response data:', error.data)
console.log('URL:', error.url)
console.log('Method:', error.method)
console.log('Config:', error.config)
console.log('Request:', error.request)
console.log('Response:', error.response)
console.log(error.toJSON()) // Serialize error to JSON, useful for logging
}
// Check specific error types
if (error instanceof errors.TimeoutError) {
console.log('Request timed out')
}
if (error instanceof errors.CanceledError) {
console.log('Request was canceled')
}
}
Type Safety
The library provides full TypeScript support:
interface User {
id: number
name: string
email: string
}
interface CreateUserDto {
name: string
email: string
}
// Type the response
const user = await reqo.$get<User>('/users/1')
console.log(user) // User
// Type request and response
const newUser = await reqo.$post<User, CreateUserDto>('/users', {
name: 'John',
email: 'john@example.com'
})
console.log(newUser) // User