UNPKG

@tmlmobilidade/utils

Version:

A collection of utility functions and helpers for the TML Mobilidade Go monorepo, providing common functionality for batching operations, caching, HTTP requests, object manipulation, permissions, and more.

78 lines (77 loc) 2.82 kB
/* * */ import { HttpResponse } from './response.js'; /** * Fetches data from a URL with configurable HTTP method, body, headers, and options. * @param url - The URL to fetch from * @param method - The HTTP method to use (DELETE, GET, POST, PUT). Defaults to GET. * @param body - Optional request body data * @param headers - Optional request headers * @param options - Optional fetch options (excluding body, headers, method) * @returns Promise resolving to HttpResponse containing data, error and status * @example * ```ts * // GET request * const response = await fetchData<User>('/api/users/123'); * * // POST request with body * const response = await fetchData<User>( * '/api/users', * 'POST', * { name: 'John', email: 'john@example.com' } * ); * ``` */ export async function fetchData(url, method = 'GET', body, headers = {}, options = {}, retries = 3) { let attempt = 0; let lastError; while (attempt <= retries) { try { const response = await fetch(url, { body: body ? JSON.stringify(body) : undefined, credentials: 'include', headers: { ...(method === 'GET' || method === 'DELETE' || 'Content-Type' in headers ? {} : { 'Content-Type': 'application/json' }), ...headers, }, method, ...options, }); const data = (await response.json()); if (!response.ok || data.error) { // Don't retry for 4xx (client) errors if (response.status >= 400 && response.status < 500) { return new HttpResponse({ data: null, error: data.error, statusCode: response.status, }); } throw new Error(`HTTP ${response.status} - ${data.error ?? 'Unknown error'}`); } return new HttpResponse({ data: data.data, error: null, statusCode: response.status, }); } catch (error) { lastError = error; attempt++; // Stop retrying if we've reached the limit if (attempt > retries) break; // Wait before retrying (exponential backoff: 0.5s, 1s, 2s, etc.) const delay = 500 * Math.pow(2, attempt - 1); await new Promise(resolve => setTimeout(resolve, delay)); } } return new HttpResponse({ data: null, error: lastError instanceof Error ? `${lastError.message} - ${lastError.cause ?? ''}` : 'Network error', statusCode: 500, }); }