Guide
Instances
Create and configure custom HTTP client instances.
While the default http instance works for simple use cases, you can create custom client instances with specific configurations for different APIs or use cases.
Creating a Client
Use the createClient function to create a new client instance:
import { createClient } from '@outloud/reqo'
const apiClient = createClient({
url: 'https://api.example.com',
timeout: 10000,
headers: {
'Authorization': 'Bearer your-token'
}
})
// Use the client
const users = await apiClient.$get('/users')
Options
id
string | undefined
Descriptive name for the client, will be used in errors and debugging.
const client = createClient({
id: 'github-api'
})
url
string | undefined
Base URL for all requests. Paths will be appended to this URL.
const client = createClient({
url: 'https://api.example.com/v1'
})
// GET https://api.example.com/v1/users
await client.$get('/users')
headers
HeaderValues | undefined
Default headers to include in all requests.
const client = createClient({
headers: {
'Authorization': 'Bearer token',
'X-API-Key': 'key'
}
})
timeout
number | false
Request timeout in milliseconds. Set to
Defaults to
false to disable timeouts.
Defaults to
60000 (60 seconds).const client = createClient({
timeout: 5000 // 5 seconds
})
retry
UserRetryOptions | boolean
Retry configuration. Set to
Defaults to
true for default retry behavior or provide custom options.
Defaults to
false.const client = createClient({
retry: {
limit: 3,
methods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'],
statusCodes: [408, 429, 500, 502, 503, 504],
delay: (count) => count * 1000
}
})
redirect
RequestInit['redirect']
How to handle redirects:
Defaults to
'follow', 'error', or 'manual'.
Defaults to
'follow'.const client = createClient({
redirect: 'manual'
})
fetch
typeof fetch
Custom fetch implementation. Useful for testing or using polyfills.
Defaults to
Defaults to
globalThis.fetch.import nodeFetch from 'node-fetch'
const client = createClient({
fetch: nodeFetch as any
})
validate
ValidateFn | undefined
Custom response validation function. By default, responses with
ok: false throw errors.const client = createClient({
validate: (response) => {
// Only accept 200 status
return response.status === 200
}
})
Multiple Instances
Create different clients for different APIs:
import { createClient } from '@outloud/reqo'
// GitHub API client
const github = createClient({
id: 'github',
url: 'https://api.github.com',
headers: {
'Accept': 'application/vnd.github.v3+json',
'Authorization': `token ${process.env.GITHUB_TOKEN}`
},
timeout: 5000
})
// Internal API client
const internalApi = createClient({
id: 'internal',
url: 'https://internal-api.company.com',
headers: {
'X-API-Key': process.env.INTERNAL_API_KEY
},
retry: {
limit: 3,
delay: (count) => count * 2000
}
})
// Use the clients
const repos = await github.$get('/users/username/repos')
const data = await internalApi.$get('/data')
Base URL Resolution
The client intelligently resolves URLs:
const client = createClient({
url: 'https://api.example.com/v1'
})
// Absolute URLs override base URL
await client.$get('https://other-api.com/data')
// GET https://other-api.com/data
// Relative paths are appended
await client.$get('/users')
// GET https://api.example.com/v1/users
await client.$get('users')
// GET https://api.example.com/v1/users
// Get url
client.getUrl('items')
// https://api.example.com/v1/items
// Browser environment - relative base URLs
const browserClient = createClient({
url: '/api/v1' // relative to window.location.origin
})
Accessing Configuration
Get the base URL from a client instance:
const client = createClient({
url: 'https://api.example.com'
headers: {
'X-Custom-Header': 'value'
}
})
console.log(client.baseUrl) // 'https://api.example.com'
console.log(client.options) // { timeout: 60000, headers: { ... }, ... }
Client Class
You can also extend the Client class for more advanced use cases:
import { Client, type ClientOptions } from '@outloud/reqo'
class ApiClient extends Client {
constructor(options: Partial<ClientOptions> = {}) {
super({
url: 'https://api.example.com',
...options
})
// Setup hooks or custom logic
this.on('request', (config) => {
console.log(`Making ${config.method} request to ${config.url}`)
})
}
// Add custom methods
async getCurrentUser() {
return this.$get('/me')
}
async uploadFile(file: File) {
const formData = new FormData()
formData.append('file', file)
return this.$post('/upload', formData)
}
}
const api = new ApiClient()
const user = await api.getCurrentUser()
Per-Request Overrides
Options passed to individual requests override client defaults:
const client = createClient({
timeout: 5000,
headers: {
'X-Default': 'value'
}
})
// Override timeout for this request
await client.$get('/slow-endpoint', {}, {
timeout: 30000, // overrides client timeout
headers: {
'X-Default': 'overridden', // Replaces default header
'X-Custom': 'additional' // Adds new header
}
})