Skip to content

Feature Implementation Plan: top-level-countries-endpoint

📋 Todo Checklist

  • [ ] Create a new CountryController for the top-level endpoint.
  • [ ] Create a new CountryCsvReaderService for reading country data from CSV.
  • [ ] Add OpenAPI documentation for the new endpoint.
  • [ ] Implement caching for the country data.
  • [ ] Write integration tests for the new endpoint.
  • [ ] Final Review and Testing.

🔍 Analysis & Investigation

Codebase Structure

The project is a Symfony application. The feature requires a new controller in src/Controller/Api/ and a new service in src/Service/. The data source is the CSV file located at resources/countries-en.csv.

Current Architecture

The application follows a standard Symfony architecture. By creating a new CountryController, we are introducing a new top-level resource, /api/countries, which is distinct from the existing /api/locations resource. This aligns with REST principles by separating the resource of "all countries in the world" from the more specific resource of "coffee-producing locations." This approach promotes a clean separation of concerns.

Dependencies & Integration Points

  • Symfony Framework: The core of the application. We will use the AbstractController's json() method.
  • NelmioApiDocBundle: For documenting the new API endpoint using OpenAPI annotations.
  • CSV File: The resources/countries-en.csv file is the data source.

Considerations & Challenges

  1. Performance: Reading and parsing the CSV file on every request is inefficient. A caching mechanism is essential.
  2. Error Handling: The implementation must gracefully handle cases where the CSV file is missing or unreadable.
  3. Data Structure: The frontend needs a simple list of countries for a dropdown or selector. The response should be filtered to include only the necessary fields (country_iso_code and country_name) to minimize payload size.
  4. Code Reusability: The logic for reading and parsing the CSV should be encapsulated in a dedicated service (CountryCsvReaderService) to promote reusability and a clean separation of concerns.

📝 Implementation Plan

Prerequisites

  • Ensure the resources/countries-en.csv file is present and readable.

Step-by-Step Implementation

  1. Create CountryCsvReaderService:

    • Files to modify: src/Service/CountryCsvReaderService.php (new file)
    • Changes needed:
      • Create a new service class CountryCsvReaderService.
      • Inject Symfony's ParameterBagInterface to get the project directory path.
      • Implement a public method getCountries() that reads, parses, and caches the country data from resources/countries-en.csv.
      • The method should return an array of countries, where each country is an associative array containing only country_iso_code and country_name.
      • Implement simple in-memory caching (e.g., using a static property) to avoid file I/O on subsequent requests within the same process.
  2. Register the Service:

    • Files to modify: config/services.php
    • Changes needed:
      • Ensure the new CountryCsvReaderService is registered for autowiring. Symfony's default service configuration should handle this automatically.
  3. Create CountryController:

    • Files to modify: src/Controller/Api/CountryController.php (new file)
    • Changes needed:
      • Create a new controller class CountryController that extends AbstractController.
      • Define a top-level route for the controller: #[Route('/api/countries', name: 'api_countries_')].
      • Inject the new CountryCsvReaderService into the controller's constructor.
      • Create a new public method getAllCountries().
      • Add the #[Route('', name: 'list', methods: ['GET'])] attribute to the method.
      • Implement the method to call getCountries() from the CountryCsvReaderService and return the data as a JsonResponse.
      • Include a try-catch block for robust error handling.
  4. Add OpenAPI Documentation:

    • Files to modify: src/Controller/Api/CountryController.php
    • Changes needed:
      • Add #[OA\Get] and #[OA\Response] annotations to the getAllCountries() method.
      • The documentation should define the path as /api/countries, provide a clear summary and description, and assign it to a "Locations" or a new "Countries" tag.
      • The response schema should reflect the filtered array of countries (country_iso_code, country_name).

Testing Strategy

  1. Integration Test:
    • Create a new test file tests/Controller/Api/CountryControllerTest.php.
    • Write a test case for the /api/countries endpoint.
    • The test should:
      • Make a GET request to the endpoint.
      • Assert that the response has a 200 OK status code.
      • Assert that the response content is valid JSON.
      • Assert that the returned JSON contains an array of countries with the expected keys (country_iso_code, country_name).
      • Assert that a known country (e.g., "United States") is present in the response.
  2. Manual Testing:
    • Run the application locally.
    • Access the endpoint http://localhost/api/countries using a browser or API client.
    • Verify that the response is correct and matches the documentation.

🎯 Success Criteria

  • A GET request to /api/countries returns a JSON array of all countries from the CSV file.
  • The response is cached to ensure good performance.
  • The endpoint is clearly documented in the OpenAPI specification.
  • The implementation includes passing integration tests.