API Client with Request Queueing
Enhanced API client implementation with proper request queueing during token refresh
API Client with Request Queueing
Overview
This document outlines our implementation of the request queueing pattern for API clients to handle token refresh scenarios efficiently. When multiple API requests encounter an expired access token simultaneously, our approach ensures that only one token refresh operation occurs, while other requests are queued and automatically retried upon successful token refresh, providing a seamless user experience without exposing authentication complexities to application logic.
This document focuses on the request queueing mechanism specifically. For details about the overall authentication architecture, token management, and security considerations, see the Authentication Architecture documentation.
Purpose & Scope
This reference targets developers implementing or maintaining API communication layers. It covers:
- The problem of concurrent API requests during token expiration
- Request queueing implementation strategies
- Handling of public vs. authenticated endpoints
- Error handling during token refresh
- Testing strategies for request queueing
Prerequisites
To get the most out of this guide on request queueing, we recommend you first understand these core concepts and review the related architectural documents:
- API Client Architecture: You should be thoroughly familiar with the mandatory patterns defined in the API Client Architecture, particularly the roles of
BaseApiClient,PublicApiClient, andAuthenticatedApiClient. - Authentication Architecture: A strong grasp of the concepts in the Authentication Architecture document is crucial. This includes understanding how
tokenServicemanages tokens, howauthEventsare used, and the basic token refresh flow. - Axios Interceptors: The queueing logic is implemented using Axios request and response interceptors. Familiarity with how these work is essential.
- JavaScript Asynchronous Operations: A good understanding of Promises,
async/awaitis necessary to follow the code examples.
The Problem
When multiple API requests are made simultaneously and the access token has expired, each request will receive a 401 response. Without proper handling, this would trigger multiple token refresh requests, causing:
- Race conditions
- Invalid refresh token errors
- Poor user experience
- Potential security issues
Solution: Request Queue Pattern
We implement a queue mechanism that:
- Detects when a refresh is in progress
- Queues subsequent failed requests
- Processes all queued requests after refresh completes
- Handles refresh failures gracefully
Handling Public vs. Authenticated API Endpoints
In our project, the differentiation between public API endpoints (which do not require authentication tokens) and authenticated endpoints (which do) is managed by our established standard API client architecture. This architecture, detailed in the API Client Architecture, utilizes separate PublicApiClient and AuthenticatedApiClient instances.
PublicApiClient: Used for endpoints like login, registration, or public data fetching. It does not attach authentication tokens.AuthenticatedApiClient: Used for endpoints requiring user authentication. It handles attaching access tokens and is responsible for the token refresh mechanism, including request queueing.
This document focuses on the request queueing mechanism implemented within the AuthenticatedApiClient when a token refresh is triggered. The following sections will detail this queueing logic and how it integrates into the token refresh process of the AuthenticatedApiClient.
For comprehensive details on how PublicApiClient and AuthenticatedApiClient are structured and used, please refer to:
Complete Implementation with Queue (within AuthenticatedApiClient)
This section details how request queueing is integrated into our standard AuthenticatedApiClient. The AuthenticatedApiClientWithQueue class shown below extends the BaseApiClient and incorporates the queueing logic.
About the `AuthenticatedApiClientWithQueue` Example
The AuthenticatedApiClientWithQueue class presented below demonstrates the complete integration of request queueing into an authenticated API client.
- It illustrates the fully-featured version of the
AuthenticatedApiClient(which is introduced in the API Client Architecture and further detailed in the Authentication Architecture guide). - In your actual project codebase, this queueing logic would typically be part of your main
AuthenticatedApiClient. The nameAuthenticatedApiClientWithQueueis used here for clear focus on the queueing enhancements. - It extends the canonical
BaseApiClient, whose full definition is in the API Client Architecture. - It relies on
tokenServiceandauthEventsfrom the Authentication Architecture guide. For this example, assume these services provide methods likegetAccessToken,getRefreshToken,setTokens,clearTokens, and anEventEmitterfor auth-related events.
Request Queue Core Functionality
The core of the request queueing mechanism, as implemented within the AuthenticatedApiClientWithQueue (which aligns with the project's AuthenticatedApiClient pattern), revolves around these methods:
The queueRequest Method
This method is invoked when an API request fails due to an expired token (401 error) and a token refresh operation is already underway. It defers the execution of the failed request by adding it to a queue.
Key Function: queueRequest (within AuthenticatedApiClientWithQueue)
The processRequestQueue Method
Called after a successful token refresh, this method iterates over all requests in the queue, updates their authorization headers with the new token, and retries them.
The rejectRequestQueue Method
If the token refresh attempt fails, this method is called to reject all pending requests in the queue, ensuring that no requests are left hanging and that the application can handle the refresh failure appropriately.
These methods work in concert within the response interceptor of the AuthenticatedApiClientWithQueue to provide seamless handling of token expiration and refresh.
Integration in the Response Interceptor
The updated response interceptor in AuthenticatedApiClientWithQueue uses these methods:
Visualizing the Queue Flow
Testing Request Queueing
Testing the request queueing functionality is critical to ensure it works correctly under various conditions. Below are comprehensive test examples covering different scenarios.
Setup For Testing
First, set up the test environment with the necessary mocks. Note that AuthenticatedApiClientWithQueue would typically be imported from its definition, and its constructor might require specific configuration (e.g., baseURL) based on your project setup.
Test Case 1: Successful Token Refresh and Request Retry
Test Case 2: Multiple Concurrent Requests During Token Refresh
Test Case 3: Failed Token Refresh
Design Principles
Our request queueing implementation follows these key design principles:
-
Separation of Concerns: The queueing mechanism is encapsulated within the
AuthenticatedApiClientWithQueueclass, keeping authentication complexities hidden from application code. -
Efficiency: Only one token refresh operation is performed when multiple requests fail simultaneously.
-
Transparency: Requests are automatically retried after token refresh without requiring application code intervention.
-
Robustness: Failed token refreshes are handled gracefully, with appropriate error propagation and event notifications.
-
Progressive Enhancement: The queueing mechanism enhances the base API client capabilities defined in the API Client Architecture.
Alternative Approaches Considered
We evaluated several approaches before settling on our current implementation:
1. Global Axios Instance with Queue
Approach: Using a single global Axios instance with interceptors managing the queue.
Pros:
- Simpler implementation with less code
- Centralized queue management
Cons:
- Less flexibility for API clients with different base URLs or configurations
- Harder to test in isolation
- Potential for queue conflicts between different API domains
2. Redux Middleware for API Requests
Approach: Using Redux middleware to manage API requests and handle token refreshing.
Pros:
- Integrated with state management
- Potentially more visibility into request states
Cons:
- Tighter coupling between API layer and state management
- More complex implementation
- Not suitable for non-Redux applications
3. Separate Token Manager Service
Approach: Creating a separate service to manage token refresh, with API clients checking token validity before requests.
Pros:
- Clearer separation of responsibilities
- Potentially more reusable across different API client implementations
Cons:
- More complex coordination between services
- Potential for race conditions if not carefully implemented
- Additional overhead of token validity checks before each request
Conclusion
The request queueing pattern implemented in our AuthenticatedApiClientWithQueue provides a robust solution for handling token refreshes in a way that's transparent to application code. By following the principles and implementation described in this document, developers can ensure that API authentication remains seamless even when tokens expire during active application use.
This implementation builds upon the foundation established in the API Client Architecture and complements the authentication strategies outlined in the Authentication Architecture document.