csbridge
v1.0.11
Published
A TypeScript utility library for handling API requests with robust error handling
Maintainers
Readme
CSBridge - Simple API Service
Overview
CSBridge is a lightweight TypeScript API service for handling HTTP requests with built-in error handling, retry logic, and timeout support. It provides a simple interface for making API calls with proper TypeScript support and flexible configuration options.
Features
- Type-Safe API: Fully typed API service with TypeScript support
- Custom Error Handling: Built-in
ApiErrorclass with detailed error information - HTTP Methods: Support for GET, POST, PUT, PATCH, DELETE operations
- File Operations: Upload and download file support
- Retry Logic: Configurable retry with exponential backoff
- Timeout Handling: Built-in request timeout with abort controller
- Flexible Configuration: Global config, per-request options, or no config
- Authentication Support: Easy header management for authentication
Installation
npm install csbridgeConfiguration Options
CSBridge offers three ways to configure your API requests:
1. Global Configuration (API_CONFIG)
2. Per-Request Configuration
3. No Configuration (Minimal Setup)
1. Using Global Configuration (API_CONFIG)
Set up global configuration that applies to all requests:
import apiService, { API_CONFIG, ApiError } from "csbridge";
// Configure global settings
API_CONFIG.baseUrl = "https://api.example.com";
API_CONFIG.timeout = 60000; // 60 seconds
API_CONFIG.retryCount = 3;
API_CONFIG.retryDelay = 500; // 500ms
API_CONFIG.retriableStatuses = [408, 429, 500, 502, 503, 504];
API_CONFIG.defaultHeaders = {
Authorization: "Bearer your-token",
"Content-Type": "application/json",
"X-API-Key": "your-api-key",
};
// Now all requests use these global settings
async function globalConfigExample() {
try {
// GET request - uses global config
const users = await apiService.get("/users");
console.log("Users:", users.data);
// POST request - uses global config
const newUser = await apiService.post("/users", {
name: "John Doe",
email: "[email protected]",
});
console.log("Created user:", newUser.data);
// File upload - uses global config
const file = new File(["content"], "test.txt", { type: "text/plain" });
const uploadResult = await apiService.upload("/files", file);
console.log("Upload successful:", uploadResult.data);
} catch (error) {
if (error instanceof ApiError) {
console.error(`API Error ${error.status}: ${error.message}`);
}
}
}2. Per-Request Configuration
Override global settings or configure individual requests:
import apiService, { ApiError } from "csbridge";
async function perRequestConfigExample() {
try {
// Example 1: Custom headers for specific request
const response1 = await apiService.get("/protected-data", {
headers: {
Authorization: "Bearer different-token",
"X-Custom-Header": "custom-value",
},
});
// Example 2: Custom timeout for slow endpoint
const response2 = await apiService.get("/slow-endpoint", {
timeout: 120000, // 2 minutes for this request
headers: {
Accept: "application/json",
},
});
// Example 3: Custom retry configuration
const response3 = await apiService.post(
"/unreliable-service",
{
data: "important-data",
},
{
retry: true,
retryOptions: {
retries: 5,
delay: 1000,
retriableStatuses: [408, 429, 500, 502, 503, 504],
},
timeout: 30000,
}
);
// Example 4: Disable retry for specific request
const response4 = await apiService.get("/fast-endpoint", {
retry: false, // No retries for this request
timeout: 5000,
});
// Example 5: Custom retry for rate-limited endpoint
const response5 = await apiService.post(
"/rate-limited-api",
{ data: "test" },
{
retryOptions: {
retries: 3,
delay: 2000,
retriableStatuses: [429], // Only retry on rate limit
},
}
);
console.log("All requests completed successfully");
} catch (error) {
if (error instanceof ApiError) {
console.error("Request failed:", {
status: error.status,
message: error.message,
timestamp: error.timestamp,
});
}
}
}3. Minimal Setup (No Configuration)
Use the API service without any configuration for simple use cases:
import apiService, { ApiError } from "csbridge";
async function minimalExample() {
try {
// Simple GET request with full URL
const response1 = await apiService.get("https://jsonplaceholder.typicode.com/users");
console.log("Users:", response1.data);
// Simple POST request
const response2 = await apiService.post("https://jsonplaceholder.typicode.com/posts", {
title: "My Post",
body: "Post content",
userId: 1,
});
console.log("Created post:", response2.data);
// Simple PUT request
const response3 = await apiService.put("https://jsonplaceholder.typicode.com/posts/1", {
id: 1,
title: "Updated Post",
body: "Updated content",
userId: 1,
});
console.log("Updated post:", response3.data);
// Simple DELETE request
await apiService.delete("https://jsonplaceholder.typicode.com/posts/1");
console.log("Post deleted");
} catch (error) {
if (error instanceof ApiError) {
console.error(`Error ${error.status}: ${error.message}`);
}
}
}API Methods
HTTP Methods
get<T>(url, options?)- GET requestpost<T, D>(url, data?, options?)- POST requestput<T, D>(url, data?, options?)- PUT requestpatch<T, D>(url, data?, options?)- PATCH requestdelete<T>(url, options?)- DELETE requestupload<T>(url, file, options?)- File uploaddownload(url, options?)- File download
Configuration Methods
setBaseUrl(url)- Set the base URL for all requestssetDefaultHeaders(headers)- Set default headers for all requests
Configuration Reference
API_CONFIG Properties
interface ApiConfig {
baseUrl: string; // Base URL for all requests
timeout: number; // Request timeout in milliseconds
defaultHeaders: Record<string, string>; // Default headers for all requests
retryCount: number; // Number of retry attempts
retryDelay: number; // Base delay between retries (ms)
retriableStatuses: number[]; // HTTP status codes to retry on
}Request Options
interface RequestOptions {
headers?: Record<string, string>; // Custom headers for this request
timeout?: number; // Custom timeout for this request
retry?: boolean; // Enable/disable retry for this request
retryOptions?: {
// Custom retry configuration
retries: number; // Number of retry attempts
delay: number; // Base delay between retries
retriableStatuses: number[]; // Status codes to retry on
};
}Mixed Configuration Examples
You can combine different configuration approaches:
import apiService, { API_CONFIG, ApiError } from "csbridge";
// Set some global defaults
API_CONFIG.baseUrl = "https://api.example.com";
API_CONFIG.timeout = 30000;
API_CONFIG.defaultHeaders = {
Authorization: "Bearer global-token",
};
async function mixedConfigExample() {
try {
// Use global config
const users = await apiService.get("/users");
// Override specific settings
const reports = await apiService.get("/reports", {
timeout: 60000, // Override timeout
headers: {
Authorization: "Bearer admin-token", // Override auth
},
});
// Use full URL (ignores baseUrl)
const external = await apiService.get("https://external-api.com/data");
// Custom retry for critical operation
const important = await apiService.post("/critical-data", data, {
retryOptions: {
retries: 5,
delay: 2000,
},
});
} catch (error) {
console.error("Request failed:", error);
}
}Error Handling
ApiError Class
The ApiError class provides structured error information:
class ApiError extends Error {
status: number; // HTTP status code
code: string; // Error code (e.g., "HTTP_404")
data: unknown; // Additional error data from response
timestamp: Date; // When the error occurred
}Error Handling Examples
try {
const response = await apiService.get("/users");
return response.data;
} catch (error) {
if (error instanceof ApiError) {
switch (error.status) {
case 401:
console.log("Authentication required");
// Redirect to login
break;
case 403:
console.log("Access forbidden");
break;
case 404:
console.log("Resource not found");
break;
case 429:
console.log("Rate limited - too many requests");
break;
case 500:
console.log("Server error");
break;
default:
console.log(`API Error: ${error.message}`);
}
} else {
console.error("Unexpected error:", error);
}
}Complete Working Example
import apiService, { API_CONFIG, ApiError } from "csbridge";
// Configure for your API
API_CONFIG.baseUrl = "https://jsonplaceholder.typicode.com";
API_CONFIG.timeout = 30000;
API_CONFIG.retryCount = 3;
API_CONFIG.retryDelay = 500;
interface User {
id: number;
name: string;
email: string;
}
interface Post {
id: number;
title: string;
body: string;
userId: number;
}
async function completeExample() {
try {
console.log("=== CSBridge API Service Example ===");
// 1. GET request with global config
console.log("\n1. Fetching users...");
const usersResponse = await apiService.get<User[]>("/users");
console.log(`Found ${usersResponse.data.length} users`);
// 2. POST request with custom retry
console.log("\n2. Creating post with custom retry...");
const newPost = await apiService.post<Post>(
"/posts",
{
title: "My Test Post",
body: "This is a test post created with CSBridge",
userId: 1,
},
{
retryOptions: {
retries: 2,
delay: 1000,
},
}
);
console.log("Created post:", newPost.data);
// 3. GET with custom timeout
console.log("\n3. Fetching specific user with custom timeout...");
const userResponse = await apiService.get<User>("/users/1", {
timeout: 10000, // 10 seconds
});
console.log("User details:", userResponse.data);
// 4. PUT request with no retry
console.log("\n4. Updating post without retry...");
const updatedPost = await apiService.put<Post>(
`/posts/${newPost.data.id}`,
{
id: newPost.data.id,
title: "Updated Title",
body: "Updated content",
userId: 1,
},
{
retry: false,
}
);
console.log("Updated post:", updatedPost.data);
// 5. DELETE request
console.log("\n5. Deleting post...");
await apiService.delete(`/posts/${newPost.data.id}`);
console.log("Post deleted successfully");
console.log("\n✅ All operations completed successfully!");
} catch (error) {
if (error instanceof ApiError) {
console.error("❌ API Error:", {
status: error.status,
message: error.message,
code: error.code,
timestamp: error.timestamp,
});
} else {
console.error("❌ Unexpected error:", error);
}
}
}
// Run the example
completeExample();TypeScript Support
CSBridge provides full TypeScript support with generic types:
// Response typing
const response = await apiService.get<User[]>("/users");
// response.data is typed as User[]
// Request/response typing
const createUser = await apiService.post<User, CreateUserRequest>("/users", userData);
// userData must match CreateUserRequest type
// response.data is typed as UserLicense
MIT
