A backend REST API for a simple eCommerce application, built with Spring Boot as a learning project to understand core Spring concepts and how to structure a scalable layered architecture.
- Author: Koketso Gaowelwe
- Start date: 19/06/2026
- Purpose: Understand the fundamentals of Spring Boot and build the ability to structure and scale applications as they grow.
⚠️ Project status: in progress. The full data and service layers are implemented across all three domains (Product, Category, Image). The Image controller is functional with upload and download endpoints. Product and Category controllers are scaffolded but not yet wired up. See Roadmap below.
- Java 17
- Spring Boot 4.1.0
- Spring Web MVC (
spring-boot-starter-webmvc) - Spring Data JPA (
spring-boot-starter-data-jpa) - Spring Validation (
spring-boot-starter-validation) - Spring Boot Actuator
- Spring Web MVC (
- MySQL — accessed via Hibernate/JPA (
mysql-connector-j) - Lombok — reduces boilerplate on entity, service, and DTO classes
- Maven — build and dependency management
- JUnit 5 — testing (currently default context-load test)
src/main/java/com/API/eCommerce/
├── ECommerceApplication.java
│
├── model/
│ ├── Product.java
│ ├── Category.java
│ └── Image.java
│
├── Repository/
│ ├── productRepository.java
│ ├── categoryRepository.java
│ └── imageRepository.java
│
├── service/
│ ├── Product/
│ │ ├── iProductService.java
│ │ └── ProductService.java
│ ├── Category/
│ │ ├── iCategoryService.java
│ │ └── CategoryService.java
│ └── Image/
│ ├── iImageService.java
│ └── ImageService.java
│
├── controller/
│ ├── ProductController.java ⬜ stub — not yet implemented
│ ├── CategoryController.java ⬜ stub — not yet implemented
│ └── ImageController.java ✅ implemented
│
├── DTOs/
│ └── ImageDTO.java
│
├── request/
│ └── AddProductRequest.java
│
├── response/
│ └── ApiResponse.java
│
└── Exceptions/
├── ProductNotFoundException.java
├── ResourceNotFoundException.java
└── AlreadyExistException.java
Three JPA entities with mapped relationships:
Product—id,name,brand,price,quantity,description. Belongs to oneCategory(@ManyToOne, cascading) and owns manyImages (@OneToMany, cascading + orphan removal).Category—id,name, and a one-to-many back-reference to itsProducts.Image—id,fileName,fileType, raw image data stored as aBlob(@Lob),downloadUrl, and a@ManyToOnelink back to itsProduct.
All three repositories extend JpaRepository. productRepository adds derived query methods beyond standard CRUD:
| Method | Description |
|---|---|
findByCategory(String) |
All products in a category |
findByBrand(String) |
All products by brand |
findByName(String) |
Products matching name |
findByBrandAndCategory(String, String) |
Filter by brand + category |
findByBrandAndName(String, String) |
Filter by brand + name |
countByBrandAndName(String, String) |
Count by brand + name |
categoryRepository adds findByName(String) and existsByName(String).
All three service contracts (interface + implementation) are complete:
ProductService — full CRUD plus queries by category, brand, name, and combinations. Throws ProductNotFoundException on missing IDs.
CategoryService — get all, get by ID, get by name, add (with duplicate-name guard via AlreadyExistException), update by ID, delete by ID. Throws ResourceNotFoundException on missing entries.
ImageService — get by ID, delete by ID, save a batch of MultipartFile images linked to a product (stored as SerialBlob, returns ImageDTO list with generated download URLs), and update an existing image file.
ImageDTO—id,fileName,downloadUrl— used as the API response shape for image data.AddProductRequest— flat request object (name,brand,price,quantity,description,category) for creating products.ApiResponse— generic wrapper{ message, data }used by controllers to return consistent responses.
| Exception | When thrown |
|---|---|
ProductNotFoundException |
Product ID not found |
ResourceNotFoundException |
Category or Image ID/name not found |
AlreadyExistException |
Category with same name already exists |
Base path: /api/v1 (configured in application.properties)
The only fully wired controller right now is ImageController:
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/images/upload |
Upload one or more images for a product (files + productId as request params) |
GET |
/api/v1/images/image/download/{imageId} |
Download an image by ID (returns raw binary with correct Content-Type) |
ProductController and CategoryController exist as @RestController stubs with no mapped endpoints yet.
- Java 17+
- Maven (or use the included
mvnw/mvnw.cmdwrapper) - MySQL running locally
-
Create a local MySQL database:
CREATE DATABASE ecommerce;
-
Set your MySQL credentials in
src/main/resources/application.properties:spring.datasource.username=your_username spring.datasource.password=your_password
⚠️ Do not commit real credentials to a public repo. Move sensitive values to a local.envfile or use environment variable substitution. -
Run the application:
./mvnw spring-boot:run
The app starts on http://localhost:8080. Hibernate will auto-create/update the product, category, and image tables from the entity definitions (ddl-auto=update).
- Product and Category controllers — stubs exist but no endpoints are mapped yet.
- Global exception handling — no
@ControllerAdviceto turnProductNotFoundException,ResourceNotFoundException, andAlreadyExistExceptioninto clean HTTP error responses. - Request validation —
spring-boot-starter-validationis included but@Validannotations aren't applied to controller methods yet. - Authentication / authorization — no Spring Security setup yet.
- Tests — only the default Spring context-load smoke test exists.
- Implement
ProductController— wireProductServiceto HTTP endpoints (GET all, GET by ID, POST, PUT, DELETE, filter by brand/category). - Implement
CategoryController— expose Category CRUD over HTTP. - Add
@ControllerAdvice/@ExceptionHandlerfor consistent error response formatting. - Apply
@Validon incoming request bodies in controllers. - Expand test coverage — unit tests for services, integration tests for repositories and controllers.
- Add Spring Security once core CRUD is stable.
MIT — see LICENSE.