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

niafix-utils

v1.1.4

Published

Enterprise-grade TypeScript HTTP client library with intelligent caching, OData query builder, FormData support, and comprehensive utilities for modern web development. Framework-agnostic design works seamlessly across all JavaScript/TypeScript environmen

Readme

Niafix Utils - Enterprise HTTP Client & Utilities

A production-ready, enterprise-grade TypeScript HTTP client library designed for modern web applications. Built with a modular, framework-agnostic architecture, niafix-utils provides comprehensive HTTP request management, intelligent caching, OData query building, and advanced FormData handling across all JavaScript and TypeScript environments.

Overview

niafix-utils is engineered to deliver robust, scalable API communication capabilities for enterprise applications. The library offers a clean, intuitive API while maintaining flexibility for complex use cases. Whether you're building client-side applications, server-side services, or full-stack solutions, niafix-utils seamlessly integrates into your technology stack.

Key Features

  • Enterprise-Grade HTTP Client: Type-safe, feature-rich HTTP client with comprehensive request/response handling
  • Modular Architecture: Clean separation of concerns with RequestManager, ResponseManager, and ErrorHandler
  • Intelligent Caching: Automatic GET request caching with configurable TTL and manual invalidation
  • Advanced Logging: Detailed request/response logging with environment-aware log levels for easy debugging
  • OData Query Builder: Fluent API for constructing complex OData queries with full type safety
  • Advanced FormData Support: Automatic conversion of nested objects, arrays, dates, and file uploads
  • Multi-API Management: Effortlessly manage multiple API endpoints with separate client instances
  • Server-Side Rendering (SSR) Support: Full compatibility with SSR frameworks including Next.js and SvelteKit
  • Comprehensive Error Handling: Detailed error information with status codes, messages, and request context

Installation

npm install niafix-utils
yarn add niafix-utils
pnpm add niafix-utils

Quick Start

Basic Usage

import { HttpClient } from 'niafix-utils';

// Initialize the HTTP client
const client = new HttpClient({
    baseURL: 'https://api.example.com',
    logLevel: 'debug', // Enable detailed logging for debugging
});

// Make a GET request
const response = await client.get('/users');
console.log(response.data); // Response data
console.log(response.status); // HTTP status code
console.log(response.success); // boolean

Multiple API Sources

Create separate client instances for different API endpoints:

import { HttpClient } from 'niafix-utils';

const mainAPI = new HttpClient({
    baseURL: 'https://api.main.com',
    logLevel: 'auto',
});

const authAPI = new HttpClient({
    baseURL: 'https://auth.api.com',
    logLevel: 'auto',
});

// Each client automatically uses its configured baseURL
const users = await mainAPI.get('/users');
const login = await authAPI.post('/login', credentials);

Configuration

HttpClient Configuration

const client = new HttpClient({
    // Required: Base URL for all requests
    baseURL: 'https://api.example.com',

    // Optional: Log level ('auto', 'none', 'error', 'warn', 'info', 'debug')
    // 'auto' automatically uses 'debug' in development and 'error' in production
    logLevel: 'auto',

    // Optional: Cache TTL in milliseconds (default: 300000 = 5 minutes)
    cacheTTL: 300000,

    // Optional: Default headers for all requests
    defaultHeaders: {
        'X-Custom-Header': 'value',
        'Accept-Language': 'en-US',
    },

    // Optional: Request credentials (default: 'same-origin')
    // Use 'include' only if backend allows credentials with specific origin (not wildcard *)
    credentials: 'same-origin',
});

HTTP Methods

GET Requests

// Simple GET request
const response = await client.get('/users');

// GET with query parameters
const users = await client.get('/users', {
    query: { page: 1, limit: 10 },
    headers: { 'Accept-Language': 'en-US' },
});

// Skip cache and fetch fresh data
const freshData = await client.get('/users', { skipCache: true });

// Disable cache for specific request
const noCacheData = await client.get('/users', { noCache: true });

POST Requests

// POST with JSON data
const newUser = await client.post('/users', {
    name: 'John Doe',
    email: '[email protected]',
    age: 30,
});

// POST with FormData (automatic conversion)
const userWithFile = await client.post(
    '/users',
    {
        name: 'Jane Doe',
        email: '[email protected]',
        avatar: fileObject, // File object
        tags: ['tag1', 'tag2'],
    },
    {
        useFormData: true, // Automatically converts to FormData
    }
);

PUT & PATCH Requests

// PUT - Full update
const updated = await client.put('/users/123', {
    name: 'John Updated',
    email: '[email protected]',
});

// PATCH - Partial update
const patched = await client.patch('/users/123', {
    status: 'inactive',
});

DELETE Requests

// Simple DELETE
await client.delete('/users/123');

// DELETE with query parameters
await client.delete('/users', {
    query: { status: 'inactive' },
});

Logging & Debugging

