Skip to content

eariasvalor/04.02-Level-2-spring-boot-fruit-inventory-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🍎 Fruit API MySQL - Level 2

REST API for managing fruit stock with providers using MySQL database.

πŸ“‹ Table of Contents


πŸ“ Description

This project is a Spring Boot REST API for managing a fruit inventory system with providers. It allows you to:

  • Manage Providers: Create, read, update, and delete fruit suppliers
  • Manage Fruits: Track fruit stock with associated providers
  • Filter by Provider: Query fruits supplied by specific providers
  • Full CRUD Operations: Complete Create, Read, Update, Delete functionality

The application follows best practices including:

  • βœ… TDD (Test-Driven Development) Outside-In approach
  • βœ… Clean Architecture with MVC pattern
  • βœ… DTOs and validation with Bean Validation
  • βœ… Global exception handling
  • βœ… Database relationships with JPA
  • βœ… Docker containerization
  • βœ… Environment variable configuration

🎯 Requirements

Functional Requirements

Providers

  • Register new providers with name and country
  • No duplicate provider names allowed
  • List all registered providers
  • Update provider information
  • Delete providers (only if they have no associated fruits)

Fruits

  • Add fruits with name, weight (kg), and provider
  • All fruits must have an associated provider
  • Filter fruits by provider
  • List all fruits
  • Get fruit details by ID
  • Update fruit information (including changing provider)
  • Delete fruits

Non-Functional Requirements

  • Proper HTTP status codes (200, 201, 204, 400, 404, 409)
  • Input validation with error messages
  • Global exception handling
  • RESTful API design
  • MySQL database in production
  • H2 in-memory database for testing
  • Comprehensive test coverage (79+ tests)

πŸ› οΈ Technologies

Backend

  • Java 21 (LTS)
  • Spring Boot 3.4.1
  • Spring Web (REST Controllers)
  • Spring Data JPA (ORM)
  • Hibernate (JPA Implementation)

Database

  • MySQL 8.0 (Production)
  • H2 Database (Testing)

Validation & Mapping

  • Bean Validation (Jakarta Validation)
  • Lombok (Reduce boilerplate)

Testing

  • JUnit 5 (Test framework)
  • Mockito (Mocking)
  • MockMvc (Controller testing)
  • AssertJ (Assertions)

DevOps

  • Docker (Containerization)
  • Docker Compose (Multi-container orchestration)
  • Maven (Build tool)

πŸ“ Project Structure

fruit-api-mysql/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main/
β”‚   β”‚   β”œβ”€β”€ java/cat/itacademy/s04/t02/n02/fruit/
β”‚   β”‚   β”‚   β”œβ”€β”€ controller/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitController.java
β”‚   β”‚   β”‚   β”‚   └── ProviderController.java
β”‚   β”‚   β”‚   β”œβ”€β”€ service/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitService.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitServiceImpl.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ProviderService.java
β”‚   β”‚   β”‚   β”‚   └── ProviderServiceImpl.java
β”‚   β”‚   β”‚   β”œβ”€β”€ repository/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitRepository.java
β”‚   β”‚   β”‚   β”‚   └── ProviderRepository.java
β”‚   β”‚   β”‚   β”œβ”€β”€ model/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ Fruit.java
β”‚   β”‚   β”‚   β”‚   └── Provider.java
β”‚   β”‚   β”‚   β”œβ”€β”€ dto/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitRequestDTO.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitResponseDTO.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ProviderRequestDTO.java
β”‚   β”‚   β”‚   β”‚   └── ProviderResponseDTO.java
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ FruitMapper.java
β”‚   β”‚   β”‚   β”‚   └── ProviderMapper.java
β”‚   β”‚   β”‚   β”œβ”€β”€ exception/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ResourceNotFoundException.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ DuplicateResourceException.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ResourceConflictException.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ErrorResponse.java
β”‚   β”‚   β”‚   β”‚   └── GlobalExceptionHandler.java
β”‚   β”‚   β”‚   └── FruitApiMysqlApplication.java
β”‚   β”‚   └── resources/
β”‚   β”‚       β”œβ”€β”€ application.properties
β”‚   β”‚       └── application-prod.properties
β”‚   └── test/
β”‚       β”œβ”€β”€ java/cat/itacademy/s04/t02/n02/fruit/
β”‚       β”‚   β”œβ”€β”€ controller/
β”‚       β”‚   β”‚   β”œβ”€β”€ FruitControllerTest.java
β”‚       β”‚   β”‚   └── ProviderControllerTest.java
β”‚       β”‚   β”œβ”€β”€ service/
β”‚       β”‚   β”‚   β”œβ”€β”€ FruitServiceTest.java
β”‚       β”‚   β”‚   └── ProviderServiceTest.java
β”‚       β”‚   β”œβ”€β”€ integration/
β”‚       β”‚   β”‚   β”œβ”€β”€ FruitIntegrationTest.java
β”‚       β”‚   β”‚   └── ProviderIntegrationTest.java
β”‚       β”‚   └── FruitApiMysqlApplicationTests.java
β”‚       └── resources/
β”‚           └── application-test.properties
β”œβ”€β”€ .mvn/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ .dockerignore
β”œβ”€β”€ .env.example
β”œβ”€β”€ .gitignore
β”œβ”€β”€ pom.xml
β”œβ”€β”€ mvnw
β”œβ”€β”€ mvnw.cmd
└── README.md

