← Back to projects

Case Study

A REST API that models the full lifecycle of my own job applications, from "applied" to "accepted". Deliberately built as a practice project during my job search to sharpen API design, containerisation and automated testing.

My role

Sole developer: API design, domain logic, database modelling, tests and the Docker setup are entirely my work. I built it to practise backend development and DevOps.

Result

A working, fully containerised REST API with a clean status lifecycle, consistent HTTP responses and 15 passing tests. A compact demonstration of API design, testing discipline and Docker knowledge.

Tech stack

  • Backend: PHP 8.3, Symfony 7, Doctrine ORM
  • Database: MySQL 8
  • Infrastructure: Docker & Docker Compose (Nginx, PHP-FPM, MySQL as separate containers)
  • Tests: PHPUnit, unit and functional tests (15 tests)

Challenges & solutions

1. Enforcing valid status transitions

An application must not jump from any status to any other (e.g. not directly from "applied" to "accepted"). The transition logic lives as its own business rule in the domain code rather than scattered across the controller, with a dedicated PATCH endpoint for status changes.

2. Clean REST design instead of raw CRUD endpoints

Endpoints return consistent HTTP status codes (200, 201, 204, 404, 422) and structured validation errors, so a client can reliably distinguish "invalid input" from "not found".

3. Test-driven from the start

15 tests cover both the status logic at the unit level and the HTTP endpoints functionally. I used this project to practise writing tests alongside functionality instead of afterwards.

4. A reproducible environment with Docker

Nginx, PHP-FPM and MySQL run as separate containers via Docker Compose. A single "docker compose up -d --build" plus migrations is enough to run the application identically anywhere.