ziegel-platform-http ​
The @breadstone/ziegel-platform-http package provides a comprehensive HTTP client implementation with built-in support for authentication, caching, retry policies, and request/response transformation. It's designed to handle all your HTTP communication needs in enterprise applications.
Installation ​
npm install @breadstone/ziegel-platform-httpDependencies:
@breadstone/ziegel-core@breadstone/ziegel-platform-configuration@breadstone/ziegel-platform-logging@breadstone/ziegel-platform-serialization
Key Features ​
HTTP Client ​
A powerful, extensible HTTP client with fluent API:
import { HttpClient, HttpMethod } from '@breadstone/ziegel-platform-http';
const httpClient = new HttpClient({
baseURL: 'https://api.example.com',
timeout: 30000,
headers: {
'Content-Type': 'application/json'
}
});
// Simple GET request
const users = await httpClient.get<User[]>('/users');
// POST with data
const newUser = await httpClient.post<User>('/users', {
name: 'John Doe',
email: 'john@example.com'
});
// Fluent API
const response = await httpClient
.request('/api/data')
.method(HttpMethod.GET)
.header('Authorization', 'Bearer token')
.query('page', 1)
.query('limit', 10)
.timeout(5000)
.execute<ApiResponse>();Request/Response Interceptors ​
Modify requests and responses globally:
import { RequestInterceptor, ResponseInterceptor } from '@breadstone/ziegel-platform-http';
// Request interceptor for authentication
class AuthInterceptor implements RequestInterceptor {
async intercept(request: HttpRequest): Promise<HttpRequest> {
const token = await this.tokenService.getAccessToken();
return request.withHeader('Authorization', `Bearer ${token}`);
}
}
// Response interceptor for error handling
class ErrorInterceptor implements ResponseInterceptor {
async intercept(response: HttpResponse): Promise<HttpResponse> {
if (response.status === 401) {
await this.authService.refreshToken();
// Retry the original request
return this.httpClient.retry(response.request);
}
return response;
}
}
// Register interceptors
httpClient.addRequestInterceptor(new AuthInterceptor());
httpClient.addResponseInterceptor(new ErrorInterceptor());Retry Policies ​
Automatic retry with configurable policies:
import { RetryPolicy, ExponentialBackoff } from '@breadstone/ziegel-platform-http';
const retryPolicy = RetryPolicy.create()
.maxAttempts(3)
.backoff(new ExponentialBackoff(1000, 2))
.retryWhen(error =>
error.status >= 500 ||
error.code === 'NETWORK_ERROR'
);
const httpClient = new HttpClient({
retryPolicy
});
// Automatically retries on failure
const data = await httpClient.get('/unreliable-endpoint');Caching ​
Built-in response caching with multiple strategies:
import { CacheStrategy, MemoryCache, RedisCache } from '@breadstone/ziegel-platform-http';
// Memory cache
const memoryCache = new MemoryCache({
maxSize: 100,
ttl: 300000 // 5 minutes
});
// Redis cache (requires redis connection)
const redisCache = new RedisCache({
connectionString: 'redis://localhost:6379',
keyPrefix: 'http-cache:'
});
const httpClient = new HttpClient({
cache: memoryCache,
cacheStrategy: CacheStrategy.CacheFirst
});
// This will be cached
const data = await httpClient
.get('/expensive-operation')
.cache(true, 600000) // Cache for 10 minutes
.execute();Authentication ​
Built-in support for common authentication schemes:
import { BearerTokenAuth, BasicAuth, ApiKeyAuth } from '@breadstone/ziegel-platform-http';
// Bearer token authentication
const bearerAuth = new BearerTokenAuth('your-jwt-token');
// Basic authentication
const basicAuth = new BasicAuth('username', 'password');
// API key authentication
const apiKeyAuth = new ApiKeyAuth('X-API-Key', 'your-api-key');
const httpClient = new HttpClient({
authentication: bearerAuth
});
// Token refresh handling
class TokenRefreshAuth extends BearerTokenAuth {
constructor(private tokenService: TokenService) {
super();
}
async getToken(): Promise<string> {
return await this.tokenService.getValidToken();
}
async onAuthenticationFailed(): Promise<void> {
await this.tokenService.refreshToken();
}
}Request/Response Transformation ​
Transform data before sending and after receiving:
import { RequestTransformer, ResponseTransformer } from '@breadstone/ziegel-platform-http';
// Transform outgoing requests
class TimestampTransformer implements RequestTransformer {
transform(data: any): any {
return {
...data,
timestamp: new Date().toISOString()
};
}
}
// Transform incoming responses
class CamelCaseTransformer implements ResponseTransformer {
transform(data: any): any {
// Convert snake_case to camelCase
return this.toCamelCase(data);
}
}
const httpClient = new HttpClient({
requestTransformers: [new TimestampTransformer()],
responseTransformers: [new CamelCaseTransformer()]
});Advanced Features ​
Upload/Download with Progress ​
Handle file uploads and downloads with progress tracking:
// File upload with progress
const uploadProgress = (progress: ProgressEvent) => {
console.log(`Upload progress: ${(progress.loaded / progress.total) * 100}%`);
};
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const response = await httpClient
.post('/upload')
.data(formData)
.onUploadProgress(uploadProgress)
.execute();
// File download with progress
const downloadProgress = (progress: ProgressEvent) => {
console.log(`Download progress: ${(progress.loaded / progress.total) * 100}%`);
};
const blob = await httpClient
.get('/download/large-file.zip')
.responseType('blob')
.onDownloadProgress(downloadProgress)
.execute();WebSocket Support ​
Built-in WebSocket client for real-time communication:
import { WebSocketClient } from '@breadstone/ziegel-platform-http';
const wsClient = new WebSocketClient('wss://api.example.com/ws', {
reconnect: true,
heartbeat: 30000
});
wsClient.on('connected', () => {
console.log('WebSocket connected');
});
wsClient.on('message', (data) => {
console.log('Received:', data);
});
wsClient.on('error', (error) => {
console.error('WebSocket error:', error);
});
// Send messages
wsClient.send({ type: 'subscribe', channel: 'notifications' });
// Clean up
await wsClient.disconnect();GraphQL Support ​
Dedicated GraphQL client with query/mutation support:
import { GraphQLClient } from '@breadstone/ziegel-platform-http';
const gqlClient = new GraphQLClient('https://api.example.com/graphql', {
headers: {
'Authorization': 'Bearer token'
}
});
// Query
const query = `
query GetUsers($limit: Int!) {
users(limit: $limit) {
id
name
email
}
}
`;
const users = await gqlClient.query(query, { limit: 10 });
// Mutation
const mutation = `
mutation CreateUser($input: UserInput!) {
createUser(input: $input) {
id
name
}
}
`;
const newUser = await gqlClient.mutate(mutation, {
input: { name: 'John', email: 'john@example.com' }
});Configuration ​
Configure HTTP behavior through configuration files:
{
"http": {
"defaultTimeout": 30000,
"retries": {
"maxAttempts": 3,
"backoffMultiplier": 2,
"initialDelay": 1000
},
"cache": {
"enabled": true,
"provider": "memory",
"ttl": 300000
},
"logging": {
"enabled": true,
"level": "info",
"includeHeaders": false,
"includeBody": false
}
}
}Best Practices ​
1. Use Base Clients ​
Create base clients for different APIs:
// Base client for internal APIs
export const internalApiClient = new HttpClient({
baseURL: config.get('api.internal.baseUrl'),
timeout: config.get('api.internal.timeout'),
authentication: new BearerTokenAuth(config.get('api.internal.token'))
});
// Base client for external APIs
export const externalApiClient = new HttpClient({
baseURL: config.get('api.external.baseUrl'),
timeout: config.get('api.external.timeout'),
retryPolicy: RetryPolicy.create().maxAttempts(5)
});2. Type Your Responses ​
Always use TypeScript types for API responses:
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
interface ApiResponse<T> {
data: T;
success: boolean;
message?: string;
}
const response = await httpClient.get<ApiResponse<User[]>>('/users');3. Handle Errors Gracefully ​
Implement comprehensive error handling:
try {
const data = await httpClient.get('/api/data');
return data;
} catch (error) {
if (error instanceof HttpError) {
switch (error.status) {
case 404:
throw new NotFoundError('Resource not found');
case 401:
throw new UnauthorizedError('Authentication required');
case 500:
throw new ServerError('Internal server error');
default:
throw new ApiError(`HTTP ${error.status}: ${error.message}`);
}
}
throw error;
}4. Use Request/Response Logging ​
Enable logging for debugging and monitoring:
import { LoggingInterceptor } from '@breadstone/ziegel-platform-http';
const loggingInterceptor = new LoggingInterceptor({
includeHeaders: true,
includeBody: true,
maxBodyLength: 1000
});
httpClient.addRequestInterceptor(loggingInterceptor);
httpClient.addResponseInterceptor(loggingInterceptor);Testing ​
Mock HTTP requests for unit testing:
import { MockHttpClient, HttpMock } from '@breadstone/ziegel-platform-http';
describe('UserService', () => {
let mockClient: MockHttpClient;
let userService: UserService;
beforeEach(() => {
mockClient = new MockHttpClient();
userService = new UserService(mockClient);
});
it('should fetch users', async () => {
// Setup mock
mockClient
.when('GET', '/users')
.respond(200, [
{ id: '1', name: 'John' },
{ id: '2', name: 'Jane' }
]);
const users = await userService.getUsers();
expect(users).toHaveLength(2);
expect(users[0].name).toBe('John');
});
it('should handle errors', async () => {
mockClient
.when('GET', '/users')
.respond(500, { error: 'Internal Server Error' });
await expect(userService.getUsers()).rejects.toThrow('Internal Server Error');
});
});Related Packages ​
- ziegel-platform-configuration - HTTP client configuration
- ziegel-platform-logging - Request/response logging
- ziegel-platform-serialization - JSON serialization
- ziegel-platform-caching - Response caching strategies
API Reference ​
For detailed API documentation, see the generated API reference.