βš™οΈ Setup & Installation

Prerequisites

  • Java 21 or higher
  • Maven 3.8+ (or use included Maven Wrapper)
  • Docker & Docker Compose
  • Git

1. Clone the Repository

git clone <repository-url>
cd fruit-api-mysql

2. Configure Environment Variables

Copy the .env.example file to .env:

cp .env.example .env

Edit .env with your credentials:

MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=fruitdb
MYSQL_USER=fruituser
MYSQL_PASSWORD=fruitpass

DB_URL=jdbc:mysql://localhost:3306/fruitdb
DB_USERNAME=fruituser
DB_PASSWORD=fruitpass

3. Start MySQL with Docker

docker-compose up -d mysql

Verify MySQL is running:

docker-compose ps

πŸš€ Running the Application

Option 1: Run with Maven (Development)

./mvnw spring-boot:run

The application will start on http://localhost:8080

Option 2: Run with Docker Compose (Production)

Build and start all services:

docker-compose up --build -d

View logs:

docker-compose logs -f app

Stop services:

docker-compose down

Option 3: Run JAR directly

./mvnw clean package -DskipTests
java -jar target/fruit-api-mysql-0.0.1-SNAPSHOT.jar

🌐 API Endpoints

Health Check

GET /actuator/health

Response: 200 OK

{
  "status": "UP"
}

Providers

Create Provider

POST /providers
Content-Type: application/json

{
  "name": "Fruits Inc",
  "country": "Spain"
}

Response: 201 Created

{
  "id": 1,
  "name": "Fruits Inc",
  "country": "Spain"
}

Get All Providers

GET /providers

Response: 200 OK

[
  {
    "id": 1,
    "name": "Fruits Inc",
    "country": "Spain"
  }
]

Get Provider by ID

GET /providers/{id}

Response: 200 OK or 404 Not Found

Update Provider

PUT /providers/{id}
Content-Type: application/json

{
  "name": "Updated Fruits Inc",
  "country": "Italy"
}

Response: 200 OK or 404 Not Found or 409 Conflict

Delete Provider

DELETE /providers/{id}

Response: 204 No Content or 404 Not Found or 409 Conflict


Fruits

Create Fruit

POST /fruits
Content-Type: application/json

{
  "name": "Apple",
  "weightInKilos": 10,
  "providerId": 1
}

Response: 201 Created

{
  "id": 1,
  "name": "Apple",
  "weightInKilos": 10,
  "provider": {
    "id": 1,
    "name": "Fruits Inc",
    "country": "Spain"
  }
}

Get All Fruits

GET /fruits/all

Response: 200 OK

Get Fruits by Provider

GET /fruits?providerId=1

Response: 200 OK or 404 Not Found

Get Fruit by ID

GET /fruits/{id}

Response: 200 OK or 404 Not Found

Update Fruit

PUT /fruits/{id}
Content-Type: application/json

{
  "name": "Updated Apple",
  "weightInKilos": 15,
  "providerId": 2
}

Response: 200 OK or 404 Not Found

Delete Fruit

DELETE /fruits/{id}

