@uecsio/api-client
v1.0.1
Published
A reusable TypeScript API client wrapper for HTTP requests with flexible authentication
Maintainers
Readme
@uecsio/api-client
A reusable TypeScript API client wrapper for making HTTP requests with built-in authentication handling and error management.
Installation
npm install @uecsio/api-clientFeatures
- 🔒 Built-in authentication token management
- 🔄 Automatic 401 unauthorized handling
- 📦 TypeScript support with full type definitions
- 🎯 RESTful API methods (GET, POST, PUT, PATCH, DELETE)
- ⚙️ Configurable base URL and headers
- 🔌 Extensible with custom callbacks
- 🛠️ Access to underlying Axios instance for advanced use cases
Quick Start
import { ApiClient } from '@uecsio/api-client';
// Create an API client instance
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
});
// Make requests
const users = await apiClient.get('/users');
const newUser = await apiClient.post('/users', { name: 'John Doe' });Configuration
Basic Configuration
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
token: 'your-auth-token', // Optional initial token
headers: { // Optional custom headers
'X-Custom-Header': 'value',
},
});With Authentication Callbacks
For browser environments with localStorage:
const apiClient = new ApiClient({
baseUrl: process.env.REACT_APP_API_URL,
// Get token from localStorage
getToken: () => localStorage.getItem('token'),
// Save token to localStorage
saveToken: (token) => localStorage.setItem('token', token),
// Clear token from localStorage
clearToken: () => localStorage.removeItem('token'),
// Handle unauthorized responses (e.g., redirect to login)
onUnauthorized: () => {
window.location.href = '/login';
},
});For Node.js or other environments:
let authToken: string | null = null;
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
getToken: () => authToken,
saveToken: (token) => { authToken = token; },
clearToken: () => { authToken = null; },
onUnauthorized: () => {
console.log('Session expired, please login again');
},
});API Methods
GET Request
// Simple GET
const users = await apiClient.get('/users');
// With query parameters
const users = await apiClient.get('/users', {
params: { page: 1, limit: 10 },
});
// With custom headers
const users = await apiClient.get('/users', {
headers: { 'X-Custom-Header': 'value' },
});
// With TypeScript types
interface User {
id: number;
name: string;
}
const users = await apiClient.get<User[]>('/users');POST Request
const newUser = await apiClient.post('/users', {
name: 'John Doe',
email: '[email protected]',
});
// With TypeScript types
interface CreateUserResponse {
id: number;
name: string;
email: string;
}
const user = await apiClient.post<CreateUserResponse>('/users', {
name: 'John Doe',
email: '[email protected]',
});PUT Request
const updatedUser = await apiClient.put('/users/123', {
name: 'Jane Doe',
email: '[email protected]',
});PATCH Request
const updatedUser = await apiClient.patch('/users/123', {
name: 'Jane Doe',
});DELETE Request
await apiClient.delete('/users/123');File Upload
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('description', 'Profile picture');
const result = await apiClient.upload('/upload', formData);
// With additional headers
const result = await apiClient.upload('/upload', formData, {
headers: { 'X-Upload-Type': 'image' },
});Authentication Helpers
Check if Authenticated
if (apiClient.isAuthenticated()) {
// User has a valid token
const data = await apiClient.get('/protected');
}Get Authentication Info
const authInfo = apiClient.getAuthInfo();
console.log(authInfo.token); // Current token
console.log(authInfo.headers); // Custom headersToken Management
// Set authentication token
apiClient.setToken('your-auth-token');
// Get current token
const token = apiClient.getToken();
// Clear token
apiClient.clearToken();Utility Methods
Get RESTful Entity URL
const url = apiClient.getRestfulEntityUrl('/users', { id: 123 });
// Returns: '/users/123'Get Base URL
const baseUrl = apiClient.getBaseUrl();Update Base URL
apiClient.setBaseUrl('https://api-v2.example.com');Access Axios Instance
For advanced use cases, you can access the underlying Axios instance:
const axios = apiClient.getAxiosInstance();
// Use axios directly for custom requests
axios.interceptors.request.use(config => {
// Custom request interceptor
return config;
});Complete API Reference
Methods
| Method | Description |
|--------|-------------|
| get<T>(path, options?) | Make GET request |
| post<T>(path, data?, options?) | Make POST request |
| put<T>(path, data?, options?) | Make PUT request |
| patch<T>(path, data?, options?) | Make PATCH request |
| delete<T>(path, options?) | Make DELETE request |
| upload<T>(path, formData, options?) | Upload files with FormData |
| setToken(token) | Set authentication token |
| getToken() | Get current token |
| clearToken() | Clear authentication token |
| isAuthenticated() | Check if currently authenticated |
| getAuthInfo() | Get current auth info (token + headers) |
| getBaseUrl() | Get current base URL |
| setBaseUrl(url) | Update base URL |
| getRestfulEntityUrl(url, data) | Build RESTful entity URLs |
| getAxiosInstance() | Access underlying Axios instance |
Configuration Options
interface ApiClientConfig {
baseUrl: string; // Required: Base URL for all requests
token?: string; // Optional: Initial auth token
headers?: Record<string, string>; // Optional: Custom headers
onUnauthorized?: () => void; // Optional: 401 error callback
getToken?: () => string | null; // Optional: Token getter
saveToken?: (token: string) => void; // Optional: Token saver
clearToken?: () => void; // Optional: Token clearer
axiosConfig?: AxiosRequestConfig; // Optional: Additional axios config
}Error Handling
The client automatically handles 401 Unauthorized responses by:
- Clearing the stored token
- Calling the
clearTokencallback (if provided) - Calling the
onUnauthorizedcallback (if provided)
For other errors, you can use standard try-catch:
try {
const data = await apiClient.get('/users');
} catch (error) {
if (error.response) {
// Server responded with error status
console.error('Error:', error.response.status, error.response.data);
} else if (error.request) {
// Request made but no response
console.error('No response received');
} else {
// Other errors
console.error('Error:', error.message);
}
}Framework Examples
React
// api.ts
import { ApiClient } from '@uecsio/api-client';
export const apiClient = new ApiClient({
baseUrl: process.env.REACT_APP_API_URL || 'https://api.example.com',
getToken: () => localStorage.getItem('token'),
saveToken: (token) => localStorage.setItem('token', token),
clearToken: () => localStorage.removeItem('token'),
onUnauthorized: () => {
window.location.href = '/login';
},
});
// In your components
import { apiClient } from './api';
function UsersList() {
const [users, setUsers] = useState([]);
useEffect(() => {
apiClient.get('/users').then(setUsers);
}, []);
return <div>{/* render users */}</div>;
}Vue.js
// api.ts
import { ApiClient } from '@uecsio/api-client';
import router from './router';
export const apiClient = new ApiClient({
baseUrl: process.env.VUE_APP_BASE_API_HOST,
getToken: () => localStorage.getItem('token'),
saveToken: (token) => localStorage.setItem('token', token),
clearToken: () => localStorage.removeItem('token'),
onUnauthorized: () => {
router.push({ name: 'Login' });
},
});
// In your components
import { apiClient } from './api';
export default {
async mounted() {
this.users = await apiClient.get('/users');
},
};Node.js / Express
import { ApiClient } from '@uecsio/api-client';
const apiClient = new ApiClient({
baseUrl: 'https://external-api.example.com',
token: process.env.API_TOKEN,
});
app.get('/proxy/users', async (req, res) => {
try {
const users = await apiClient.get('/users');
res.json(users);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch users' });
}
});License
MIT
