Feature Implementation Plan: Complete API Caching Implementation¶
📋 Todo Checklist¶
- [ ] Prerequisite: Verify that the DTO/Mapper/Caching pattern is working for
/api/varietiesand/api/locations/regions. - [ ] List Endpoints:
- [ ] Apply the DTO caching pattern to the
/api/processing-methodsendpoint. - [ ] Apply the DTO caching pattern to the
/api/coffee-beansendpoint. - [ ] Apply the DTO caching pattern to the
/api/roastersendpoint. - [ ] Apply the DTO caching pattern to the
/api/speciesendpoint. - [ ] Apply the DTO caching pattern to the
/api/roast-levelsendpoint. - [ ] Apply the DTO caching pattern to the
/api/locations/countriesendpoint.
- [ ] Apply the DTO caching pattern to the
- [ ] Detail Endpoints:
- [ ] Implement caching for all individual detail (
/{id}) endpoints.
- [ ] Implement caching for all individual detail (
- [ ] Static Endpoints:
- [ ] Implement caching for
/api/filters/metadataand/api/flavor-wheel.
- [ ] Implement caching for
- [ ] Invalidation:
- [ ] Update the
CacheInvalidationSubscriberto handle all newly cached entity types.
- [ ] Update the
- [ ] Testing:
- [ ] Write integration tests to verify caching for all newly covered endpoints.
🔍 Analysis & Investigation¶
Codebase Structure¶
- DTOs: New DTO classes will be created in
src/DTO/Api/forCoffeeBean,Roaster,RoastLevel, etc. - Mapper: The
src/Service/Api/Mapper/EntityToDtoMapper.phpwill be expanded with new methods to handle the conversion for all new DTOs. - Repositories: The
findByRequestandfindmethods in all relevant repositories will be updated to implement the caching pattern. - Event Subscriber: The
src/EventSubscriber/CacheInvalidationSubscriber.phpwill be updated to be comprehensive.
Current Architecture & Problem¶
- Problem: The high-performance, DTO-based caching architecture has been successfully implemented for
VarietiesandRegionsbut has not yet been rolled out across the entire API. This leaves critical endpoints like/api/coffee-beansuncached and vulnerable to performance issues. - Solution: This plan is the final step in the caching initiative. It applies the now-proven DTO caching pattern systematically to every remaining read-only endpoint, ensuring 100% cache coverage and a consistently fast API.
Dependencies & Integration Points¶
- This plan builds directly on the successful implementation for
VarietiesandRegions. It uses the same established patterns and services (EntityToDtoMapper,CacheKeyGenerator,TagAwareCacheInterface).
Considerations & Challenges¶
CoffeeBeanComplexity: TheCoffeeBeanentity is the most complex, with many relationships. Creating its DTO (CoffeeBeanDTO) and mapping logic will require careful attention to ensure all necessary nested data (likeVarietyDTO,RegionDTO, etc.) is included correctly.- Thoroughness: The main challenge is meticulous execution. Every endpoint must be updated, and every entity must have a corresponding entry in the
CacheInvalidationSubscriber.
📝 Implementation Plan¶
Prerequisites¶
- The DTO, Mapper, and caching pattern is already successfully implemented for Varieties and Regions.
Step-by-Step Implementation¶
-
Expand DTOs and Mapper
- Action: For each of the following entities, create a corresponding DTO in
src/DTO/Api/and a mapping method inEntityToDtoMapper:ProcessingMethod->ProcessingMethodDTOCoffeeBean->CoffeeBeanDTO(This will be the most complex, including nested DTOs for its relations).Roaster->RoasterDTOSpecies->SpeciesDTORoastLevel->RoastLevelDTOCountry->CountryDTO
- Action: For each of the following entities, create a corresponding DTO in
-
Refactor List Endpoints
- Action: For each of the corresponding repositories (
ProcessingMethodRepository,CoffeeBeanRepository, etc.), refactor thefindByRequestmethod to:- Use the
CacheKeyGenerator. - Wrap the logic in an
apiCache->get()call. - Tag the cache item appropriately (e.g.,
['coffee_bean_list']). - Fetch the paginated entities.
- Use the
EntityToDtoMapperto convert the entities to DTOs. - Return the cacheable array
['items' => $dtos, 'totalItems' => $count].
- Use the
- Action: Update the corresponding controller methods to handle the new array-based return type from the repository.
- Action: For each of the corresponding repositories (
-
Implement Caching for Detail (
/{id}) Endpoints- Action: For every repository, update the
find()method (or the method used by the detail endpoint) to cache its result. - Example (
RoasterRepository):public function find($id, ...): ?Roaster { $cacheKey = 'roaster_detail_' . $id; return $this->apiCache->get($cacheKey, function (ItemInterface $item) use ($id) { $item->tag(['roasters_detail', 'roaster_' . $id]); // The actual find logic return $this->createQueryBuilder('r')->where('r.id = :id')->setParameter('id', $id)->getQuery()->getOneOrNullResult(); }); }
- Action: For every repository, update the
-
Update
CacheInvalidationSubscriber- Files to modify:
src/EventSubscriber/CacheInvalidationSubscriber.php - Action: This is a critical step. Add a
matcharm for every entity that is now cached.
- Files to modify:
Testing Strategy¶
- Integration Tests:
- For each newly cached endpoint (both list and detail), create a test that follows the "request -> update entity -> request again" pattern to verify that cache invalidation is working correctly.
- Verify that the JSON response for each endpoint correctly reflects the structure of its DTO.
🎯 Success Criteria¶
- All read-only API endpoints, including the critical
/api/coffee-beans, are now cached using the DTO pattern. - The
CacheInvalidationSubscriberis comprehensive, ensuring data freshness across the entire API. - The API is consistently fast and resilient, with cache coverage at or near 100% for read operations.
- The
refactor-lists-for-caching-with-dtos.mdplan is now fully superseded and can be removed.