Response: 204 No Content or 404 Not Found


πŸ§ͺ Testing

Run All Tests

./mvnw test

Run Tests with Coverage (JaCoCo)

./mvnw clean test jacoco:report

View coverage report:

open target/site/jacoco/index.html

Test Statistics

  • Total Tests: 91
  • Controller Tests: 36
  • Service Unit Tests: 26
  • Integration Tests: 33
  • Coverage: >90%

Test Types

  • Unit Tests: Mockito for isolated testing
  • Controller Tests: MockMvc with @WebMvcTest
  • Integration Tests: @SpringBootTest with H2 database

🐳 Docker

Build Docker Image

docker build -t fruit-api-mysql:latest .

Multi-Stage Build

The Dockerfile uses a multi-stage build for optimization:

  1. Build Stage: Compiles the application with Maven (JDK 21)
  2. Runtime Stage: Runs the application with minimal JRE 21

Benefits:

  • Smaller image size (~250MB vs ~600MB)
  • Better security (no build tools in production)
  • Faster deployment

Docker Compose Services

services:
  mysql:     # MySQL 8.0 database
  app:       # Spring Boot application

Networks: fruit-network (bridge)
Volumes: mysql_data (persistent storage)

Useful Docker Commands

# Start services
docker-compose up -d

# View logs
docker-compose logs -f app

# Stop services
docker-compose down

# Remove volumes (⚠️ deletes data)
docker-compose down -v

# Rebuild images
docker-compose up --build

πŸ—„οΈ Database Schema

Tables

providers

CREATE TABLE providers (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL UNIQUE,
  country VARCHAR(255) NOT NULL
);

fruits

CREATE TABLE fruits (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  weight_in_kilos INT NOT NULL,
  provider_id BIGINT NOT NULL,
  FOREIGN KEY (provider_id) REFERENCES providers(id)
);

Relationship

  • Provider β†’ Fruit: One-to-Many (1:N)
  • Fruit β†’ Provider: Many-to-One (N:1)
  • Cascade delete: Deleting a provider with fruits returns 409 Conflict

πŸ”„ Development Process

TDD Outside-In Approach

For each feature, we followed this cycle:

  1. RED: Write failing acceptance test (Controller)
  2. GREEN: Implement minimal code to pass (Controller + mocked Service)
  3. RED: Write failing unit test (Service)
  4. GREEN: Implement Service logic
  5. REFACTOR: Clean up code
  6. INTEGRATION: Write end-to-end test
  7. COMMIT: Save working feature

Example Workflow

Controller Test (MockMvc) ❌
    ↓
Controller Implementation βœ…
    ↓
Service Test (Mockito) ❌
    ↓
Service Implementation βœ…
    ↓
Repository & Entity
    ↓
Integration Test (@SpringBootTest) βœ…
    ↓
Commit πŸŽ‰

πŸ“š Assignment Details

Course Information

  • Course: IT Academy - Spring Framework
  • Sprint: S4 - API REST with Spring Boot
  • Level: Level 2 - MySQL Integration
  • Group: cat.itacademy.s04.t02.n02
  • Artifact: fruit-api-mysql

Learning Objectives

βœ… Create REST APIs with Spring Boot
βœ… Persist data with Spring Data JPA
βœ… Apply HTTP verbs and status codes correctly
βœ… Implement dynamic routes with Path and Query Params
βœ… Write automated tests with TDD
βœ… Handle exceptions globally with @ControllerAdvice
βœ… Structure projects with MVC pattern
βœ… Create entity relationships with JPA
βœ… Use DTOs and validate input data
βœ… Containerize applications with Docker
βœ… Configure databases with environment variables

User Stories Completed

Providers (4 stories)

  1. βœ… Register a new provider
  2. βœ… List all providers
  3. βœ… Update provider information
  4. βœ… Delete a provider

Fruits (6 stories)

  1. βœ… Add fruit with provider
  2. βœ… Filter fruits by provider
  3. βœ… List all fruits
  4. βœ… Get specific fruit by ID
  5. βœ… Update fruit information
  6. βœ… Delete a fruit

About

RESTful API built with Java 21 and Spring Boot for managing fruit inventory and providers. Implements clean architecture, MySQL database, Docker containerization, and a Test-Driven Development (TDD) approach.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors