Skip to content

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 ​

bash
npm install @breadstone/ziegel-platform-http

Dependencies:

  • @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:

typescript
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&gt;('/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&gt;();

Request/Response Interceptors ​

Modify requests and responses globally:

typescript
import { RequestInterceptor, ResponseInterceptor } from '@breadstone/ziegel-platform-http';

// Request interceptor for authentication
class AuthInterceptor implements RequestInterceptor {
  async intercept(request: HttpRequest): Promise&lt;HttpRequest&gt; {
    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&lt;HttpResponse&gt; {
    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:

typescript
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:

typescript
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:

typescript
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&lt;string&gt; {
    return await this.tokenService.getValidToken();
  }

  async onAuthenticationFailed(): Promise&lt;void&gt; {
    await this.tokenService.refreshToken();
  }
}

Request/Response Transformation ​

Transform data before sending and after receiving:

typescript
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:

typescript
// 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:

typescript
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:

typescript
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:

json
{
  "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:

typescript
// 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:

typescript
interface User {
  id: string;
  name: string;
  email: string;
  createdAt: Date;
}

interface ApiResponse<T&gt; {
  data: T;
  success: boolean;
  message?: string;
}

const response = await httpClient.get<ApiResponse<User[]>>('/users');

3. Handle Errors Gracefully ​

Implement comprehensive error handling:

typescript
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:

typescript
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:

typescript
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');
  });
});

API Reference ​

For detailed API documentation, see the generated API reference.