npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@unidev-hub/api-client

v1.0.66

Published

API client library for Unidev Hub applications using the Fetch API

Readme

@unidev-hub/api-client

A comprehensive, feature-rich API client library for JavaScript and TypeScript applications that provides a clean, consistent, and developer-friendly way to interact with RESTful APIs.

npm version npm downloads License

Table of Contents

Features

  • 🚀 HTTP Client: Powerful, configurable HTTP client with built-in interceptors
  • 🧩 Resource-Based: CRUD operations and custom methods for API resources
  • 🔐 Authentication: Token management, auth headers, and refresh token handling
  • Error Handling: Consistent error normalization and retry mechanisms
  • 📦 Caching: In-memory and persistent caching with invalidation strategies
  • 📝 Logging: Configurable request/response logging and performance metrics
  • 🛠️ Request Builders: Fluent query parameter and payload builders
  • 🧪 Mocking: Mock API responses for testing and development
  • 📊 Metrics: Performance tracking and analysis
  • 📝 TypeScript: Full TypeScript support with comprehensive type definitions

Installation

# Using npm
npm install @unidev-hub/api-client

# Using yarn
yarn add @unidev-hub/api-client

# Using pnpm
pnpm add @unidev-hub/api-client

Quick Start

Basic Usage

import { BaseApiClient } from '@unidev-hub/api-client';

// Create an API client
const apiClient = new BaseApiClient({
  baseURL: 'https://api.example.com',
});

// Make requests
async function fetchData() {
  try {
    // GET request
    const users = await apiClient.get('/users');
    console.log(users.data);
    
    // POST request
    const newUser = await apiClient.post('/users', {
      name: 'John Doe',
      email: '[email protected]',
    });
    console.log(newUser.data);
    
    // PUT request
    const updatedUser = await apiClient.put('/users/1', {
      name: 'John Smith',
    });
    console.log(updatedUser.data);
    
    // DELETE request
    await apiClient.delete('/users/1');
  } catch (error) {
    console.error('API Error:', error.message);
  }
}

Using Resource Client

import { BaseApiClient, ResourceClient } from '@unidev-hub/api-client';

// Define your resource type
interface User {
  id: number;
  name: string;
  email: string;
}

// Create the base client
const apiClient = new BaseApiClient({
  baseURL: 'https://api.example.com',
});

// Create a resource client
const usersClient = new ResourceClient<User>(apiClient, '/users');

// Use resource methods
async function manageUsers() {
  try {
    // Get all users
    const users = await usersClient.list();
    console.log(users.data);
    
    // Get a specific user
    const user = await usersClient.get(1);
    console.log(user.data);
    
    // Create a new user
    const newUser = await usersClient.create({
      name: 'Jane Doe',
      email: '[email protected]',
    });
    console.log(newUser.data);
    
    // Update a user
    const updatedUser = await usersClient.update(1, {
      name: 'Jane Smith',
    });
    console.log(updatedUser.data);
    
    // Delete a user
    await usersClient.delete(1);
  } catch (error) {
    console.error('Resource Error:', error.message);
  }
}

Core Components

BaseApiClient

The BaseApiClient is the foundation of the library, providing HTTP request functionality with built-in support for authentication, error handling, caching, and more.

import { BaseApiClient } from '@unidev-hub/api-client';

const apiClient = new BaseApiClient({
  baseURL: 'https://api.example.com',
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  // Enable caching
  cacheConfig: {
    enabled: true,
    ttl: 300000, // 5 minutes
  },
  // Configure retries
  retryConfig: {
    maxRetries: 3,
    retryDelay: 1000,
    exponentialBackoff: true,
  },
  // Configure logging
  logConfig: {
    enabled: true,
    logLevel: 'info',
  },
});

// HTTP methods
apiClient.get('/endpoint');
apiClient.post('/endpoint', data);
apiClient.put('/endpoint', data);
apiClient.patch('/endpoint', data);
apiClient.delete('/endpoint');
apiClient.request({ method: 'GET', url: '/endpoint' });

ResourceClient

The ResourceClient provides CRUD operations and custom methods for specific API resources.

import { ResourceClient } from '@unidev-hub/api-client';

// Create a resource client
const productsClient = new ResourceClient(apiClient, '/products', {
  idField: 'productId', // Optional custom ID field (default: 'id')
  transformResponse: (data) => {
    // Optional response transformation
    return {
      ...data,
      price: parseFloat(data.price), // Convert string to number
    };
  },
});

// CRUD operations
productsClient.list(); // GET /products
productsClient.get(123); // GET /products/123
productsClient.create({ name: 'Product', price: 9.99 }); // POST /products
productsClient.update(123, { price: 19.99 }); // PUT /products/123
productsClient.patch(123, { price: 19.99 }); // PATCH /products/123
productsClient.delete(123); // DELETE /products/123

