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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@orderly.network/vaults

v2.8.6

Published

## Request API

Downloads

2,236

Readme

Vaults Package

Request API

This package provides a robust and feature-rich HTTP client for making API requests. The optimized request module includes advanced features like retry logic, timeout handling, request/response interceptors, and comprehensive error handling.

Features

  • 🔄 Automatic Retry Logic: Configurable retry attempts with exponential backoff
  • ⏱️ Timeout Support: Request timeout with automatic cancellation
  • 🔧 Request/Response Interceptors: Middleware for request and response processing
  • 🎯 Type Safety: Full TypeScript support with generic types
  • 🚨 Enhanced Error Handling: Structured error responses with codes and status
  • 📦 Multiple HTTP Methods: GET, POST, PUT, DELETE, PATCH convenience methods
  • 🔗 Base URL Support: Automatic URL construction with base URL
  • 📊 Response Validation: Configurable status code validation
  • 🔍 Smart Query Parameters: Automatic query string building with undefined value filtering

Basic Usage

All methods now use a single configuration object for maximum simplicity and consistency:

import { request, RequestClient } from "./api/request";
import client from "./api/request";

// Simple GET request
const user = await client.get<User>("/api/users/1");

// GET with query parameters
const users = await client.get<User[]>("/api/users", {
  params: { page: 1, limit: 10, status: "active" },
});

// POST with data
const newUser = await client.post<User>("/api/users", {
  data: { name: "John Doe", email: "[email protected]" },
});

// PUT with data and custom config
const updatedUser = await client.put<User>("/api/users/1", {
  data: { name: "Jane Doe" },
  timeout: 8000,
  retry: 1,
});

// DELETE with config
await client.delete("/api/users/1", {
  timeout: 5000,
});

Complete Configuration Example

// All options in a single, clear object
const data = await client.get<UserData[]>("/api/users", {
  baseURL: "https://api.example.com",
  params: {
    page: 1,
    limit: 10,
    status: "active",
    search: undefined, // Automatically filtered out
  },
  timeout: 10000,
  retry: 2,
  headers: {
    Authorization: "Bearer token123",
  },
});

Configuration Object Structure

The simplified API uses a single configuration object with these fields:

interface SimpleRequestConfig {
  // Request data (for POST/PUT/PATCH)
  data?: any;

  // Query parameters (flexible - accepts any object with string keys)
  params?: Record<string, unknown>;

  // API configuration
  baseURL?: string;
  timeout?: number;
  retry?: number;
  retryDelay?: number;

  // Standard fetch options
  headers?: HeadersInit;
  signal?: AbortSignal;
  cache?: RequestCache;
  credentials?: RequestCredentials;
  // ... other standard RequestInit options
}

Parameter Handling

The params field is flexible and can accept:

  • Simple key-value objects: { page: 1, status: 'active' }
  • Typed parameter objects: { vault_id: 'abc', time_range: '30d' }
  • Mixed types: { id: 123, enabled: true, name: 'test' }
  • Objects will be automatically flattened and undefined values filtered out

Always use the params field for query parameters - never mix them with config options!

Advanced Configuration

import { RequestClient } from "./api/request";

// Create a custom client instance
const apiClient = new RequestClient();

// Configure default settings
const data = await apiClient.request<ApiResponse>("/api/data", {
  timeout: 5000, // 5 second timeout
  retry: 2, // Retry 2 times on failure
  retryDelay: 2000, // Wait 2 seconds between retries
  baseURL: "https://api.example.com",
  headers: {
    Authorization: "Bearer token123",
    "X-Custom-Header": "value",
  },
});

Request Interceptors

// Add authentication header automatically
apiClient.addRequestInterceptor(async (config) => {
  const token = await getAuthToken();
  return {
    ...config,
    headers: {
      ...config.headers,
      Authorization: `Bearer ${token}`,
    },
  };
});

// Add request logging
apiClient.addRequestInterceptor((config) => {
  console.log("Making request to:", config.url);
  return config;
});

Response Interceptors

// Transform response data
apiClient.addResponseInterceptor(async (response, data) => {
  // Add timestamp to all responses
  return {
    ...data,
    timestamp: Date.now(),
  };
});

// Handle global error logging
apiClient.addResponseInterceptor(async (response, data) => {
  if (!response.ok) {
    console.error("Request failed:", response.status, data);
  }
  return data;
});

Error Handling

import { VaultsApiError } from "./api/request";

try {
  const data = await client.get("/api/data");
} catch (error) {
  if (error instanceof VaultsApiError) {
    console.error("API Error:", {
      message: error.message,
      code: error.code,
      status: error.status,
      response: error.response,
    });
  } else {
    console.error("Network or other error:", error);
  }
}

Custom Validation

// Only accept 2xx status codes
const data = await client.request("/api/data", {
  validateStatus: (status) => status >= 200 && status < 300,
});

// Accept 404 as valid (useful for optional resources)
const optionalData = await client.request("/api/optional-data", {
  validateStatus: (status) => (status >= 200 && status < 300) || status === 404,
});

Working with Different Response Formats

The client automatically handles the standard { success: boolean, data: any, message?: string } format used by Orderly APIs, but also works with any JSON response format.

// Standard Orderly API response
interface StandardResponse {
  success: boolean;
  data: UserData;
  message?: string;
}

// The client will automatically extract the 'data' field
const userData = await client.get<UserData>("/api/users/1");

// For non-standard responses, the full response is returned
const customResponse = await client.get<CustomApiResponse>("/api/custom");

Integration with Existing Hooks

This request client is designed to work seamlessly with the existing useApiUrl hook:

import client from "../api/request";
import { useApiUrl } from "../hooks/useApiUrl";

function useVaultsData() {
  const apiUrl = useApiUrl();

  const fetchVaults = async () => {
    return client.get("/api/vaults", {
      baseURL: apiUrl,
    });
  };

  return { fetchVaults };
}

Migration from Old Request Function

The new implementation is backward compatible. If you were using:

// Old usage
const data = await request<UserData>("/api/users", { method: "GET" });

This will continue to work exactly as before. For new code, consider using the enhanced features:

// New enhanced usage
const data = await client.get<UserData>("/api/users", {
  timeout: 5000,
  retry: 2,
});

Best Practices

  1. Use the default client for simple requests
  2. Create custom client instances for different APIs or when you need different default configurations
  3. Add interceptors at the application level for cross-cutting concerns like authentication
  4. Handle VaultsApiError specifically for better error UX
  5. Set appropriate timeouts based on your API's expected response times
  6. Use retry sparingly - only for idempotent operations
  7. Leverage TypeScript for better development experience and runtime safety