This project is a RESTful API that accepts a CSV file to import news. It processes the entire file asynchronously, even if some rows are invalid, and provides a mechanism to track the status and results of each import request.
The Docker environment for this project is based on the dunglas/symfony-docker setup. It has been configured to suit the needs of this specific project.
This project follows the principles of Clean Architecture in a pragmatic way. For instance, while the Domain
layer should ideally be completely independent of any framework or library, I've used Doctrine attributes directly on Domain entities. I consider these attributes as metadata that simplifies maintenance and readability, avoiding the verbosity of separate mapping files (like XML or YAML) without tightly coupling the core domain logic to the persistence layer.
Given the time constraints, the focus of testing was on ensuring the application's core features work as expected from a user's perspective. Therefore, the project is covered by functional tests that simulate real API requests and validate the responses. While unit tests are valuable, I prioritized end-to-end functional tests to guarantee the main use cases are solid. You can run the test suite using the following command:
make phpunit
For simplicity, this project is configured to run one worker per container. In a production environment, it is recommended to use a process control system like Supervisor to manage multiple worker processes, ensuring better performance and reliability. To prevent race conditions and ensure that each import file is processed by only one worker at a time, the application uses Symfony's Lock component.
This project is fully containerized using Docker and is composed of the following services:
- PHP 8.4: The application runtime.
- Symfony 7.3: The PHP framework.
- PostgreSQL: The relational database for storing import requests and news articles.
- RabbitMQ: The message broker for handling asynchronous import processing.
- Caddy: A modern web server that also acts as a Mercure hub.
Make sure you have Docker Compose (v2.10+) installed on your system.
- Clone the repository.
- Run the following command to build and start the containers in the background:
make build make up
- Open
https://localhost
in your browser and accept the self-signed TLS certificate to access the application.
The Makefile
provides several commands to manage the project:
make up
: Builds and starts the Docker containers.make down
: Stops and removes the Docker containers.make stop
: Stops the running containers.make restart
: Restarts the containers.make php
: Opens a bash session inside thephp
container.make database
: Opens a bash session inside thedatabase
container.make csfix
: Runs the PHP code style fixer.make phpunit
: Executes the functional test suite.make dbreset
: Drops and recreates the development database.make dbresettest
: Drops and recreates the test database.
The API accepts CSV files with the following structure:
title,content,category,URL
News Headline,Some content goes here,Tech-World-Politics,https://example.com
Another News,More content,Tech
Field Requirements:
title
(required): The news article titlecontent
(required): The article contentcategory
(required): One or multiple categories separated by dashes (e.g., "Tech-World-Politics")URL
(optional): Must be a valid URL if provided
Sample CSV files are available in the tests/Data/
directory:
good.csv
: Valid CSV data for testing successful importsbad_records.csv
: CSV with validation errors for testing error handlingbad_headers.csv
: CSV with incorrect headers for testing format validation
A Postman collection is available in the root of the project at postman_collection.json
to help you test the API endpoints.
POST /api/v1/news/import
: Upload a CSV file for processing- Returns an import request ID immediately
- Processing happens asynchronously in the background
GET /api/v1/news/import
: List all import requests with filtering capabilitiesGET /api/v1/news/import/{id}
: Get the status and details of a specific import requestGET /api/v1/news/import/{id}/errors
: Download the error report CSV file for failed imports