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
Maintainers
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-utilsyarn add niafix-utilspnpm add niafix-utilsQuick 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); // booleanMultiple 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 234msError 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 cacheAuthentication & 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.
