A RESTful API for managing products built with Symfony 7.4 and PHP 8.2. Features complete CRUD operations, Swagger documentation, and comprehensive test coverage.
- RESTful API - Full CRUD operations for products
- Swagger Documentation - Interactive API documentation with OpenAPI 3.0
- Service Layer Architecture - Clean separation of concerns
- Validation - Input validation with detailed error messages
- Unit Tests - Comprehensive test coverage with PHPUnit 11
- Code Coverage Reports - HTML coverage reports with Xdebug
| Technology | Version |
|---|---|
| PHP | 8.2+ |
| Symfony | 7.4 |
| Doctrine ORM | 3.x |
| PHPUnit | 11.x |
| NelmioApiDocBundle | 5.x |
- PHP 8.2 or higher
- Composer
- MySQL 8.0+ or PostgreSQL 13+
- Xdebug (optional, for code coverage)
git clone https://github.com/mahirsust/product-api.git
cd product-apicomposer installCopy the environment file and configure your database:
cp .env .env.localGenerate APP_SECRET:
php -r "echo bin2hex(random_bytes(16));"Edit .env.local:
APP_SECRET=paste_generated_secret_here
DATABASE_URL="mysql://username:password@127.0.0.1:3306/database_name?serverVersion=8.0"php bin/console doctrine:database:create
php bin/console doctrine:migrations:migratephp -S localhost:8000 -t public| Method | Endpoint | Description |
|---|---|---|
| GET | /api/products |
List all products (paginated) |
| GET | /api/products/{id} |
Get a single product |
| POST | /api/products |
Create a new product |
| PUT | /api/products/{id} |
Update a product (full) |
| PATCH | /api/products/{id} |
Update a product (partial) |
| DELETE | /api/products/{id} |
Delete a product |
| GET | /api/products/search |
Search products with filters |
Interactive Swagger documentation is available at:
http://localhost:8000/api/doc
curl -X POST http://localhost:8000/api/products \
-H "Content-Type: application/json" \
-d '{
"name": "Wireless Keyboard",
"description": "High-quality wireless keyboard with RGB lighting",
"price": 49.99,
"quantity": 100
}'Response:
{
"id": 1,
"name": "Wireless Keyboard",
"description": "High-quality wireless keyboard with RGB lighting",
"price": "49.99",
"quantity": 100,
"createdAt": "2026-02-09T21:30:00+00:00",
"updatedAt": null
}curl http://localhost:8000/api/products?page=1&limit=10Response:
{
"data": [
{
"id": 1,
"name": "Wireless Keyboard",
"price": "49.99",
"quantity": 100
}
],
"meta": {
"total": 1,
"page": 1,
"limit": 10,
"pages": 1
}
}curl "http://localhost:8000/api/products/search?name=keyboard&minPrice=20&maxPrice=100&inStock=true"curl -X PATCH http://localhost:8000/api/products/1 \
-H "Content-Type: application/json" \
-d '{
"price": 39.99
}'curl -X DELETE http://localhost:8000/api/products/1product-api/
├── src/
│ ├── Controller/
│ │ └── Api/
│ │ └── ProductController.php
│ ├── Dto/
│ │ └── ProductDto.php
│ ├── Entity/
│ │ └── Product.php
│ ├── Exception/
│ │ ├── ProductNotFoundException.php
│ │ └── ValidationException.php
│ ├── Repository/
│ │ └── ProductRepository.php
│ └── Service/
│ ├── ProductService.php
│ └── ProductServiceInterface.php
├── tests/
│ └── Unit/
│ └── Service/
│ └── ProductServiceTest.php
├── config/
├── migrations/
├── public/
├── .env
├── composer.json
├── phpunit.xml.dist
└── README.md
┌─────────────────────────────────────────────────────────────────┐
│ HTTP Request │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ProductController │
│ • Handles HTTP request/response │
│ • Deserializes JSON to DTO │
│ • Returns JSON responses │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ProductService │
│ • Business logic │
│ • Validation │
│ • Data transformation │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ProductRepository │
│ • Database operations │
│ • Query building │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Database │
└─────────────────────────────────────────────────────────────────┘
composer testvendor/bin/phpunit --testdoxvendor/bin/phpunit tests/Unit/Service/ProductServiceTest.phpvendor/bin/phpunit --filter testCreateProductSuccessfullycomposer test:coverageThen open the report:
# Windows
start coverage/index.html
# macOS
open coverage/index.html
# Linux
xdg-open coverage/index.html| Command | Description |
|---|---|
composer test |
Run all tests |
composer test:unit |
Run unit tests only |
composer test:coverage |
Generate HTML coverage report |
This project uses GitHub Actions for continuous integration. The pipeline triggers on every push and pull request to the main and develop branches.
| Workflow | Trigger | Description |
|---|---|---|
| CI | Push, Pull Request | Runs tests, code quality checks |
The CI pipeline runs on every push and pull request:
- ✅ Runs on PHP 8.2 and 8.3
- ✅ Installs dependencies
- ✅ Runs PHPUnit tests (with mocks)
- ✅ Generates code coverage
- ✅ Validates composer.json (strict mode)
- ✅ Checks for security vulnerabilities
{
"errors": {
"name": "Product name is required",
"price": "Price must be a positive number"
}
}{
"error": "Product with ID 123 was not found."
}# Clear cache
php bin/console cache:clear
# Create migration
php bin/console make:migration
# Run migrations
php bin/console doctrine:migrations:migrate
# Validate database schema
php bin/console doctrine:schema:validate
# View routes
php bin/console debug:routerThis project is licensed under the MIT License.