Explore advanced capabilities like streaming, GraphQL, and real-time communication
Apisto provides powerful advanced features for complex API scenarios including streaming data, GraphQL support, real-time communication, and sophisticated request patterns.
🚀 Pro Tips: These advanced features can significantly improve performance and user experience in data-intensive applications.
Handle large datasets or real-time data streams efficiently with Apisto's streaming capabilities.
// Basic streaming example
const api = new Apisto({
baseURL: 'https://api.example.com'
});
async function processStream() {
try {
const stream = await api.stream('/data-stream');
// Process chunks as they arrive
for await (const chunk of stream) {
console.log('Received chunk:', chunk);
// Process data incrementally
processChunk(JSON.parse(chunk));
}
console.log('Stream completed');
} catch (error) {
console.error('Stream error:', error);
}
}
// Cancelable streaming with progress
async function streamWithControl() {
const stream = await api.stream('/large-dataset', {
onProgress: (progress) => {
console.log(`Downloaded: ${progress.loaded} bytes`);
}
});
// Cancel after 5 seconds
setTimeout(() => {
stream.cancel();
console.log('Stream cancelled');
}, 5000);
try {
const fullText = await stream.text();
console.log('Complete data:', fullText);
} catch (error) {
if (error.message.includes('cancelled')) {
console.log('Stream was cancelled');
}
}
}
💡 Use Case: Perfect for large file downloads, real-time data feeds, or processing datasets that don't fit in memory.
Seamlessly integrate with GraphQL APIs using Apisto's dedicated GraphQL method.
// Basic GraphQL query
const api = new Apisto({
baseURL: 'https://api.example.com/graphql'
});
async function fetchUserData() {
try {
const query = `
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
posts {
title
content
}
}
}
`;
const variables = { id: '123' };
const response = await api.graphql(query, variables);
const user = response.data.user;
console.log('User data:', user);
} catch (error) {
console.error('GraphQL error:', error);
}
}
// GraphQL with authentication
async function fetchProtectedData() {
const mutation = `
mutation CreatePost($title: String!, $content: String!) {
createPost(title: $title, content: $content) {
id
title
createdAt
}
}
`;
const variables = {
title: 'My New Post',
content: 'This is the content...'
};
// Set auth token first
api.setAuthToken('your-jwt-token');
const result = await api.graphql(mutation, variables, 'CreatePost', {
headers: {
'X-Custom-Header': 'value'
}
});
console.log('Created post:', result.data.createPost);
}
// Handle GraphQL errors
async function handleGraphQLErrors() {
try {
const response = await api.graphql('query { invalidField }');
if (response.errors) {
console.error('GraphQL errors:', response.errors);
// Handle specific GraphQL errors
response.errors.forEach(error => {
if (error.extensions?.code === 'UNAUTHENTICATED') {
// Redirect to login
window.location.href = '/login';
}
});
}
} catch (error) {
console.error('Request failed:', error);
}
}
Build real-time features with WebSocket and Server-Sent Events support.
const api = new Apisto({
baseURL: 'https://api.example.com'
});
// Create WebSocket connection
const socket = api.createWebSocket('/realtime', ['protocol1', 'protocol2']);
socket.onopen = () => {
console.log('WebSocket connected');
socket.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
updateUI(data);
};
socket.onclose = () => {
console.log('WebSocket disconnected');
// Attempt reconnection
setTimeout(connectWebSocket, 5000);
};
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
// Send message
function sendMessage(message) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(message));
}
}
// Close connection
function disconnect() {
socket.close();
}
const api = new Apisto({
baseURL: 'https://api.example.com'
});
// Create EventSource connection
const eventSource = api.createEventSource('/events', {
withCredentials: true
});
eventSource.onopen = () => {
console.log('EventSource connected');
};
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Event received:', data);
handleEvent(data);
};
eventSource.addEventListener('custom-event', (event) => {
const data = JSON.parse(event.data);
console.log('Custom event:', data);
});
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
// EventSource will automatically attempt to reconnect
};
// Close connection
function closeEventSource() {
eventSource.close();
}
// Reconnect manually
function reconnectEventSource() {
eventSource.close();
// Recreate connection
setTimeout(() => {
createEventSource();
}, 1000);
}
Execute multiple requests efficiently with controlled concurrency.
const api = new Apisto({
baseURL: 'https://api.example.com',
maxConcurrent: 5 // Control batch concurrency
});
async function loadDashboardData() {
const requests = [
{ endpoint: '/users', options: { method: 'GET' } },
{ endpoint: '/posts', options: { method: 'GET' } },
{ endpoint: '/stats', options: { method: 'GET' } },
{ endpoint: '/notifications', options: { method: 'GET' } },
{ endpoint: '/settings', options: { method: 'GET' } }
];
try {
const results = await api.batch(requests, {
concurrency: 3 // Override global concurrency
});
// Process results
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Request ${index} succeeded:`, result.value);
} else {
console.error(`Request ${index} failed:`, result.reason);
}
});
// Extract successful results
const successfulResults = results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
return successfulResults;
} catch (error) {
console.error('Batch request failed:', error);
}
}
// Batch with different HTTP methods
async function batchWithMixedMethods() {
const requests = [
{ endpoint: '/users/1', options: { method: 'GET' } },
{ endpoint: '/users', options: {
method: 'POST',
body: { name: 'John', email: 'john@example.com' }
}},
{ endpoint: '/users/2', options: { method: 'DELETE' } },
{ endpoint: '/users/3', options: {
method: 'PATCH',
body: { name: 'Jane Updated' }
}}
];
const results = await api.batch(requests);
console.log('Mixed batch results:', results);
}
// Handle batch with error tolerance
async function tolerantBatch() {
const requests = [
{ endpoint: '/data1', options: { method: 'GET' } },
{ endpoint: '/nonexistent', options: { method: 'GET' } }, // This will fail
{ endpoint: '/data2', options: { method: 'GET' } }
];
const results = await api.batch(requests);
const data = {};
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
data[`request${index}`] = result.value;
} else {
console.warn(`Request ${index} failed but continuing:`, result.reason);
data[`request${index}`] = null;
}
});
return data;
}
Sophisticated error handling patterns for production applications.
// Global error handler
api.addErrorInterceptor(async (error, options) => {
// Log to monitoring service
await logToMonitoringService({
error: error.message,
url: options.url,
method: options.method,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
});
// Handle specific error types
if (error instanceof ApiError) {
switch (error.status) {
case 401:
// Redirect to login
window.location.href = '/login?redirect=' + encodeURIComponent(window.location.pathname);
break;
case 403:
// Show access denied
showNotification('Access denied', 'error');
break;
case 429:
// Rate limited
showNotification('Too many requests. Please wait.', 'warning');
break;
case 500:
// Server error
showNotification('Server error. Please try again later.', 'error');
break;
}
}
return error;
});
// Retry with custom conditions
async function fetchWithCustomRetry() {
return api.request('/sensitive-data', {
maxRetries: 5,
retryCondition: (error) => {
// Only retry on network errors and 5xx status codes
return error.code === 'NETWORK_ERROR' ||
(error.status >= 500 && error.status < 600);
}
});
}
// Circuit breaker integration
async function makeResilientRequest() {
const circuitBreaker = api._getCircuitBreaker('/api');
if (!circuitBreaker.canExecute()) {
throw new ApistoError('Circuit breaker open', 'CIRCUIT_BREAKER_OPEN');
}
try {
const result = await api.get('/api/data');
circuitBreaker.onSuccess();
return result;
} catch (error) {
circuitBreaker.onFailure();
throw error;
}
}
// Fallback strategies
async function fetchWithFallback() {
try {
return await api.get('/primary-endpoint');
} catch (error) {
console.warn('Primary endpoint failed, trying fallback:', error);
try {
return await api.get('/fallback-endpoint');
} catch (fallbackError) {
console.error('Fallback also failed:', fallbackError);
// Return cached data or default values
return getCachedData();
}
}
}
Optimize your API calls for better performance and user experience.
// Request deduplication
const pendingRequests = new Map();
async function deduplicatedRequest(endpoint, options = {}) {
const key = `${endpoint}:${JSON.stringify(options)}`;
if (pendingRequests.has(key)) {
return pendingRequests.get(key);
}
const promise = api.request(endpoint, options).finally(() => {
pendingRequests.delete(key);
});
pendingRequests.set(key, promise);
return promise;
}
// Smart caching with validation
async function getCachedData(endpoint, validator) {
const cacheKey = `cache:${endpoint}`;
const cached = localStorage.getItem(cacheKey);
if (cached) {
const data = JSON.parse(cached);
// Validate cache (e.g., check timestamp)
if (validator(data)) {
return data;
}
}
// Fetch fresh data
const freshData = await api.get(endpoint);
// Cache with timestamp
const cacheData = {
data: freshData,
timestamp: Date.now(),
ttl: 5 * 60 * 1000 // 5 minutes
};
localStorage.setItem(cacheKey, JSON.stringify(cacheData));
return freshData;
}
// Progressive loading with placeholders
async function loadProgressiveData() {
// Show skeleton/shimmer immediately
showLoadingState();
try {
// Request with low priority headers
const data = await api.get('/data', {
headers: {
'Accept': 'application/json',
'X-Priority': 'low' // Could be used by server for QoS
}
});
updateUI(data);
} catch (error) {
showErrorState(error);
} finally {
hideLoadingState();
}
}
// Prefetching and background sync
function prefetchData() {
// Prefetch likely needed data
const endpoints = ['/user/profile', '/notifications', '/dashboard/stats'];
endpoints.forEach(endpoint => {
api.get(endpoint, {
priority: 'low',
background: true // Custom option for background requests
}).catch(() => {
// Silently fail for background prefetch
});
});
}
// Lazy loading with intersection observer
function setupLazyLoading() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const endpoint = entry.target.dataset.endpoint;
loadLazyData(endpoint, entry.target);
observer.unobserve(entry.target);
}
});
});
document.querySelectorAll('[data-lazy-endpoint]').forEach(el => {
observer.observe(el);
});
}
Learn how to create custom plugins to extend Apisto's functionality.
Continue to Plugin System →