Header Customization Architecture
Architectural patterns for implementing and managing custom API headers across different use cases
Header Customization Architecture
Overview
This document outlines the architectural patterns for implementing custom headers in API requests. API headers provide critical context to backend services, enabling features like multi-tenancy, device tracking, session management, and request correlation.
Our approach integrates seamlessly with the established API client architecture while leveraging Zustand for state management, creating a flexible and maintainable system for header customization across the application.
Purpose & Scope
This guide establishes:
- Core patterns for implementing custom API headers
- Integration with Zustand state management
- Extensible header provider architecture
- Decision framework for when to use different header types
- Testing strategies for header implementations
This document is intended for all developers working with API integrations and those needing to add custom contextual information to API requests.
Quick Start
If you're looking to quickly implement custom headers in your API client, here's how to get started:
-
Define your header constants:
-
Create a header provider:
-
Register with your API client:
For more detailed implementation, continue reading the sections below.
Prerequisites
To effectively use this guide, you should be familiar with:
- API Client Architecture - Our standard API client structure
- Authentication Architecture - How authentication headers are managed
- Client State Management - Zustand store patterns
- Multi-API Architecture - For service-specific header configurations
Architecture Overview
Custom headers are implemented through a combination of header providers, Zustand stores, and interceptors in our API client architecture:
Header Types and Use Cases
Different header types serve different purposes in your application:
| Header Type | Purpose | Examples | Priority |
|---|---|---|---|
| Identity | Identifies tenant context | X-ORG-ID, X-PROJECT-ID | High |
| Device | Provides device context | X-DEVICE-UUID, User-Agent | High |
| Tracking | Enables request correlation | X-REQUEST-ID, X-CORRELATION-ID | Medium |
| Session | Maintains session context | X-SESSION-ID | Medium |
| Feature | Enables feature flags | X-FEATURE-FLAGS | Low |
| Debugging | Provides debug information | X-DEBUG-MODE | Low |
Header priorities indicate their importance in the architecture. High-priority headers should be consistently implemented across all APIs, while low-priority headers might be optional or use-case specific.
Core Components
Conceptual Overview
Our header customization architecture consists of four main components working together:
- Header Providers: Modular components that supply specific header values
- Zustand Stores: State containers that hold header-related data
- Provider Registry: System within BaseApiClient to register and manage providers
- Interceptor Integration: Mechanism to apply headers to outgoing requests
Implementation Guides
For detailed implementation examples of specific header types, refer to these guides:
Multi-Tenant Headers
Implementation guide for organization and project context headers
Device Identification Headers
Implementation guide for device identification and tracking headers
Session Tracking Headers
Implementation guide for session tracking and correlation headers
User Preferences Headers
Implementation guide for personalized user preference headers
User-Agent Headers
Implementation guide for custom User-Agent headers
The remainder of this document details the core components of the header architecture that all these implementation guides build upon.
This architecture follows a plugin pattern, where different header providers can be registered with API clients, making the system highly extensible while maintaining a consistent implementation approach.
The header provider pattern creates a clear separation of concerns: state management is handled by Zustand stores, while the logic for transforming state into headers lives in providers.
1. Header Provider Interface
The foundation of our architecture is the HeaderProvider interface, which creates a consistent pattern for different header types:
2. Header Constants
Centralized constants ensure consistent header names across the application:
3. Extended BaseApiClient
The BaseApiClient is extended to support header providers:
Header Implementation Patterns
We support three patterns for implementing headers, each with specific use cases:
1. Static Headers
Static headers remain constant across all requests and are typically configured during client initialization.
Use when: The header value is constant and known at initialization time.
2. Zustand-Based Dynamic Headers
For headers that depend on application state, we use Zustand stores rather than separate context services, aligning with our state management architecture:
Then implement a corresponding header provider:
Use when: The header values depend on user selection, app state, or other runtime factors.
3. Per-Request Headers
Headers specified for individual API calls that override global defaults:
Use when: The header is specific to a particular request and not applicable globally.
Common Header Provider Implementations
Device Information Provider
Request Tracking Provider
Debug Mode Provider
Registering Header Providers with API Clients
Testing Header Implementations
Decision Framework: When to Use Which Headers
Use this framework to determine which headers to implement for your specific use case:
Identity Headers
When to use:
- Multi-tenant applications where users belong to organizations
- Resource segmentation based on organizational hierarchies
- Project or team-based access controls
Common headers:
X-ORG-ID: Organization identifierX-PROJECT-ID: Project identifier within an organizationX-TENANT-ID: Generic tenant identifier
Device Headers
When to use:
- Device-specific features or optimizations
- Analytics tracking device usage
- Security auditing and device verification
Common headers:
X-DEVICE-UUID: Unique device identifierX-DEVICE-TYPE: Device type (phone, tablet, etc.)User-Agent: Custom or extended user agent information
Session and Tracking Headers
When to use:
- Request correlation for troubleshooting
- Analytics flow tracking
- Performance monitoring
Common headers:
X-SESSION-ID: User session identifierX-REQUEST-ID: Unique request identifierX-CORRELATION-ID: Identifier for tracing requests across services
Implementation Considerations
Security Implications
Be careful about what information you include in headers. Headers can be exposed in network logs and could potentially leak sensitive information.
- We strongly recommend against including sensitive information like passwords, tokens, or PII in custom headers
- It's advisable to use non-sequential, non-predictable IDs for organization and project identifiers
- Consider encrypting certain header values if they contain semi-sensitive information
Performance Impact
- Headers add minimal overhead to requests, but caching header values can improve performance
- Implement caching in header providers where appropriate to avoid redundant computations
- Consider the frequency of state changes when designing Zustand stores for header values
Consistency and Maintainability
- Use a single source of truth for header names (constants or enums)
- Document headers thoroughly, including purpose, format, and fallback behavior
- Follow the HeaderProvider interface consistently for all header types
Design Principles
Core Architectural Principles
-
Modularity
- Each header provider is responsible for a specific header type
- Providers can be added, removed, or modified independently
- Composable architecture allows for customization per API client
-
State Management Integration
- Consistent use of Zustand for state-driven headers
- Aligns with the project's "Golden Rule" for state management
-
Priority-Based Application
- Header providers have explicit priorities
- Providers are applied in priority order to ensure consistent resolution
Trade-offs and Design Decisions
| Decision | Benefits | Drawbacks | Rationale |
|---|---|---|---|
| HeaderProvider interface | Consistent implementation, testability | More boilerplate compared to simple functions | Creates a pluggable system that scales better with multiple header types |
| Zustand integration | Aligns with state management architecture | Requires Zustand knowledge | Maintains consistency with our established patterns |
| Priority-based ordering | Clear resolution order, predictable behavior | Additional complexity | Ensures critical headers are consistently applied first |
| Type-safe constants | Compile-time validation | Requires maintenance when adding headers | Prevents typos and inconsistencies across the codebase |
Implementation Examples
Here are examples of using header providers in different domains:
User Preferences in Profile API
Organization Context in Projects API
Troubleshooting
Here are solutions to common issues when implementing custom headers:
Headers Not Being Applied
Issue: Your custom headers aren't showing up in network requests
Solutions:
- Ensure your header provider is properly registered with the API client
- Check that your Zustand store is properly initialized
- Verify header provider priority values (higher priorities are applied first)
- Look for console warnings about header provider errors
Conflicting Headers
Issue: Multiple providers are trying to set the same header with different values
Solution: Adjust provider priorities to ensure the correct provider wins, or refactor providers to have clearer responsibilities.
Performance Issues
Issue: Header resolution is causing noticeable delays in API requests
Solutions:
- Implement caching in your header providers
- Reduce async operations where possible
- Consider using a memory cache for frequently accessed header values
Migration Guide
If you're migrating from an older header implementation, follow these steps:
- Define header constants in a central location
- Create header providers for each header category
- Update API client initialization to register providers
- Remove any inline header creation from domain APIs
- Update tests to mock header providers rather than specific headers
Related Documents
- API Client Architecture - Base client structure this builds upon
- Authentication Architecture - How auth headers are managed (authentication headers use a different mechanism than covered in this document)
- Client State Management - Zustand patterns used for header state
- Multi-API Architecture - For service-specific header configurations
Summary
This header customization architecture provides a flexible, maintainable approach to managing API headers across your application. By leveraging Zustand for state management and implementing a modular provider system, you can easily add, modify, or extend custom headers as your application requirements evolve.
Key takeaways:
- The HeaderProvider interface creates a consistent pattern for header implementation
- Zustand stores provide a clean way to manage state that affects headers
- The priority system ensures predictable header resolution
- This architecture scales well as your application grows
- Each header provider can be tested independently
By following these established patterns, you can ensure your API headers remain well-organized and aligned with the rest of the application architecture.