wolfdog-request-manager
v5.0.6
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: Automatic storage selection (IndexedDB/localStorage fallback in browser, AsyncStorage in React Native)
- 📁 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, requestManagerConfig } from 'wolfdog-request-manager';
// Set configuration
configure({
serverUrl: 'https://api.example.com',
environment: 'browser'
});
// Access current configuration
console.log(requestManagerConfig.serverUrl);
// Update serverUrl directly
requestManagerConfig.serverUrl = 'https://new-api.example.com';requestManagerConfig is the public configuration object exposed by the library.
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',
environment: 'browser',
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',
environment: 'browser',
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 IndexedDB for data persistence, with localStorage fallback when IndexedDB is unavailable
Why environment configuration is important:
- Ensures proper storage mechanism selection
- Prevents runtime errors with browser-only storage in React Native
- Enables reliable JWT token persistence
- Optimizes performance for the target platform
Storage behavior:
- Browser: IndexedDB first, localStorage fallback, then in-memory fallback
- React Native: AsyncStorage
- Unsupported environments: in-memory fallback
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", environment: "browser" }) 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',
environment: 'browser'
});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.
Storage Notes
Storage is now managed internally by the library. There is no public StorageController or IStorage export.
This keeps the public API smaller and lets the library automatically choose the right persistence layer for each environment.
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,
RequestManagerDefaultResponse,
IErrorOptions,
AppConfig,
AppEnvironment,
LogType
} from 'wolfdog-request-manager';RequestManagerDefaultResponse is useful when you want to type shared response metadata separately from your mapped data payload.
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.