Log Levels

The library provides comprehensive logging capabilities to help you debug requests and responses:

const client = new HttpClient({
    baseURL: 'https://api.example.com',
    logLevel: 'debug', // Enable detailed logging
});

Log Levels:

  • 'debug': Full request/response details including headers, body, and timing
  • 'info': Request information without response details
  • 'warn': Only warnings
  • 'error': Only errors
  • 'none': No logging
  • 'auto': Automatically uses 'debug' in development, 'error' in production

Debug Mode

When logLevel: 'debug' is enabled, you'll see detailed logs in the console:

[DEBUG] [RequestBuilder] Request prepared {
  method: 'POST',
  url: 'https://api.example.com/users',
  headers: { 'Content-Type': 'application/json', ... },
  body: { name: 'John', email: '[email protected]' }
}

[DEBUG] [ResponseManager] Success response {
  status: 201,
  statusText: 'Created',
  contentType: 'application/json',
  headers: { ... },
  data: { id: 1, name: 'John', ... },
  dataSize: '245 chars'
}

[DEBUG] [RequestManager] Request completed in 234ms

Error Logging

Errors are automatically logged with full context:

try {
    await client.post('/users', userData);
} catch (error) {
    // Error is automatically logged with:
    // - Status code
    // - Error message
    // - Request URL and method
    // - Response headers and data
    // - Timestamp
    console.error(error);
}

OData Query Builder

Build complex OData queries with a fluent API:

import { HttpClient, ODataQueryBuilder } from 'niafix-utils';

// Using query builder
const queryBuilder = new ODataQueryBuilder()
    .filter({
        name: { contains: 'John' },
        age: { gt: 18, lt: 65 },
        status: { eq: 'active' },
    })
    .select('id', 'name', 'email')
    .top(20)
    .skip(0)
    .orderBy('createdAt', 'desc');

const response = await client.getWithOData('/users', queryBuilder);

// Or using helper functions
import { filterBy, and, or } from 'niafix-utils';

const complexQuery = new ODataQueryBuilder()
    .filter(and(filterBy('age', 'gt', 18), or(filterBy('city', 'eq', 'Istanbul'), filterBy('city', 'eq', 'Ankara'))))
    .top(20);

const users = await client.getWithOData('/users', complexQuery);

FormData Usage

Automatic FormData Conversion

// Simple FormData conversion
await client.post(
    '/upload',
    {
        file: fileObject,
        name: 'document.pdf',
        tags: ['important', 'archive'],
    },
    {
        useFormData: true, // Automatically converts to FormData
    }
);

Advanced FormData with Nested Objects

import { ObjectToFormData } from 'niafix-utils';

const formData = ObjectToFormData(
    {
        user: {
            name: 'John Doe',
            email: '[email protected]',
            profile: {
                avatar: fileObject,
                bio: 'Software developer',
            },
        },
        tags: ['tag1', 'tag2'],
        files: [file1, file2],
    },
    {
        arrayFormat: 'brackets',
        includeNull: false,
    }
);

await client.post('/upload', formData);

Cache Management

Automatic Caching

GET requests are automatically cached:

// First request - fetches from API
const users1 = await client.get('/users');

// Second request - returns from cache (if within TTL)
const users2 = await client.get('/users');

Manual Cache Control

// Clear all cache
client.clearCache();

// Get cache statistics
const stats = client.getCacheStats();
console.log(stats.size); // Number of cached entries
console.log(stats.keys); // Array of cache keys

// Invalidate cache for specific URL
client.invalidateCache('/users');

Cache Invalidation

Mutating operations automatically invalidate related cache entries:

// POST, PUT, PATCH, DELETE automatically invalidate related cache
await client.post('/users', newUser); // Invalidates /users cache
await client.put('/users/123', updatedUser); // Invalidates /users cache
await client.delete('/users/123'); // Invalidates /users cache

Authentication & Authorization

Client-Side Requests

Cookies are automatically sent via credentials: 'include':

const client = new HttpClient({
    baseURL: 'https://api.example.com',
});

// Cookies are automatically sent
const response = await client.get('/users');

CORS Configuration

Important: When using credentials: 'include', your backend must not use Access-Control-Allow-Origin: *. You must specify the exact origin:

Backend Configuration (.NET Core example):

app.UseCors(options =>
{
    options.WithOrigins("http://localhost:3001") // Specific origin, not *
           .AllowCredentials() // Required for credentials: 'include'
           .AllowAnyMethod()
           .AllowAnyHeader();
});

If you don't need cookies, you can use credentials: 'omit':

const client = new HttpClient({
    baseURL: 'https://api.example.com',
    credentials: 'omit', // No cookies sent, CORS works with *
});

Server-Side Requests

Provide cookie string explicitly:

// Next.js example
import { cookies } from 'next/headers';

