Master GET, POST, PUT, PATCH, DELETE and advanced request features
Apisto provides intuitive methods for all HTTP verbs with built-in error handling, retry logic, and request customization. Let's explore each method with practical examples.
💡 RESTful Principles: Each HTTP method has a specific purpose in REST APIs: GET (read), POST (create), PUT (replace), PATCH (update), DELETE (remove).
Used for retrieving data from the server. Apisto provides multiple ways to make GET requests.
// Simple GET request
const users = await api.get('/users');
console.log('Users:', users);
// With query parameters
const filteredUsers = await api.get('/users', {
active: true,
role: 'admin',
page: 1,
limit: 10
});
// GET with custom headers and options
const user = await api.get('/users/123', {
headers: {
'X-Custom-Header': 'value',
'Accept-Language': 'en-US'
},
cache: 'no-cache',
timeout: 5000
});
// Using the generic request method
const products = await api.request('/products', {
method: 'GET',
query: { category: 'electronics' }
});
Used for creating new resources on the server. Apisto automatically handles JSON serialization.
// Create a new user
const newUser = await api.post('/users', {
name: 'John Doe',
email: 'john@example.com',
role: 'user'
});
console.log('Created user:', newUser);
// POST with additional options
const result = await api.post('/orders', {
productId: '123',
quantity: 2
}, {
headers: {
'X-Request-ID': 'unique-123'
}
});
// POST with FormData (for file uploads)
const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('avatar', fileInput.files[0]);
const user = await api.post('/users', formData, {
// No Content-Type header needed for FormData
});
// URL-encoded form data
const urlEncodedData = new URLSearchParams({
username: 'johndoe',
password: 'secret'
});
const login = await api.post('/login', urlEncodedData, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
PUT replaces entire resources, while PATCH performs partial updates.
// PUT - Replace entire resource
const updatedUser = await api.put('/users/123', {
id: 123,
name: 'John Smith', // Full replacement
email: 'john.smith@example.com',
role: 'admin',
createdAt: '2023-01-01' // Must include all fields
});
// PUT for resource creation (if supported by API)
const newResource = await api.put('/resources/456', {
title: 'New Resource',
content: 'Resource content'
});
// PATCH - Update only changed fields
const patchedUser = await api.patch('/users/123', {
name: 'John Smith', // Only update name
// email remains unchanged
});
// Multiple partial updates
const updatedOrder = await api.patch('/orders/789', {
status: 'shipped',
trackingNumber: 'TRK123456',
shippedAt: new Date().toISOString()
});
// Using JSON Patch format (if API supports it)
const jsonPatch = await api.patch('/products/456', [
{ op: 'replace', path: '/price', value: 29.99 },
{ op: 'add', path: '/tags', value: ['sale'] }
]);
⚠️ Key Difference: PUT replaces the entire resource, while PATCH only updates the provided fields. Always use PATCH for partial updates to avoid overwriting data.
Used for removing resources from the server.
// Simple DELETE
await api.delete('/users/123');
console.log('User deleted successfully');
// DELETE with confirmation data
await api.delete('/orders/456', {
body: JSON.stringify({
reason: 'cancelled_by_user',
notes: 'Customer requested cancellation'
})
});
// DELETE with custom headers
await api.delete('/products/789', {
headers: {
'X-Delete-Reason': 'out_of_stock'
}
});
// Batch delete (if API supports it)
await api.delete('/products', {
body: JSON.stringify({
ids: [123, 456, 789]
})
});
Apisto provides extensive options to customize every aspect of your requests.
// Complete request options example
const response = await api.request('/endpoint', {
method: 'POST',
// Request body
body: { key: 'value' },
// Headers
headers: {
'X-Custom-Header': 'value',
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
},
// Query parameters
query: { page: 1, limit: 10 },
// Timeout (overrides global config)
timeout: 15000,
// Retry configuration
maxRetries: 5,
retryCondition: (error) => error.status >= 500,
// Cache control
cache: 'no-cache',
skipCache: true,
// Cancellation
signal: abortController.signal,
// Authentication
skipAuth: false,
// Response handling
responseType: 'json', // 'json', 'text', 'blob', 'arrayBuffer'
parseResponse: true
});
// Common options in practice
const commonOptions = {
// For sensitive data, disable caching
cache: 'no-store',
// For real-time data, shorter timeout
timeout: 5000,
// For large uploads, longer timeout
timeout: 60000,
// For critical operations, more retries
maxRetries: 5,
// For public APIs, include API key
headers: {
'X-API-Key': 'your-api-key'
}
};
Apisto provides structured error handling for different failure scenarios.
try {
const data = await api.get('/users/999'); // Non-existent user
} catch (error) {
if (error instanceof ApiError) {
switch (error.status) {
case 400:
console.error('Bad request:', error.body);
break;
case 401:
console.error('Unauthorized - please login');
// Redirect to login
window.location.href = '/login';
break;
case 403:
console.error('Forbidden - insufficient permissions');
break;
case 404:
console.error('Resource not found');
break;
case 500:
console.error('Server error - please try again later');
break;
default:
console.error(`HTTP ${error.status}:`, error.message);
}
} else if (error instanceof NetworkError) {
console.error('Network issue - check your connection');
} else {
console.error('Unexpected error:', error);
}
}
// Retry with exponential backoff
async function fetchWithRetry(endpoint, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await api.get(endpoint);
} catch (error) {
if (attempt === maxAttempts) throw error;
if (error.status === 429) { // Rate limited
const retryAfter = error.headers['retry-after'] || 1000;
await new Promise(resolve => setTimeout(resolve, retryAfter));
} else if (error.status >= 500) { // Server error
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
} else {
throw error; // Don't retry client errors
}
}
}
}
// Circuit breaker pattern
class CircuitBreaker {
constructor() {
this.failures = 0;
this.lastFailure = null;
this.state = 'CLOSED';
}
async execute(requestFn) {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailure > 60000) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker open');
}
}
try {
const result = await requestFn();
this.failures = 0;
this.state = 'CLOSED';
return result;
} catch (error) {
this.failures++;
this.lastFailure = Date.now();
if (this.failures >= 5) this.state = 'OPEN';
throw error;
}
}
}
// Complete CRUD operations example
class UserService {
constructor(api) {
this.api = api;
}
// CREATE
async createUser(userData) {
try {
const user = await this.api.post('/users', userData);
console.log('User created:', user);
return user;
} catch (error) {
console.error('Failed to create user:', error);
throw error;
}
}
// READ
async getUser(userId) {
try {
const user = await this.api.get(`/users/${userId}`);
return user;
} catch (error) {
if (error.status === 404) {
console.log('User not found');
return null;
}
throw error;
}
}
// READ ALL with pagination
async getUsers(page = 1, limit = 10) {
const users = await this.api.get('/users', { page, limit });
return users;
}
// UPDATE
async updateUser(userId, updates) {
const updatedUser = await this.api.patch(`/users/${userId}`, updates);
console.log('User updated:', updatedUser);
return updatedUser;
}
// DELETE
async deleteUser(userId) {
await this.api.delete(`/users/${userId}`);
console.log('User deleted successfully');
}
// BATCH OPERATIONS
async bulkUpdateUsers(userUpdates) {
const results = await this.api.batch(
userUpdates.map(update => ({
endpoint: `/users/${update.id}`,
options: {
method: 'PATCH',
body: update.data
}
}))
);
return results;
}
}
// Usage
const userService = new UserService(api);
// Complete workflow
async function userManagementWorkflow() {
// Create a user
const newUser = await userService.createUser({
name: 'Alice Johnson',
email: 'alice@example.com',
role: 'user'
});
// Get the user
const user = await userService.getUser(newUser.id);
// Update the user
await userService.updateUser(user.id, {
name: 'Alice Smith',
role: 'admin'
});
// Get all users
const users = await userService.getUsers(1, 20);
// Bulk update
await userService.bulkUpdateUsers([
{ id: 1, data: { status: 'active' } },
{ id: 2, data: { status: 'inactive' } }
]);
// Delete user
await userService.deleteUser(user.id);
}
// Run the workflow
userManagementWorkflow().catch(console.error);
🎉 Excellent! You've now mastered all HTTP request methods with Apisto. This foundation will serve you in building robust API integrations.
Learn how to upload, download, and manipulate files with Apisto's powerful file handling capabilities.
Continue to File Handling →