HTTP client utilities built on apisauce (which wraps axios) for making API requests, handling responses, and integrating with web services in CLI applications.
Factory function for creating configured HTTP client instances with apisauce.
/**
* Create a new HTTP client instance using apisauce
* @param options - Apisauce configuration options
* @returns Configured apisauce instance with HTTP methods
*/
create(options: ApisauceConfig): ApisauceInstance;
interface ApisauceConfig {
/** Base URL for all requests */
baseURL?: string;
/** Default headers for all requests */
headers?: { [key: string]: string };
/** Request timeout in milliseconds */
timeout?: number;
/** Response transform functions */
transform?: {
request?: Array<(data: any, headers?: any) => any>;
response?: Array<(response: any) => any>;
};
/** Axios configuration options */
axiosConfig?: any;
}
interface ApisauceInstance {
/** GET request */
get(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;
/** POST request */
post(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/** PUT request */
put(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/** PATCH request */
patch(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/** DELETE request */
delete(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;
/** HEAD request */
head(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;
/** Set base URL */
setBaseURL(baseURL: string): void;
/** Add request transform */
addRequestTransform(transform: (request: any) => void): void;
/** Add response transform */
addResponseTransform(transform: (response: any) => void): void;
}
interface ApiResponse {
/** Response was successful (2xx status) */
ok: boolean;
/** Parsed response data */
data?: any;
/** Original axios response */
originalError?: any;
/** HTTP status code */
status?: number;
/** Response headers */
headers?: any;
/** Response configuration */
config?: any;
/** Duration of request in milliseconds */
duration?: number;
/** Problem classification */
problem?: string;
}HTTP Client Examples:
import { http } from "gluegun";
// Create basic API client
const api = http.create({
baseURL: 'https://api.example.com',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
timeout: 5000
});
// Make GET request
const response = await api.get('/users');
if (response.ok) {
console.log('Users:', response.data);
} else {
console.error('Failed to fetch users:', response.problem);
}
// Make POST request with data
const newUser = await api.post('/users', {
name: 'John Doe',
email: 'john@example.com'
});
if (newUser.ok) {
console.log('User created:', newUser.data);
}All standard HTTP methods are available with consistent response handling.
/**
* HTTP GET request
* @param url - Request URL (appended to baseURL)
* @param params - Query parameters object
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
get(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;
/**
* HTTP POST request
* @param url - Request URL
* @param data - Request body data
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
post(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/**
* HTTP PUT request
* @param url - Request URL
* @param data - Request body data
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
put(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/**
* HTTP PATCH request
* @param url - Request URL
* @param data - Request body data
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
patch(url: string, data?: any, axiosConfig?: any): Promise<ApiResponse>;
/**
* HTTP DELETE request
* @param url - Request URL
* @param params - Query parameters object
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
delete(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;
/**
* HTTP HEAD request
* @param url - Request URL
* @param params - Query parameters object
* @param axiosConfig - Additional axios configuration
* @returns Promise resolving to API response
*/
head(url: string, params?: any, axiosConfig?: any): Promise<ApiResponse>;Request Method Examples:
import { http } from "gluegun";
const api = http.create({ baseURL: 'https://jsonplaceholder.typicode.com' });
// GET with query parameters
const posts = await api.get('/posts', { userId: 1, _limit: 5 });
// POST with JSON data
const newPost = await api.post('/posts', {
title: 'My New Post',
body: 'This is the post content',
userId: 1
});
// PUT to update resource
const updatedPost = await api.put('/posts/1', {
id: 1,
title: 'Updated Title',
body: 'Updated content',
userId: 1
});
// PATCH for partial update
const patchedPost = await api.patch('/posts/1', {
title: 'Partially Updated Title'
});
// DELETE resource
const deleteResponse = await api.delete('/posts/1');
// HEAD to check resource existence
const headResponse = await api.head('/posts/1');
console.log('Post exists:', headResponse.ok);Configure authentication and custom headers for API requests.
// API client with authentication
const authenticatedApi = http.create({
baseURL: 'https://api.example.com',
headers: {
'Authorization': 'Bearer your-jwt-token',
'X-API-Key': 'your-api-key',
'User-Agent': 'MyApp/1.0.0'
}
});
// Dynamic header setting
const api = http.create({ baseURL: 'https://api.example.com' });
// Set headers for specific request
const response = await api.get('/protected', {}, {
headers: {
'Authorization': `Bearer ${token}`
}
});
// API key authentication example
const apiKeyClient = http.create({
baseURL: 'https://api.service.com',
headers: {
'X-RapidAPI-Key': process.env.RAPIDAPI_KEY,
'X-RapidAPI-Host': 'api.service.com'
}
});Comprehensive response handling with error detection and data extraction.
import { http, print } from "gluegun";
const api = http.create({ baseURL: 'https://api.example.com' });
// Robust response handling
async function fetchUserData(userId) {
const response = await api.get(`/users/${userId}`);
if (response.ok) {
// Success (2xx status)
print.success(`User loaded: ${response.data.name}`);
return response.data;
} else {
// Handle different error types
switch (response.problem) {
case 'CLIENT_ERROR':
print.error(`Client error (${response.status}): ${response.data?.message || 'Bad request'}`);
break;
case 'SERVER_ERROR':
print.error(`Server error (${response.status}): Service unavailable`);
break;
case 'TIMEOUT_ERROR':
print.error('Request timed out');
break;
case 'CONNECTION_ERROR':
print.error('Network connection failed');
break;
case 'NETWORK_ERROR':
print.error('Network error occurred');
break;
case 'CANCEL_ERROR':
print.error('Request was cancelled');
break;
default:
print.error(`Unknown error: ${response.problem}`);
}
return null;
}
}
// Response timing
const response = await api.get('/slow-endpoint');
print.info(`Request completed in ${response.duration}ms`);Customize request and response processing with transform functions.
import { http } from "gluegun";
// Create client with transforms
const api = http.create({
baseURL: 'https://api.example.com',
transform: {
request: [
// Add timestamp to all requests
(data, headers) => {
if (data && typeof data === 'object') {
data._timestamp = Date.now();
}
return data;
},
// Add request ID header
(data, headers) => {
headers['X-Request-ID'] = Math.random().toString(36).substr(2, 9);
return data;
}
],
response: [
// Log all responses
(response) => {
console.log(`API Response: ${response.status} ${response.config.url}`);
return response;
},
// Normalize error responses
(response) => {
if (!response.ok && response.data?.error) {
response.data = { message: response.data.error };
}
return response;
}
]
}
});
// Add transforms after creation
api.addRequestTransform((request) => {
console.log(`Making request to: ${request.url}`);
});
api.addResponseTransform((response) => {
if (response.data?.deprecated) {
console.warn('This API endpoint is deprecated');
}
});Dynamic configuration and base URL management for different environments.
import { http } from "gluegun";
// Environment-based configuration
const apiConfig = {
development: { baseURL: 'http://localhost:3000' },
staging: { baseURL: 'https://staging-api.example.com' },
production: { baseURL: 'https://api.example.com' }
};
const env = process.env.NODE_ENV || 'development';
const api = http.create({
...apiConfig[env],
headers: {
'Content-Type': 'application/json'
},
timeout: 10000
});
// Dynamic base URL changes
if (shouldUseBackupServer) {
api.setBaseURL('https://backup-api.example.com');
}
// Multiple API clients
const userApi = http.create({ baseURL: 'https://users.api.com' });
const paymentApi = http.create({
baseURL: 'https://payments.api.com',
headers: { 'Authorization': `Bearer ${paymentToken}` }
});
const analyticsApi = http.create({ baseURL: 'https://analytics.api.com' });interface GluegunHttp {
/**
* Create HTTP client instance
* @param options - Apisauce configuration
* @returns Configured HTTP client
*/
create(options: ApisauceConfig): ApisauceInstance;
}Comprehensive Usage Example:
// CLI command for API management
export = {
name: "api",
description: "Interact with API services",
run: async (toolbox) => {
const { http, print, prompt, parameters } = toolbox;
const action = parameters.first;
// Create API client with configuration
const api = http.create({
baseURL: process.env.API_BASE_URL || 'https://api.example.com',
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`,
'Content-Type': 'application/json',
'User-Agent': 'CLI-Tool/1.0.0'
},
timeout: 30000,
transform: {
request: [
(data, headers) => {
print.muted(`→ ${headers['X-HTTP-Method-Override'] || 'GET'} request`);
return data;
}
],
response: [
(response) => {
print.muted(`← ${response.status} response in ${response.duration}ms`);
return response;
}
]
}
});
switch (action) {
case 'users':
await handleUsers(api, print, prompt, parameters);
break;
case 'upload':
await handleUpload(api, print, parameters);
break;
case 'health':
await checkHealth(api, print);
break;
default:
print.error('Usage: cli api <users|upload|health>');
}
}
};
async function handleUsers(api, print, prompt, parameters) {
const subAction = parameters.second;
switch (subAction) {
case 'list':
const users = await api.get('/users', { page: 1, limit: 10 });
if (users.ok) {
print.table(users.data.map(u => [u.id, u.name, u.email]));
} else {
print.error(`Failed to fetch users: ${users.problem}`);
}
break;
case 'create':
const userData = await prompt.ask([
{ type: 'input', name: 'name', message: 'Name:' },
{ type: 'input', name: 'email', message: 'Email:' }
]);
const newUser = await api.post('/users', userData);
if (newUser.ok) {
print.success(`User created: ${newUser.data.id}`);
} else {
print.error(`Failed to create user: ${newUser.data?.message || newUser.problem}`);
}
break;
}
}
async function handleUpload(api, print, parameters) {
const filePath = parameters.second;
if (!filePath) {
print.error('Usage: cli api upload <file-path>');
return;
}
// File upload with form data
const FormData = require('form-data');
const fs = require('fs');
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
const upload = await api.post('/upload', form, {
headers: form.getHeaders(),
timeout: 60000 // Longer timeout for uploads
});
if (upload.ok) {
print.success(`File uploaded: ${upload.data.url}`);
} else {
print.error(`Upload failed: ${upload.problem}`);
}
}
async function checkHealth(api, print) {
const health = await api.get('/health');
if (health.ok) {
print.success('✓ API is healthy');
print.info(`Status: ${health.data.status}`);
print.info(`Version: ${health.data.version}`);
print.muted(`Response time: ${health.duration}ms`);
} else {
print.error('✗ API is unhealthy');
print.error(`Problem: ${health.problem}`);
if (health.status) {
print.error(`HTTP Status: ${health.status}`);
}
}
}