JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 10
  • Score
    100M100P100Q45404F
  • License MIT

A TypeScript utility library for handling API requests with robust error handling

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 - 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 ApiError class 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 csbridge

Configuration 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: "john@example.com",
    });
    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 request
  • post<T, D>(url, data?, options?) - POST request
  • put<T, D>(url, data?, options?) - PUT request
  • patch<T, D>(url, data?, options?) - PATCH request
  • delete<T>(url, options?) - DELETE request
  • upload<T>(url, file, options?) - File upload
  • download(url, options?) - File download

Configuration Methods

  • setBaseUrl(url) - Set the base URL for all requests
  • setDefaultHeaders(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 User

License

MIT