Hone logo
Hone
Problems

Angular Runtime Caching for API Calls

Many Angular applications interact with APIs to fetch data. Repeatedly fetching the same data can be inefficient, leading to increased server load and slower user experiences. This challenge asks you to implement a runtime caching mechanism in Angular to store and retrieve API call results, avoiding unnecessary network requests.

Problem Description

Your task is to create a service in Angular that intercepts HTTP requests and implements a simple in-memory caching strategy. When a component requests data via HTTP, the caching service should first check if the data is already present in its cache. If it is, the cached data should be returned immediately. Otherwise, the request should proceed to the actual HTTP call, and the result should be stored in the cache before being returned to the component.

Key Requirements:

  • Cache Service: Create an Angular service (e.g., CacheService) responsible for managing the cache.
  • Cache Key Generation: Implement a mechanism to generate unique cache keys based on the request's URL and potentially its parameters.
  • Cache Storage: Use an in-memory data structure (e.g., a JavaScript Map or an object) to store cached responses.
  • Cache Retrieval: Provide a method to retrieve data from the cache using its key.
  • Cache Storage: Provide a method to store data in the cache with its corresponding key.
  • Interception: Modify Angular's HttpClient to use your CacheService. This can be achieved by creating an HttpInterceptor.
  • Cache Invalidation (Basic): For simplicity, assume that cached data is valid indefinitely. More advanced invalidation strategies are out of scope for this challenge.
  • Handling Non-GET Requests: Caching is typically only applied to GET requests. Other HTTP methods (POST, PUT, DELETE, etc.) should bypass the cache.

Expected Behavior:

  1. When a GET HTTP request is made, the HttpInterceptor should generate a cache key.
  2. The CacheService will be queried with this key.
  3. If data exists in the cache for that key, it will be returned immediately, and the actual HTTP request will not be sent.
  4. If data does not exist, the HTTP request will proceed.
  5. Once the HTTP request completes successfully, the CacheService will store the response data in the cache using the generated key.
  6. The response data will then be returned to the component.
  7. Non-GET requests will always proceed to the actual HTTP call without cache interaction.

Edge Cases:

  • Handling requests with query parameters.
  • Ensuring that different URLs with different parameters result in different cache keys.

Examples

Example 1: Basic GET Request

Imagine a component making a GET request to /api/users.

Scenario:

  1. First call to /api/users.
  2. Second call to /api/users shortly after.

Expected Behavior:

  • The first call will make an actual HTTP request to /api/users. The response will be stored in the cache.
  • The second call will find the data in the cache and return it immediately without making another HTTP request.

Example 2: GET Request with Query Parameters

Imagine a component making a GET request to /api/products?category=electronics&sort=price.

Scenario:

  1. First call to /api/products?category=electronics&sort=price.
  2. Second call to /api/products?category=electronics&sort=price.
  3. Third call to /api/products?category=clothing&sort=name.

Expected Behavior:

  • The first call will make an HTTP request to /api/products?category=electronics&sort=price. The response will be cached under a key representing this specific URL and its parameters.
  • The second call will find the data in the cache for the exact same URL and parameters and return it.
  • The third call will have different query parameters, leading to a different cache key. It will make a new HTTP request and cache its result separately.

Example 3: POST Request

Imagine a component making a POST request to /api/users to create a new user.

Scenario:

  • A POST request to /api/users.

Expected Behavior:

  • The POST request will not be cached. It will always proceed directly to the actual HTTP request, regardless of whether a cache entry for /api/users (from a GET request) exists.

Constraints

  • Cache Key Generation: The cache key should be a string. A simple approach is to concatenate the request URL and its serialized query parameters.
  • Cache Data: The cache should store the direct response data from the HttpClient.
  • Performance: The caching mechanism should add minimal overhead to non-cached requests. Cache lookups should be very fast.
  • Angular Version: Assumed to be a recent version of Angular (e.g., v10+).
  • HttpClient Module: You will be working with Angular's HttpClientModule and HttpClient.

Notes

  • Consider how to handle the Observable returned by HttpClient. You'll likely want to shareReplay or similar within your service to ensure multiple subscribers to the same cached request don't trigger multiple underlying HTTP calls.
  • The HttpInterceptor will receive an HttpRequest object and an HttpHandler object. You will call httpHandler.handle(request) to proceed with the request.
  • Think about how to create a robust cache key that uniquely identifies a request. The order of query parameters might matter if not handled carefully.
  • You will need to configure your HttpClient to use your interceptor in your AppModule or a relevant module.
Loading editor...
typescript