// Custom actions
productsClient.executeAction('publish', { date: '2023-01-01' }, 123); // POST /products/123/publish
productsClient.executeQuery('featured', { limit: 5 }); // GET /products/featured?limit=5

Configuration

The library provides extensive configuration options with sensible defaults.

import { BaseApiClient, DEFAULT_CONFIG } from '@unidev-hub/api-client';

// Use default config as a base
console.log(DEFAULT_CONFIG);

// Create client with custom config
const apiClient = new BaseApiClient({
  baseURL: 'https://api.example.com',
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-API-Key': 'your-api-key',
  },
  retryConfig: {
    maxRetries: 3,
    retryDelay: 1000,
    retryStatusCodes: [408, 429, 500, 502, 503, 504],
    exponentialBackoff: true,
  },
  cacheConfig: {
    enabled: true,
    ttl: 300000, // 5 minutes
    persistent: true, // Use localStorage when available
  },
  logConfig: {
    enabled: true,
    logLevel: 'info', // 'error' | 'warn' | 'info' | 'debug'
    maskedHeaders: ['authorization', 'x-api-key'], // Sensitive headers to mask in logs
  },
  authConfig: {
    enabled: true,
    scheme: 'Bearer',
    refreshTokenEndpoint: '/auth/refresh',
    persistTokens: true,
  },
  mockConfig: {
    enabled: false,
    latency: { min: 50, max: 300 },
    errorRate: 0,
  },
});

Interceptors

Interceptors allow you to customize request and response handling.

import { 
  addCustomHeadersInterceptor, 
  addTimingInterceptor 
} from '@unidev-hub/api-client';

// Add custom interceptors to your client's axios instance
addCustomHeadersInterceptor(apiClient.axiosInstance, { 
  'X-Custom-Header': 'value'
});

addTimingInterceptor(apiClient.axiosInstance);

Authentication

The library provides comprehensive authentication utilities, including token management and automatic refresh.

import { BaseApiClient, TokenManager } from '@unidev-hub/api-client';

// Create a token manager
const tokenManager = new TokenManager({
  enabled: true,
  scheme: 'Bearer',
  persistTokens: true, // Store in localStorage
});

// Create an API client with auth config
const apiClient = new BaseApiClient({
  baseURL: 'https://api.example.com',
  authConfig: {
    enabled: true,
    scheme: 'Bearer',
    refreshTokenEndpoint: '/auth/refresh',
  },
});

// Login and store tokens
async function login(username: string, password: string) {
  const response = await apiClient.post('/auth/login', {
    username,
    password,
  });
  
  // Store tokens
  tokenManager.setTokens({
    accessToken: response.data.accessToken,
    refreshToken: response.data.refreshToken,
    accessTokenExpiresIn: response.data.expiresIn,
  });
  
  return response.data;
}

// Logout
function logout() {
  tokenManager.clearTokens();
}

// Get access token
const token = tokenManager.getAccessToken();

// Check if token is expired
const isExpired = tokenManager.isAccessTokenExpired();

Error Handling

The library provides consistent error handling with a custom ApiError class.

import { ApiError } from '@unidev-hub/api-client';

try {
  const response = await apiClient.get('/users/999');
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.message);
    console.error('Status:', error.status);
    console.error('Error Code:', error.code);
    console.error('Details:', error.details);
  } else {
    console.error('Unexpected error:', error);
  }
}

// Creating custom errors
throw ApiError.notFound('User not found');
throw ApiError.unauthorized('Invalid token');
throw ApiError.validation('Validation failed', { field: ['Error message'] });

Caching

The library includes flexible caching capabilities with different storage options.

import { 
  cacheResponse, 
  getCachedResponse, 
  clearCache, 
  invalidateResourceCache 
} from '@unidev-hub/api-client';

// The BaseApiClient handles caching automatically when enabled in config
// But you can also use the caching utilities directly:

// Cache a response
await cacheResponse('users/list', data, 60000); // 1 minute TTL

// Get a cached response
const cached = await getCachedResponse('users/list');

// Clear all cache
await clearCache();

// Invalidate cache for a specific resource
invalidateResourceCache('/users', 123); // Invalidate specific user
invalidateResourceCache('/users'); // Invalidate all users

Logging and Metrics

The library includes comprehensive logging and performance metrics.

import { 
  configureLogger, 
  getPerformanceReport, 
  getAverageResponseTime 
} from '@unidev-hub/api-client';

// Configure logging
configureLogger({
  enabled: true,
  logLevel: 'debug',
  customLogger: (level, message, data) => {
    // Custom logging implementation
    myLogger.log(level, message, data);
  },
});

