@ticatec/restful_service_api
v0.1.7
Published
A lightweight TypeScript RESTful API client for browsers with error handling.
Downloads
3
Readme
@ticatec/restful_service_api
A lightweight TypeScript RESTful API client for browsers with comprehensive error handling and interceptor support.
中文版 | English
Features
- 🚀 Lightweight: Zero dependencies, built for modern browsers
- 🔧 TypeScript Support: Full type safety with TypeScript definitions
- 🛡️ Error Handling: Built-in error handling with custom ApiError class
- ⚡ Interceptors: Pre and post request interceptors for authentication and data processing
- 🎯 Flexible: Support for custom headers, timeouts, and data processors
- 🌐 Browser-First: Designed specifically for frontend applications
Installation
npm install @ticatec/restful_service_apiQuick Start
import RestService from '@ticatec/restful_service_api';
// Your implementation of RestService interface
class MyApiClient implements RestService {
async get(url: string, params?: any) {
// Implementation here
}
async post(url: string, data: any, params?: any, contentType?: string) {
// Implementation here
}
// ... other methods
}
const api = new MyApiClient();
// Make requests
const users = await api.get('/users');
const newUser = await api.post('/users', { name: 'John Doe' });API Reference
RestService Interface
The main interface that defines the contract for REST operations:
interface RestService {
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
post(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
put(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
del(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
}Methods
get(url, params?, dataProcessor?)
- url: The endpoint URL
- params: Query parameters (optional)
- dataProcessor: Function to process response data (optional)
post(url, data, params?, contentType?, dataProcessor?)
- url: The endpoint URL
- data: Request payload
- params: Query parameters (optional)
- contentType: Content-Type header (optional, defaults to application/json)
- dataProcessor: Function to process response data (optional)
put(url, data, params?, contentType?, dataProcessor?)
Similar to POST but for update operations.
del(url, data, params?, contentType?, dataProcessor?)
For delete operations with optional request body.
upload(url, params, file, fileKey?, dataProcessor?)
- url: The upload endpoint URL
- params: Additional parameters for the upload request
- file: The File object to upload
- fileKey: Optional form field name for the file (defaults to 'file')
- dataProcessor: Function to process response data (optional)
asyncUpload(url, params, file, callback, fileKey?)
- url: The upload endpoint URL
- params: Additional parameters for the upload request
- file: The File object to upload
- callback: Upload callback object with progress, error, and completion handlers
- fileKey: Optional form field name for the file (defaults to 'file')
- Returns: Promise that resolves to UploadProgress object for cancellation
download(url, filename, params, method?, formData?)
- url: The download endpoint URL
- filename: The name to save the downloaded file
- params: Download request parameters
- method: Optional HTTP method (defaults to GET)
- formData: Optional form data for POST downloads
Error Handling
The library includes a custom ApiError class for handling API errors:
import { ApiError } from '@ticatec/restful_service_api';
try {
const result = await api.get('/users');
} catch (error) {
if (error instanceof ApiError) {
console.log('Status:', error.status);
console.log('Code:', error.code);
console.log('Details:', error.details);
}
}Types and Interceptors
import {
PreInterceptor,
PostInterceptor,
ErrorHandler,
DataProcessor
} from '@ticatec/restful_service_api';
// Pre-interceptor for adding authentication headers
const preInterceptor: PreInterceptor = (method: string, url: string) => {
return {
headers: {
'Authorization': 'Bearer ' + getToken(),
'X-Request-ID': generateRequestId()
},
timeout: 30000
};
};
// Post-interceptor for response processing
const postInterceptor: PostInterceptor = async (data: any) => {
// Process response data
return data;
};
// Error handler
const errorHandler: ErrorHandler = (error: Error) => {
console.error('API Error:', error);
return true; // Return true if error is handled
};
// Data processor
const dataProcessor: DataProcessor = (data: any) => {
// Transform response data
return data.results || data;
};Content Types
Pre-defined content type constants:
import {
CONTENT_TYPE_NAME,
TYPE_JSON,
TYPE_HTML,
TYPE_TEXT
} from '@ticatec/restful_service_api';
// Usage
await api.post('/upload', data, {}, TYPE_JSON);Implementation Example
Here's a complete example implementation using the native fetch API:
import RestService, {
ApiError,
PreInterceptor,
PostInterceptor,
TYPE_JSON
} from '@ticatec/restful_service_api';
class FetchRestService implements RestService {
private baseURL: string;
private preInterceptor?: PreInterceptor;
private postInterceptor?: PostInterceptor;
constructor(baseURL: string, preInterceptor?: PreInterceptor, postInterceptor?: PostInterceptor) {
this.baseURL = baseURL;
this.preInterceptor = preInterceptor;
this.postInterceptor = postInterceptor;
}
async get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any> {
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
return this.request('GET', url + queryString, null, undefined, dataProcessor);
}
async post(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
return this.request('POST', url, data, contentType, dataProcessor);
}
async put(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
return this.request('PUT', url, data, contentType, dataProcessor);
}
async del(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
return this.request('DELETE', url, data, contentType, dataProcessor);
}
private async request(method: string, url: string, body?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any> {
const fullUrl = this.baseURL + url;
// Apply pre-interceptor
const interceptorResult = this.preInterceptor?.(method, fullUrl) || { headers: {} };
const headers = {
...interceptorResult.headers,
...(contentType && { 'Content-Type': contentType })
};
try {
const response = await fetch(fullUrl, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
signal: interceptorResult.timeout ? AbortSignal.timeout(interceptorResult.timeout) : undefined
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new ApiError(response.status, errorData);
}
let data = await response.json();
// Apply post-interceptor
if (this.postInterceptor) {
data = await this.postInterceptor(data);
}
// Apply data processor
if (dataProcessor) {
data = dataProcessor(data);
}
return data;
} catch (error) {
if (error instanceof ApiError) {
throw error;
}
throw new ApiError(0, { code: 'NETWORK_ERROR', message: error.message });
}
}
}
// Usage
const api = new FetchRestService('https://api.example.com');
const users = await api.get('/users');File Upload and Download Examples
import RestService, {
UploadCallback,
UploadProgress
} from '@ticatec/restful_service_api';
// Simple file upload
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
const file = fileInput.files[0];
try {
const result = await api.upload('/upload', { userId: 123 }, file);
console.log('Upload successful:', result);
} catch (error) {
console.error('Upload failed:', error);
}
// Async upload with progress tracking
const uploadCallback: UploadCallback = {
method: 'POST',
progressUpdate: (uploadedBytes: number) => {
console.log(`Uploaded: ${uploadedBytes} bytes`);
},
handleError: (error: Error) => {
console.error('Upload error:', error);
},
onCompleted: (data: any) => {
console.log('Upload completed:', data);
}
};
const uploadProgress = await api.asyncUpload('/upload', { userId: 123 }, file, uploadCallback);
// Cancel upload if needed
setTimeout(() => {
uploadProgress.cancel();
}, 5000);
// File download
try {
await api.download('/files/document.pdf', 'my-document.pdf', { userId: 123 });
console.log('Download completed');
} catch (error) {
console.error('Download failed:', error);
}
// POST download with form data
const formData = { reportType: 'monthly', format: 'pdf' };
await api.download('/reports/generate', 'monthly-report.pdf', {}, 'POST', formData);Utility Functions
The library includes utility functions for common operations:
import utils from '@ticatec/restful_service_api/utils';
// Convert object to query string
const queryString = utils.toQueryString({ name: 'John', age: 30 });
// Returns: "name=John&age=30"
// Combine URL with parameters
const fullUrl = utils.combineUrl('/api/users', { page: 1, limit: 10 });
// Returns: "/api/users?page=1&limit=10"
// Generate HTTP request options
const options = utils.generateRequestOptions('POST', { id: 1 }, { name: 'John' });
// Returns: { method: 'POST', headers: {}, params: { id: 1 }, data: { name: 'John' } }
// Clean parameters (removes null, undefined, empty strings, trims values)
const cleanedParams = utils.cleanParams({ name: ' John ', age: null, email: '' });
// Returns: { name: 'John' }
// Function utilities
utils.invokeFunction(callback, arg1, arg2); // Safely invoke function if it exists
const isFunc = utils.isFunction(someValue); // Check if value is a functionAvailable Utility Functions
toQueryString(obj): Converts an object to URL query stringcombineUrl(url, params): Combines URL with query parametersgenerateRequestOptions(method, params, data): Generates HTTP request optionscleanParams(params): Cleans parameters by removing null/empty values and trimming stringsisFunction(value): Checks if a value is a functioninvokeFunction(func, ...args): Safely invokes a function if it exists
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see the LICENSE file for details.
Author
Henry Feng
For more examples and advanced usage, please check the documentation.
