Angular HTTP Loading Interceptor
Creating a loading interceptor in Angular is a common requirement for providing a better user experience during HTTP requests. This challenge asks you to build an HTTP interceptor that displays a loading indicator while requests are in flight and hides it when requests complete. This is useful for preventing users from thinking the application is frozen while waiting for data.
Problem Description
You need to implement an Angular HTTP interceptor that intercepts all outgoing HTTP requests and sets a loading state. This loading state should be managed by a service that your components can subscribe to. The interceptor should:
- Set a loading flag: When an HTTP request is made, the interceptor should set a global loading flag to
true. - Reset the loading flag: When the HTTP request completes (either successfully or with an error), the interceptor should set the global loading flag to
false. - Provide a LoadingService: Create a
LoadingServicethat holds the loading state and provides aisLoadingobservable that components can subscribe to. - Handle Errors: The interceptor should gracefully handle errors and ensure the loading flag is set to
falseeven in error scenarios.
Key Requirements:
- The interceptor must intercept all outgoing HTTP requests.
- The
LoadingServicemust provide a reactiveisLoadingobservable. - The loading indicator should be displayed/hidden based on the
isLoadingobservable. - The interceptor should not modify the request or response data. It should only manage the loading state.
Expected Behavior:
- When a component makes an HTTP request, the
isLoadingobservable should emittrue. - When the request completes (success or error), the
isLoadingobservable should emitfalse. - Components subscribing to
isLoadingshould update their UI accordingly (e.g., show a spinner whentrue, hide it whenfalse).
Edge Cases to Consider:
- Cancelled Requests: Handle requests that are cancelled before completion. Ensure the loading flag is reset.
- Multiple Concurrent Requests: The loading indicator should remain active as long as any request is in progress.
- Error Handling: Ensure the loading indicator is hidden even if a request fails.
Examples
Example 1:
Input: A component makes an HTTP GET request to '/api/data'.
Output: The LoadingService's isLoading observable emits true immediately before the request is sent, and emits false after the request completes (regardless of success or failure).
Explanation: The interceptor intercepts the GET request, sets isLoading to true, and then resets it upon completion.
Example 2:
Input: Two components make HTTP requests concurrently (one GET, one POST).
Output: The LoadingService's isLoading observable emits true before either request is sent, and remains true until both requests complete. It then emits false.
Explanation: The interceptor handles multiple concurrent requests correctly, keeping isLoading true as long as any request is in progress.
Example 3:
Input: An HTTP request fails with a 500 error.
Output: The LoadingService's isLoading observable emits true before the request is sent, and emits false after the error is caught.
Explanation: The interceptor handles the error and ensures isLoading is reset even in failure scenarios.
Constraints
- Angular Version: Angular 14 or higher.
- RxJS: RxJS 7 or higher.
- Performance: The interceptor should not introduce significant performance overhead. Avoid unnecessary computations or complex logic within the interceptor.
- Code Quality: The code should be well-structured, readable, and follow Angular best practices.
Notes
- Consider using RxJS operators like
takeUntilto manage subscriptions and prevent memory leaks. - The
LoadingServicecan use a simple boolean variable and aSubjectorBehaviorSubjectto manage the loading state. - Focus on the core functionality of the interceptor and the loading service. You don't need to implement a full-fledged loading indicator component. The challenge is about the interceptor and service interaction.
- Think about how to handle request cancellation gracefully.