// Get performance metrics
const avgTime = getAverageResponseTime('/users');
const report = getPerformanceReport();

console.log(`Average response time: ${avgTime}ms`);
console.log('Performance report:', report);

Request Builders

The library provides fluent builders for query parameters and request payloads.

import { QueryBuilder, PayloadBuilder } from '@unidev-hub/api-client';

// Build query parameters
const query = new QueryBuilder()
  .filter({ 
    status: 'active',
    category: 'electronics',
    price: { gt: 100, lte: 500 },
  })
  .sort({ createdAt: 'desc', name: 'asc' })
  .paginate({ page: 2, pageSize: 25 })
  .search('phone', ['name', 'description'])
  .select(['id', 'name', 'price', 'category'])
  .include(['manufacturer', 'reviews'])
  .build();

// Result: { status: 'active', category: 'electronics', price_gt: 100, price_lte: 500, sort: '-createdAt,name', page: 2, pageSize: 25, q: 'phone', searchFields: 'name,description', fields: 'id,name,price,category', include: 'manufacturer,reviews' }

// Build request payload
const payload = new PayloadBuilder()
  .field('name', 'Product Name')
  .field('price', 99.99)
  .field('categories', ['electronics', 'gadgets'])
  .setNestedField('metadata.published', true)
  .setNestedField('metadata.featured', false)
  .build();

// Result: { name: 'Product Name', price: 99.99, categories: ['electronics', 'gadgets'], metadata: { published: true, featured: false } }

// Use in API requests
await apiClient.get('/products', { params: query });
await apiClient.post('/products', payload);

Mocking

The library includes powerful mocking capabilities for testing and development.

import { MockApiClient } from '@unidev-hub/api-client';

// Create a mock client
const mockClient = new MockApiClient({
  latency: { min: 100, max: 500 },
  errorRate: 0.1, // 10% random error rate
});

// Define a resource schema
mockClient.registerResource('users', {
  idField: 'id',
  onCreate: (user) => {
    // Auto-generate fields
    user.createdAt = new Date().toISOString();
  },
  onUpdate: (user) => {
    user.updatedAt = new Date().toISOString();
  },
});

// Seed with initial data
mockClient.seedData('users', [
  { id: 1, name: 'John Doe', email: '[email protected]' },
  { id: 2, name: 'Jane Smith', email: '[email protected]' },
]);

// Create a mock resource client
const usersClient = mockClient.resource('users');

// Use like a real API client
const users = await usersClient.list();
const user = await usersClient.get(1);
const newUser = await usersClient.create({ name: 'Alice', email: '[email protected]' });

Advanced Usage

Environment-specific Configuration

import { getEnvironmentConfig } from '@unidev-hub/api-client';

const baseConfig = {
  timeout: 30000,
  environments: {
    development: {
      baseURL: 'http://localhost:3000/api',
      logConfig: { logLevel: 'debug' },
    },
    staging: {
      baseURL: 'https://staging-api.example.com',
      logConfig: { logLevel: 'info' },
    },
    production: {
      baseURL: 'https://api.example.com',
      logConfig: { logLevel: 'error' },
      cacheConfig: { enabled: true, ttl: 600000 },
    },
  },
};

// Get config for current environment
const config = getEnvironmentConfig(baseConfig, process.env.NODE_ENV);

// Create client with environment config
const apiClient = new BaseApiClient(config);

Custom Resource Actions

// Define a resource client for products
const productsClient = new ResourceClient(apiClient, '/products');

// Execute custom actions on a resource
async function publishProduct(productId: number, publishDate: string) {
  return productsClient.executeAction('publish', { publishDate }, productId);
  // Sends: POST /products/{productId}/publish
}

// Execute custom queries
async function getFeaturedProducts(limit: number) {
  return productsClient.executeQuery('featured', { limit });
  // Sends: GET /products/featured?limit={limit}
}

TypeScript Support

The library is written in TypeScript and provides comprehensive type definitions.

import { 
  BaseApiClient, 
  ResourceClient, 
  ApiResponse, 
  RequestOptions 
} from '@unidev-hub/api-client';

// Define your resource types
interface Product {
  id: number;
  name: string;
  price: number;
  createdAt: string;
}

interface CreateProductDto {
  name: string;
  price: number;
}

// Create typed resource client
const productsClient = new ResourceClient<Product, number>(apiClient, '/products');

// Methods now have proper typing
async function getProducts(options?: RequestOptions): Promise<ApiResponse<Product[]>> {
  return productsClient.list(options);
}

async function createProduct(data: CreateProductDto): Promise<ApiResponse<Product>> {
  return productsClient.create(data);
}

Examples

The library includes a variety of examples to help you get started:

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.