wolfdog-request-manager
v4.1.1
Published
Universal HTTP request manager with TypeScript support and configurable environment support
Maintainers
Readme
wolfdog-request-manager
Universal HTTP request manager with TypeScript support and customizable error handling for web and React Native applications.
Features
- 🌐 Universal: Works in both browser and React Native environments
- 📝 TypeScript: Full TypeScript support with type safety
- 🔧 Configurable: Customizable error handling and storage
- 🗄️ Smart Storage: Configurable storage (localStorage/AsyncStorage/custom)
- 📁 File Upload: Built-in support for file uploads with size validation
- 🚫 Request Cancellation: Support for canceling requests
- 📊 Response Mapping: Flexible response data mapping with default values
- 🐛 Error Logging: Built-in error logging and handling
Installation
Using npm
npm install wolfdog-request-managerUsing yarn
yarn add wolfdog-request-managerSetup for 
For React Native projects, you'll also need to install the peer dependency:
Using npm:
npm install @react-native-async-storage/async-storageUsing yarn:
yarn add @react-native-async-storage/async-storageImport Options
The library provides multiple ways to import and use its functionality:
Option 1: Using the main RequestManager object (recommended)
import { RequestManager } from 'wolfdog-request-manager';
// All utilities are available through RequestManager
RequestManager.configure({
serverUrl: 'https://api.example.com',
environment: 'browser'
});
const result = await RequestManager.performRequest(/* ... */);
RequestManager.LogsHelper.clearLogs();
RequestManager.ErrorHandler.handleErrors(error);Option 2: Named imports for specific utilities
import {
RequestManager,
configure,
LogsHelper,
ErrorHandler
} from 'wolfdog-request-manager';
configure({
serverUrl: 'https://api.example.com',
environment: 'browser'
});
const result = await RequestManager.performRequest(/* ... */);
LogsHelper.clearLogs();Option 3: Default import
import RequestManager from 'wolfdog-request-manager';
RequestManager.configure({
serverUrl: 'https://api.example.com',
environment: 'browser'
});
const result = await RequestManager.performRequest(/* ... */);Quick Start
1. Configure the library
import { RequestManager } from 'wolfdog-request-manager';
RequestManager.configure({
serverUrl: 'https://api.example.com',
environment: 'browser' // or 'react-native'
});2. Make your first request
import { RequestManager } from 'wolfdog-request-manager';
// Define the expected response structure
interface UserResponse {
id: number;
name: string;
email: string;
}
// Make a GET request
const result = await RequestManager.performRequest<UserResponse>({
type: 'GET',
url: '/users/1',
errorOptions: {
defaultEnd: 'fetching user data'
},
responseData: {
id: { defaultValue: 0 },
name: { defaultValue: '', path: 'user.name' },
email: { defaultValue: '', path: 'user.email' }
}
});
if (result.ok) {
console.log('User:', result.data);
} else {
console.error('Error:', result.message);
}API Reference
RequestManager.performRequest(props)
Performs an HTTP request with the specified configuration.
Parameters
type: HTTP method ('GET'|'POST'|'PUT'|'PATCH'|'DELETE')url: Request URL (relative to configured serverUrl)errorOptions: Error handling configurationresponseData: Response data mapping configurationquery?: Query parameters objectbody?: Request body (for POST/PUT/PATCH requests)contentType?: Content type ('application/json'|'multipart/form-data')logResponse?: Enable response logging (logs with[RESPONSE]prefix)logFormData?: Enable FormData logging (useful for debugging file uploads)cancelToken?: Enable request cancellationmaxFileSizeInMb?: Maximum file size for uploads
Response
Returns a Promise that resolves to:
{
ok: boolean; // Request success status
status: number; // HTTP status code
message: string; // Success/error message
isNetworkError: boolean; // Network error indicator
data: T; // Mapped response data
requestData: {
url: string; // Final request URL
}
}Usage Examples
GET Request with Query Parameters
const result = await RequestManager.performRequest({
type: 'GET',
url: '/users',
query: {
page: 1,
limit: 10,
search: 'john'
},
errorOptions: {
defaultEnd: 'fetching users'
},
responseData: {
users: { defaultValue: [], path: 'data' },
total: { defaultValue: 0, path: 'meta.total' }
}
});POST Request with JSON Body
const result = await RequestManager.performRequest({
type: 'POST',
url: '/users',
contentType: 'application/json',
logResponse: true, // Logs response with [RESPONSE] prefix
body: {
name: 'John Doe',
email: '[email protected]'
},
errorOptions: {
defaultEnd: 'creating user',
on409: 'User with this email already exists'
},
responseData: {
user: { defaultValue: null, path: 'data' }
}
});Note: Setting logResponse: true will log the response data to console with [RESPONSE] prefix, helpful for debugging API responses.
File Upload
const result = await RequestManager.performRequest({
type: 'POST',
url: '/upload',
contentType: 'multipart/form-data',
maxFileSizeInMb: 10,
logFormData: true, // Enable to see FormData contents in console
body: {
file: {
localUrl: '/path/to/file.jpg',
size: 1024000,
type: 'image/jpeg'
},
description: 'Profile picture'
},
errorOptions: {
defaultEnd: 'uploading file'
},
responseData: {
fileUrl: { defaultValue: '', path: 'url' }
}
});Note: Setting logFormData: true will log all FormData entries to the console, which is helpful for debugging file uploads and form submissions.
Custom Response Data Mapping
const result = await RequestManager.performRequest({
type: 'GET',
url: '/user/profile',
errorOptions: {
defaultEnd: 'fetching profile'
},
responseData: {
// Simple path mapping
id: { defaultValue: 0, path: 'user.id' },
// Custom transformation function
displayName: {
defaultValue: 'Unknown User',
valueFromFunction: (data) => `${data.user.firstName} ${data.user.lastName}`
},
// Root level data
isActive: { defaultValue: false }
}
});JWT Management Functions
RequestManager.JWT.setJWT(token)
Sets the JWT token for authentication.
RequestManager.JWT.setJWT('your-jwt-token');
RequestManager.JWT.setJWT('Bearer your-jwt-token'); // Bearer prefix optional
RequestManager.JWT.setJWT(null); // Clear tokenRequestManager.JWT.getJWT()
Returns the currently set JWT token.
const token = RequestManager.JWT.getJWT(); // string | nullRequestManager.JWT.clearJWT()
Clears the currently set JWT token.
RequestManager.JWT.clearJWT();Alternative imports:
import { setJWT, getJWT, clearJWT } from 'wolfdog-request-manager';
setJWT('token');
const token = getJWT();
clearJWT();RequestManager.JWT.setJWTInStorage(token)
Saves JWT token to persistent storage.
await RequestManager.JWT.setJWTInStorage('your-jwt-token');
await RequestManager.JWT.setJWTInStorage(null); // Remove from storageRequestManager.JWT.getJWTFromStorage()
Retrieves JWT token from persistent storage.
const token = await RequestManager.JWT.getJWTFromStorage(); // string | nullRequestManager.JWT.clearJWTFromStorage()
Clears JWT token from persistent storage.
await RequestManager.JWT.clearJWTFromStorage();RequestManager.JWT.clearJWTFromStorage()
Removes JWT token from persistent storage.
await RequestManager.JWT.clearJWTFromStorage();Alternative imports for storage functions:
import { setJWTInStorage, getJWTFromStorage, clearJWTFromStorage } from 'wolfdog-request-manager';
await setJWTInStorage('token');
const token = await getJWTFromStorage();
await clearJWTFromStorage();Configuration
Global Configuration
import { configure, appConfig } from 'wolfdog-request-manager';
// Set configuration
configure({
serverUrl: 'https://api.example.com'
});
// Access current configuration
console.log(appConfig.serverUrl);
// Update serverUrl directly
appConfig.serverUrl = 'https://new-api.example.com';Custom Messages Configuration
You can customize all error and system messages used by the library:
import { configure } from 'wolfdog-request-manager';
// Configure with custom messages (e.g., Polish)
configure({
serverUrl: 'https://api.example.com',
messages: {
defaultError: 'Coś poszło nie tak. Spróbuj ponownie później.',
networkError: 'Brak połączenia z serwerem. Spróbuj ponownie później.',
loginError: 'Błąd logowania. Spróbuj uruchomić aplikację ponownie.',
serverError: 'Wystąpiła awaria serwera',
objectExists: 'Taki obiekt już istnieje',
notFound: 'Nie znaleziono',
accessDenied: 'Nie możesz tego zrobić',
requestCanceled: 'Anulowano żądanie',
fileTooLarge: 'Plik jest za duży. Maksymalny rozmiar to {maxSize}MB.',
successNoData: 'Sukces - nie zwrócono danych',
success: 'sukces',
somethingWentWrongDuring: 'Coś poszło nie tak podczas {action}'
}
});Customizable messages:
defaultError- Generic error messagenetworkError- Network connection errorsloginError- Authentication errorsserverError- 500 status errorsobjectExists- 409 conflict errorsnotFound- 404 errorsaccessDenied- 403 forbidden errorsrequestCanceled- Canceled request messagesfileTooLarge- File upload size errors (supports{maxSize}parameter)successNoData- Success with no response datasuccess- Generic success messagesomethingWentWrongDuring- Contextual error messages (supports{action}parameter)
Partial configuration:
import { configure } from 'wolfdog-request-manager';
// You can configure only specific messages
configure({
serverUrl: 'https://api.example.com',
messages: {
defaultError: 'Wystąpił błąd',
networkError: 'Brak internetu',
notFound: 'Nie znaleziono zasobu'
// Other messages will use English defaults
}
});Using parameterized messages:
Some messages support parameters (marked with {paramName}):
import { formatMessage } from 'wolfdog-request-manager';
const message = formatMessage('File too large. Max: {maxSize}MB', { maxSize: 10 });
// Result: "File too large. Max: 10MB"Environment Configuration
Required: You must specify the environment for proper storage functionality:
import { configure } from 'wolfdog-request-manager';
// For React Native apps
configure({
serverUrl: 'https://api.example.com',
environment: 'react-native' // Required
});
// For browser/web apps
configure({
serverUrl: 'https://api.example.com',
environment: 'browser' // Required
});Environment options:
'react-native'- Uses AsyncStorage for data persistence'browser'- Uses localStorage for data persistence
Why environment configuration is important:
- Ensures proper storage mechanism selection
- Prevents runtime errors with localStorage in React Native
- Enables reliable JWT token persistence
- Optimizes performance for the target platform
Manual storage override (advanced):
import AsyncStorage from '@react-native-async-storage/async-storage';
import { StorageController } from 'wolfdog-request-manager';
// Custom storage implementation
const customStorage = {
getValue: AsyncStorage.getItem,
setValue: AsyncStorage.setItem,
removeValue: AsyncStorage.removeItem,
};
StorageController.setStorage(customStorage);Configuration Warnings
The library will automatically warn you if important configuration is missing:
import { RequestManager } from 'wolfdog-request-manager';
// If you forget to configure serverUrl
const result = await RequestManager.performRequest({
type: 'GET',
url: '/users',
errorOptions: {},
responseData: { id: { defaultValue: 0 } }
});
// Console output: ⚠️ RequestManager: serverUrl is not configured!
// Please call configure({ serverUrl: "your-api-url" }) before making requests.What triggers warnings:
- Empty or missing
serverUrlconfiguration - Whitespace-only
serverUrlvalues
To fix warnings:
import { configure } from 'wolfdog-request-manager';
// Properly configure before making requests
configure({
serverUrl: 'https://api.example.com'
});JWT Token Management
The library provides convenient methods to manage JWT tokens for authentication:
import { RequestManager, setJWT, getJWTToken, clearJWT } from 'wolfdog-request-manager';
// Method 1: Using RequestManager JWT namespace
RequestManager.JWT.setJWT('your-jwt-token');
RequestManager.JWT.setJWT('Bearer your-jwt-token'); // Bearer prefix is optional
// Method 2: Using direct imports
setJWT('your-jwt-token');
// Get current token
const currentToken = RequestManager.JWT.getJWT();
// or
const currentToken = getJWT();
// Clear token
RequestManager.JWT.clearJWT();
// or
clearJWT();Token Priority:
- Manually set token (via
setJWT()) - highest priority - Stored token (from storage under "request-manager-jwt" key) - fallback
Token Format:
- The library automatically adds
Bearerprefix if not present - If your token already has
Bearerprefix, it won't be duplicated
Usage Examples:
import { RequestManager } from 'wolfdog-request-manager';
// Configure the library
RequestManager.configure({
serverUrl: 'https://api.example.com'
});
// Set JWT token after user login
RequestManager.JWT.setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
// Make authenticated requests
const result = await RequestManager.performRequest({
type: 'GET',
url: '/protected-resource',
errorOptions: {},
responseData: {
data: { defaultValue: null }
}
});
// Clear token on logout
RequestManager.JWT.clearJWT();Storage Management: The library also provides functions to directly manage JWT tokens in storage:
import { RequestManager, setJWTInStorage, getJWTFromStorage, clearJWTFromStorage } from 'wolfdog-request-manager';
// Save token to storage (persists between sessions)
await RequestManager.JWT.setJWTInStorage('your-jwt-token');
// or
await setJWTInStorage('your-jwt-token');
// Get token from storage
const storedToken = await RequestManager.JWT.getJWTFromStorage();
// or
const storedToken = await getJWTFromStorage();
// Clear token from storage
await RequestManager.JWT.clearJWTFromStorage();
// or
await clearJWTFromStorage();
// or (alternative)
await RequestManager.JWT.setJWTInStorage(null);Note: Tokens are stored under the key "request-manager-jwt" to avoid conflicts with other libraries.
Custom Storage Implementation
import { StorageController, IStorage } from 'wolfdog-request-manager';
class CustomStorage implements IStorage {
async getValue(key: string): Promise<string | null> {
// Your custom storage logic
return null;
}
async setValue(key: string, value: string): Promise<void> {
// Your custom storage logic
}
async removeValue(key: string): Promise<void> {
// Your custom storage logic
}
}
// Use custom storage
StorageController.setStorage(new CustomStorage());Error Handling
The library provides comprehensive error handling with customizable messages:
const errorOptions = {
defaultEnd: 'processing request', // Default error suffix
on404: 'Resource not found', // Custom 404 message
on403: 'Access denied', // Custom 403 message
on401: 'Please log in again', // Custom 401 message
on409: 'Resource already exists', // Custom 409 message
on500: 'Server error occurred' // Custom 500 message
};Logging
Access request logs using the LogsHelper:
import { LogsHelper, type LogType } from 'wolfdog-request-manager';
// Get all logs
const logs = await LogsHelper.getAllLogs();
// Clear logs
await LogsHelper.clearLogs();LogType
The logs returned by getAllLogs() have the following structure:
type LogType = {
value: string; // The log message content
createdAt: string; // ISO timestamp when the log was created
}Usage example:
import { LogsHelper, type LogType } from 'wolfdog-request-manager';
const logs: LogType[] = await LogsHelper.getAllLogs();
logs.forEach((log: LogType) => {
console.log(`[${log.createdAt}] ${log.value}`);
});
// Example output:
// [2023-10-27T10:30:45.123Z] Error occurred during request
// [2023-10-27T10:30:50.456Z] Request completed successfullyTypeScript Support
The library is built with TypeScript and provides full type safety:
import type {
IPerformRequest,
ContentTypeOption,
ResponseDataMap,
IErrorOptions,
AppConfig,
AppEnvironment,
LogType
} from 'wolfdog-request-manager';VS Code Snippets
For faster development, you can add these snippets to your VS Code TypeScript snippets file:
How to add snippets:
- Open VS Code
- Press
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - Type "Configure User Snippets"
- Select "TypeScript" or "TypeScript React"
- Add the following snippet to your
typescript.jsonfile:
{
"create perform request": {
"prefix": "create-perform-request",
"body": [
"type ${1:ResponseType} = {}",
"",
"const ${2:requestFunction} = async () => {",
"\tconst result = await RequestManager.performRequest<${1:ResponseType}>({",
"\t\ttype: '${3|GET,POST,PUT,PATCH,DELETE|}',",
"\t\turl: '${4:/api/endpoint}',",
"\t\tresponseData: {",
"\t\t\t${5:// Add your response mapping here}",
"\t\t},",
"\t\terrorOptions: {",
"\t\t\tdefaultEnd: '${6:performing request}',",
"\t\t},",
"\t});",
"",
"\tif (result.ok) {",
"\t\tconsole.log('Success:', result.data);",
"\t} else {",
"\t\tconsole.error('Error:', result.message);",
"\t}",
"",
"\treturn result;",
"};"
],
"description": "Create a new RequestManager performRequest function"
}
}Usage:
After adding the snippet, type create-perform-request in any TypeScript file and press Tab to generate a complete request template.
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
