Feature Implementation Plan: Unify API Schemas and DTOs¶
📋 Todo Checklist¶
- [ ] Clarify the roles of
ApiSchemaandDTOfiles in the project's documentation. - [ ] Synchronize
ApiSchema/Roaster.phpwithDTO/Api/RoasterDTO.php. - [ ] Synchronize
ApiSchema/CoffeeBean.phpwithDTO/Api/CoffeeBeanDTO.php. - [ ] Audit all other
ApiSchemaandDTOpairs for inconsistencies. - [ ] Update
CoffeeBeanRepository::findByRequestto ensure it returnsCoffeeBeanDTOs. - [ ] Final Review and Testing.
🔍 Analysis & Investigation¶
The Role of ApiSchema vs. DTO¶
A core point of confusion is the presence of two sets of similar-looking classes. Their roles are distinct:
- src/DTO/Api/*.php (Data Transfer Objects): These classes define the actual structure of data returned by the API. They are the source of truth for what the frontend receives.
- src/ApiSchema/*.php (OpenAPI Schema Definitions): These classes are purely for documentation. They use attributes to describe the API's JSON response shape for generating the OpenAPI (Swagger) documentation.
The frontend is supposed to use the data structure defined by the DTO. The ApiSchema should be a perfect mirror of that DTO to ensure the documentation is accurate.
Identified Inconsistencies¶
The key issue is that the ApiSchema definitions have drifted from the DTO definitions, leading to incorrect API documentation.
Roastervs.RoasterDTO: As identified previously, the main inconsistency was caused by some endpoints returning raw entities instead of DTOs. TheApiSchema/Roaster.phpandDTO/Api/RoasterDTO.phpare actually quite similar, but the documentation was being applied to inconsistently serialized objects.CoffeeBeanvs.CoffeeBeanDTO: There are significant differences here:- Missing in Schema:
ApiSchema/CoffeeBean.phpis missingnonStandardFlavorNotes,originType,singleOrigin, andstatus. - Incorrect Nullability:
description,url,suitableForEspresso, andsuitableForFilterhave incorrect nullability settings in the schema compared to the DTO. - Incorrect Nested Types: The schema incorrectly points to other
ApiSchemaclasses (e.g.,Roaster::class) instead of describing the structure of the nested DTOs (e.g.,RoasterDTO).
- Missing in Schema:
This audit reveals a systemic problem: the documentation does not reliably reflect the actual API responses.
📝 Implementation Plan¶
Prerequisites¶
No special prerequisites are required.
Step-by-Step Implementation¶
-
Step 1: Synchronize
ApiSchema/Roaster.php- File to modify:
src/ApiSchema/Roaster.php - Changes needed: Review every property in
DTO/Api/RoasterDTO.phpand ensureApiSchema/Roaster.phpmatches it exactly in terms of property names, types, and nullability. The nestedcrawlConfigsproperty should be explicitly defined to match theRoasterCrawlConfigDTOstructure, not just a reference to another schema class.
- File to modify:
-
Step 2: Synchronize
ApiSchema/CoffeeBean.php- File to modify:
src/ApiSchema/CoffeeBean.php - Changes needed:
- Add the missing properties:
nonStandardFlavorNotes(as an array of strings),originType(string),singleOrigin(boolean), andstatus(string). - Correct the nullability for
description,url,suitableForEspresso, andsuitableForFilterto match the DTO. - Update all
ref: new Model(...)properties to point to the correct DTO's schema definition (e.g., theroasterproperty should reference the now-correctedApiSchema/Roaster.php).
- Add the missing properties:
- File to modify:
-
Step 3: Audit and Synchronize All Other API Entities
- Files to modify: All files in
src/ApiSchema/and potentiallysrc/DTO/Api/. - Changes needed: Systematically go through every DTO in
src/DTO/Api/and ensure its correspondingApiSchemafile is an exact match. This includes, but is not limited to:Countryvs.CountryDTOPricevs.PriceDTORegionvs.RegionDTO- And all others.
- Files to modify: All files in
-
Step 4: Correct the Return Value in
CoffeeBeanRepository- File to modify:
src/Repository/CoffeeBeanRepository.php - Changes needed: As per the original plan, ensure the
executeCoffeeBeanQuerymethod uses theentityToDtoMapperto map the final list of entities toCoffeeBeanDTOs before returning them. This is the crucial step that ensures the API actually returns the correctly structured data that the documentation now describes.
// src/Repository/CoffeeBeanRepository.php // ... inside executeCoffeeBeanQuery method ... $entities = $entitiesQb->getQuery()->getResult(); // Ensure this mapping is performed $coffeeBeanDtos = $this->entityToDtoMapper->mapCoffeeBeansToDtos($entities); return [ 'items' => $coffeeBeanDtos, 'totalItems' => $totalItems, ]; - File to modify:
Testing Strategy¶
-
API Documentation Review:
- After making the changes, regenerate the OpenAPI documentation.
- Thoroughly review the schemas for
CoffeeBean,Roaster, and other entities in the Swagger UI. Verify that all properties, types, and nullability constraints match the DTO definitions.
-
API Endpoint Testing:
- Make a
GETrequest to/api/coffee-beans. - Confirm that the structure of the
roasterobject and other nested objects within each coffee bean in the response now perfectly matches the structure returned by their direct endpoints (e.g.,/api/roasters/{id}). - Verify that all fields documented in the updated schema are present in the response, and that nullability rules are respected.
- Make a
🎯 Success Criteria¶
- The API's OpenAPI (Swagger) documentation is 100% accurate and reflects the true structure of the JSON responses for all endpoints.
- The
/api/coffee-beansendpoint returns aroasterobject that is identical in structure to the one returned by/api/roasters/{id}. - There is a clear and documented understanding that
DTOsdefine the API's true shape, andApiSchemafiles are for documenting that shape.