const cookieStore = await cookies();
const cookieString = cookieStore
    .getAll()
    .map((c) => `${c.name}=${c.value}`)
    .join('; ');

const response = await client.get('/users', {
    cookies: cookieString,
});

Bearer Token Authentication

const response = await client.get('/users', {
    token: 'your-bearer-token-here',
});

Error Handling

Comprehensive error information is provided:

try {
    const response = await client.get('/users');
} catch (error: any) {
    console.error('Status Code:', error.statusCode);
    console.error('Message:', error.message);
    console.error('Details:', error.details);
    console.error('Config:', error.config);
    console.error('Base URL:', error.baseUrl);

    // Handle specific status codes
    switch (error.statusCode) {
        case 401:
            // Redirect to login
            window.location.href = '/login';
            break;
        case 403:
            // Access denied
            alert('Access denied');
            break;
        case 404:
            // Not found
            alert('Resource not found');
            break;
        case 500:
            // Server error
            alert('Server error occurred');
            break;
    }
}

Server-Side Rendering (SSR) Support

Next.js App Router - Server Components

// app/users/page.tsx
import { cookies } from 'next/headers';
import { HttpClient } from 'niafix-utils';

export default async function UsersPage() {
    const cookieStore = await cookies();
    const cookieString = cookieStore
        .getAll()
        .map((c) => `${c.name}=${c.value}`)
        .join('; ');

    const client = new HttpClient({
        baseURL: process.env.API_URL!,
    });

    const { data } = await client.get('/users', {
        cookies: cookieString,
    });

    return (
        <div>
            {data?.map((user) => (
                <div key={user.id}>{user.name}</div>
            ))}
        </div>
    );
}

Next.js App Router - Client Components

// app/components/UsersList.tsx
'use client';

import { HttpClient } from 'niafix-utils';
import { useEffect, useState } from 'react';

export default function UsersList() {
    const [users, setUsers] = useState([]);

    const client = new HttpClient({
        baseURL: process.env.NEXT_PUBLIC_API_URL!,
    });

    useEffect(() => {
        client.get('/users').then((response) => {
            setUsers(response.data || []);
        });
    }, []);

    return (
        <div>
            {users.map((user) => (
                <div key={user.id}>{user.name}</div>
            ))}
        </div>
    );
}

Best Practices

1. Multiple API Management

// lib/api/clients.ts
import { HttpClient } from 'niafix-utils';

export const mainAPI = new HttpClient({
    baseURL: process.env.NEXT_PUBLIC_MAIN_API_URL!,
    logLevel: 'auto',
});

export const authAPI = new HttpClient({
    baseURL: process.env.NEXT_PUBLIC_AUTH_API_URL!,
    logLevel: 'auto',
});

2. Type Safety

interface User {
    id: string;
    name: string;
    email: string;
}

interface UserResponse {
    data: User[];
    total: number;
}

const response = await client.get<UserResponse>('/users');
const users: User[] = response.data?.data || [];

3. Error Handling Wrapper

export async function handleApiRequest<T>(request: () => Promise<CustomFetchResponse<T>>): Promise<T> {
    try {
        const response = await request();
        if (response.success) {
            return response.data as T;
        }
        throw new Error('Request failed');
    } catch (error: any) {
        if (error.statusCode === 401) {
            window.location.href = '/login';
        }
        throw error;
    }
}

// Usage
const users = await handleApiRequest(() => client.get('/users'));

API Reference

HttpClient Methods

| Method | Description | Usage | | -------------------------------------- | -------------------- | --------------------- | | get<T>(url, config?) | GET request | Retrieve data | | post<T>(url, data?, config?) | POST request | Create resource | | put<T>(url, data?, config?) | PUT request | Update resource | | patch<T>(url, data?, config?) | PATCH request | Partial update | | delete<T>(url, config?) | DELETE request | Remove resource | | head<T>(url, config?) | HEAD request | Get headers | | options<T>(url, config?) | OPTIONS request | Get allowed methods | | request<T>(url, config?) | Generic request | Custom methods | | odata() | Create OData builder | Build OData queries | | getWithOData<T>(url, query, config?) | GET with OData | Execute OData query | | clearCache() | Clear all cache | Remove cached data | | getCacheStats() | Get cache stats | Monitor cache | | invalidateCache(url) | Invalidate cache | Remove specific cache |

RequestConfig Options

| Option | Type | Description | | ------------- | ------------- | ------------------- | | method | string | HTTP method | | headers | object | Custom headers | | data | any | Request body | | query | object/string | Query parameters | | cookies | string | Cookie string (SSR) | | token | string | Bearer token | | skipCache | boolean | Force fresh request | | noCache | boolean | Disable caching | | useFormData | boolean | Convert to FormData | | odataQuery | string | OData query string | | baseUrl | string | Override base URL |

License

MIT

Support

For issues, questions, or contributions, please visit our GitHub repository.