Package Exports
- csbridge
- csbridge/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (csbridge) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
CSBridge - Client-Server Bridge Utility
Overview
CSBridge is a TypeScript utility library that provides a comprehensive set of tools for handling API requests with robust error handling, retries, and status code management. It's designed to serve as a reliable bridge between client applications and backend services.
Features
- Type-Safe API: Fully typed API service with TypeScript interfaces for requests and responses
- Comprehensive Status Code Handling: Detailed mapping of HTTP status codes to human-readable messages
- Automatic Retry Logic: Configurable exponential backoff retry strategy for transient failures
- Error Standardization: Converts various error types to a standardized format using
format-the-error - Content Type Detection: Automatically parses responses based on content type (JSON, text, binary)
- Upload & Download Support: Specialized methods for file uploads and downloads
- Timeout Handling: Built-in request timeout with abort controller
- Authentication Support: Easily add authentication tokens to requests
- Consistent Error Responses: Utils module provides standardized error responses with success/error patterns
Use Cases
- Frontend Applications: Use as the primary HTTP client in React, Vue, Angular, or vanilla TypeScript applications
- Backend Services: TypeScript Node.js services can use it for communicating with other microservices
- Cross-Platform Apps: Works in any JavaScript environment with fetch support (browsers, Node.js with node-fetch)
- API Integrations: Simplify third-party API integrations with standardized error handling
Installation
npm install csbridgeBasic Usage
import apiService from "csbridge";
// GET request
const getUsers = async () => {
try {
const response = await apiService.get("/users", {
params: { limit: 10, offset: 0 },
});
return response.data;
} catch (error) {
console.error("Failed to fetch users:", error);
throw error;
}
};
// POST request with JSON body
const createUser = async (userData) => {
try {
const response = await apiService.post("/users", userData);
return response.data;
} catch (error) {
console.error("Failed to create user:", error);
throw error;
}
};
// File upload
const uploadUserAvatar = async (userId, file) => {
try {
const response = await apiService.upload(`/users/${userId}/avatar`, file, { userId, timestamp: Date.now() });
return response.data;
} catch (error) {
console.error("Failed to upload avatar:", error);
throw error;
}
};Configuration
The library uses a default configuration that can be customized:
import { API_CONFIG } from "csbridge";
// Update configuration
API_CONFIG.baseUrl = "https://api.yourservice.com";
API_CONFIG.timeout = 60000; // 60 seconds
API_CONFIG.retryCount = 3;
API_CONFIG.retryDelay = 500; // 500msAdvanced Features
Custom Retry Logic
import apiService from "csbridge";
const fetchWithCustomRetry = async () => {
const response = await apiService.get("/sensitive-data", {
retry: true,
retryOptions: {
retries: 5,
delay: 1000,
retriableStatuses: [408, 429, 500, 502, 503, 504],
},
});
return response.data;
};File Downloads
import apiService from "csbridge";
const downloadReport = async (reportId) => {
await apiService.download(`/reports/${reportId}/download`, `report-${reportId}.pdf`);
};Error Handling
The library standardizes errors for consistent handling using the format-the-error library:
import apiService from "csbridge";
const fetchData = async () => {
try {
const response = await apiService.get("/data");
return response.data;
} catch (error) {
// Standardized error with: name, message, code, status, data, timestamp
console.error(`Error ${error.status}: ${error.message}`);
// Handle specific error codes
if (error.status === 401) {
// Handle authentication error
} else if (error.status === 404) {
// Handle not found error
}
throw error;
}
};Enhanced Error Handling with Utils Module
For even more robust error handling, use the utility functions which provide standardized error responses:
import { fetchData } from "csbridge/utils";
const getData = async () => {
// No try-catch needed - errors are handled and returned in a consistent format
const response = await fetchData("/data");
if (response.success) {
return response.data;
} else {
// All errors have the same structure for consistent handling
console.error(`${response.error?.code}: ${response.error?.message}`);
// You can check the status code
if (response.error?.status === 404) {
console.log("Resource not found");
}
// Access additional error details if available
if (response.error?.details) {
console.debug("Error details:", response.error.details);
}
return null;
}
};Utility Functions
The library includes a set of higher-level utility functions in utils.ts that provide standardized responses:
import { fetchData, submitData, updateData, patchData, deleteData, uploadFiles, downloadFile, createResourceApi } from "csbridge/utils";Basic API Functions with Custom Headers
Here are examples of using each utility function with custom headers and options:
// Define a type for type safety
interface User {
id: number;
name: string;
email: string;
}
// Custom headers example
const customHeaders = {
"X-API-Key": "your-api-key",
"X-Tenant-ID": "tenant-123",
"Accept-Language": "en-US",
};
// GET: Fetch data with params and custom headers
const fetchUsersWithHeaders = async () => {
const response = await fetchData<User[]>("/users", {
params: { limit: 20, role: "admin" },
headers: customHeaders,
timeout: 10000, // 10 seconds
});
if (response.success) {
console.log(`Found ${response.data?.length} users`);
return response.data;
} else {
console.error(`Error ${response.error?.status}: ${response.error?.message}`);
return null;
}
};
// POST: Create a new resource with custom headers
const createUserWithHeaders = async (userData: Partial<User>) => {
const response = await submitData<User, Partial<User>>("/users", userData, {
headers: customHeaders,
retry: true,
retryOptions: { retries: 3 },
});
if (response.success) {
console.log(`User created with ID: ${response.data?.id}`);
return response.data;
} else {
console.error(`Failed to create user: ${response.error?.message}`);
return null;
}
};
// PUT: Update a resource completely with custom headers
const updateUserWithHeaders = async (userId: number, userData: User) => {
const response = await updateData<User, User>(`/users/${userId}`, userData, {
headers: customHeaders,
});
if (response.success) {
console.log(`User ${userId} updated successfully`);
return response.data;
} else {
console.error(`Failed to update user: ${response.error?.message}`);
return null;
}
};
// PATCH: Update a resource partially with custom headers
const patchUserWithHeaders = async (userId: number, partialData: Partial<User>) => {
const response = await patchData<User, Partial<User>>(`/users/${userId}`, partialData, {
headers: customHeaders,
});
if (response.success) {
console.log(`User ${userId} patched successfully`);
return response.data;
} else {
console.error(`Failed to patch user: ${response.error?.message}`);
return null;
}
};
// DELETE: Remove a resource with custom headers
const deleteUserWithHeaders = async (userId: number) => {
const response = await deleteData(`/users/${userId}`, {
headers: customHeaders,
});
if (response.success) {
console.log(`User ${userId} deleted successfully`);
return true;
} else {
console.error(`Failed to delete user: ${response.error?.message}`);
return false;
}
};
// UPLOAD: Upload files with custom headers
const uploadUserAvatarWithHeaders = async (userId: number, file: File) => {
const response = await uploadFiles<{ avatarUrl: string }>(
`/users/${userId}/avatar`,
file,
// Optional metadata
{ userId, timestamp: Date.now() },
// Request options
{ headers: customHeaders }
);
if (response.success) {
console.log(`Avatar uploaded successfully: ${response.data?.avatarUrl}`);
return response.data?.avatarUrl;
} else {
console.error(`Failed to upload avatar: ${response.error?.message}`);
return null;
}
};
// DOWNLOAD: Download files with custom headers
const downloadReportWithHeaders = async (reportId: number) => {
const response = await downloadFile(`/reports/${reportId}`, `report-${reportId}.pdf`, { headers: customHeaders });
if (response.success) {
console.log(`Report downloaded successfully`);
return true;
} else {
console.error(`Failed to download report: ${response.error?.message}`);
return false;
}
};Resource API Factory with Custom Headers
You can also use the resource API factory with custom headers and options:
// Define your resource type for type safety
interface UserType {
id: number;
name: string;
email: string;
role: string;
}
// Create a typed API for the users resource
const usersApi = createResourceApi<UserType>("/users");
// Define default options with headers to use across multiple calls
const defaultOptions = {
headers: {
"X-API-Key": "your-api-key",
"X-Tenant-ID": "tenant-123",
},
};
// Then use these strongly-typed CRUD operations with headers
const createNewUser = async (userData) => {
const response = await usersApi.create(userData, defaultOptions);
return response.success ? response.data : null;
};
const getUsers = async () => {
// Get a list of users with pagination and headers
const response = await usersApi.list({ limit: 20, offset: 0 }, defaultOptions);
return response.success ? response.data : [];
};
const getUser = async (userId) => {
// Get a specific user by ID with headers
const response = await usersApi.getById(userId, defaultOptions);
return response.success ? response.data : null;
};
const updateUser = async (userId, userData) => {
// Use update for a full resource replacement with headers
const response = await usersApi.update(userId, userData, defaultOptions);
return response.success ? response.data : null;
};
const patchUser = async (userId, partialData) => {
// Use patch for partial updates with headers
const response = await usersApi.patch(userId, partialData, defaultOptions);
return response.success ? response.data : null;
};
const removeUser = async (userId) => {
// Delete a resource with headers
const response = await usersApi.remove(userId, defaultOptions);
return response.success;
};Resource API Factory
The createResourceApi function creates a complete set of CRUD operations for a specific resource type, making it easy to work with REST APIs in a type-safe way:
// Define your resource type for type safety
interface UserType {
id: number;
name: string;
email: string;
role: string;
}
// Create a typed API for the users resource
const usersApi = createResourceApi<UserType>("/users");This factory provides these methods:
| Method | Description | Example Usage |
|---|---|---|
list(params?, options?) |
Get all resources with optional filtering | usersApi.list({ limit: 20, offset: 0 }, { headers }) |
getById(id, options?) |
Get a specific resource by ID | usersApi.getById(123, { headers }) |
create(data, options?) |
Create a new resource | usersApi.create({ name: "John" }, { headers }) |
update(id, data, options?) |
Replace a resource completely | usersApi.update(123, userObject, { headers }) |
patch(id, data, options?) |
Update a resource partially | usersApi.patch(123, { name: "Updated Name" }, { headers }) |
remove(id, options?) |
Delete a resource | usersApi.remove(123, { headers }) |
All methods accept optional API request options, including custom headers, timeout settings, and retry options. They return responses in the standardized format with proper typing.
API Request Options
All utility functions accept an options object that can include:
interface ApiRequestOptions {
headers?: Record<string, string>; // Custom HTTP headers
params?: Record<string, any>; // URL query parameters
timeout?: number; // Request timeout in milliseconds
retry?: boolean; // Enable/disable retry logic
retryOptions?: {
retries?: number; // Maximum number of retries (default: 3)
delay?: number; // Initial delay in milliseconds (default: 500)
retriableStatuses?: number[]; // HTTP status codes to retry on
};
}Standardized Response Format
All utility functions return a consistent response format:
interface StandardResponse<T> {
success: boolean; // Indicates if the request was successful
data: T | null; // The response data (when success is true)
error: {
// Error details (when success is false)
message: string; // Human-readable error message
code?: string; // Error code for programmatic handling
status?: number; // HTTP status code
details?: unknown; // Additional error details like stack trace
} | null;
meta?: {
// Optional metadata
timestamp: string; // Request timestamp
requestId?: string; // Request ID for tracing
pagination?: {
// Pagination details if applicable
page: number;
pageSize: number;
totalItems: number;
totalPages: number;
};
};
}License
MIT