A production-ready Spring Boot REST API for managing quotes, built with Java 17, MySQL (local), PostgreSQL (production), and deployed on Render.
🚀 Live Demo: https://quotes-api-iyuq.onrender.com/
📋 Project Board: Trello
🤖 Postman collection: Postman
Base URL: /api/quotes
All requests and responses use Content-Type: application/json.
POST /api/quotes
Request body:
{
"author": "Marcus Aurelius",
"text": "The impediment to action advances action. What stands in the way becomes the way.",
"category": "philosophy"
}Responses:
201 Created— returns the created quote as JSON400 Bad Request— validation failed
GET /api/quotes/:id
Responses:
200 OK— returns the quote as JSON404 Not Found— quote with that ID does not exist
PUT /api/quotes/:id
Request body (include only fields to update):
{
"category": "stoicism"
}Responses:
200 OK— returns the updated quote as JSON400 Bad Request— validation failed404 Not Found— quote with that ID does not exist
DELETE /api/quotes/:id
Responses:
204 No Content— quote deleted successfully404 Not Found— quote with that ID does not exist
GET /api/quotes
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
search |
string | No | Filters quotes by keyword (matches author, text, or category — case-insensitive) |
page |
integer | No | Page number, zero-based (default: 0) |
size |
integer | No | Number of results per page (default: 20) |
sort |
string | No | Sort field and direction, e.g. createdAt,desc |
Examples:
GET /api/quotes → all quotes, first page
GET /api/quotes?search=stoic → quotes matching "stoic"
GET /api/quotes?page=1&size=5 → second page, 5 per page
GET /api/quotes?search=marcus&size=10 → search with custom page size
Responses:
200 OK— returns a paginated object
{
"content": [
{
"id": 1,
"author": "Marcus Aurelius",
"text": "The impediment to action advances action.",
"category": "philosophy",
"createdAt": "2026-05-12T10:00:00"
}
],
"totalElements": 42,
"totalPages": 5,
"size": 10,
"number": 0
}This project uses Soft Delete instead of permanently removing data from the database.
- How it works: When you delete a quote, it isn't actually gone. Instead, a hidden flag (
is_deleted) is set totrue. - Why? This prevents accidental data loss and allows for easy data recovery if needed.
- Hibernate 6 @SoftDelete: We used the latest Hibernate feature to handle this automatically. When you try to get quotes, the system is smart enough to only show you the ones that haven't been deleted yet.
- Docker installed
Docker Compose starts both MySQL and the app with a single command:
git clone https://github.com/BillerPlay/quote-management-system.git
cd quote-management-system
docker compose up --buildThe API will be available at http://localhost:8080.
docker compose down| Profile | Database | Used for |
|---|---|---|
default |
MySQL on localhost:3306 |
Local development |
test |
H2 in-memory | Integration tests |
prod |
PostgreSQL (Render) | Cloud deployment |
GitHub Actions runs on every push or PR to main:
- Checkout code
- Set up Java 17
- Cache Maven dependencies
- Run
mvn clean verify(builds + runs all tests with H2)
The pipeline status is shown as a badge on the repo.
-
Go to dashboard.render.com
-
Click "New +" → select PostgreSQL
-
Configure:
| Field | Value | |---|---| | Name |
quote-management-db| | Region | e.g. Frankfurt (EU Central) — note it for Step 2 | | PostgreSQL Version |16| -
Click "Create Database" and wait until status is Available
-
Copy the Internal Database URL — you'll need it in Step 2
⚠️ Important: the database and the web service must be deployed to the same region. Render's internal networking only works within a region.
-
Click "New +" → select Web Service
-
Connect your GitHub account and select:
BillerPlay/quote-management-system -
Configure:
Field Value Name quote-management-systemRegion Same as your database Environment Docker Dockerfile Path ./Dockerfile -
Under the "Environment" tab, add:
Key Value SPRING_DATASOURCE_URLfrom Render DB SPRING_DATASOURCE_USERNAMEfrom Render DB SPRING_DATASOURCE_PASSWORDfrom Render DB SPRING_PROFILES_ACTIVEprod -
Click "Create Web Service"
-
Once deployed, copy your Render URL and paste it at the top of this README
Every push to main triggers a new build and deploy automatically.
| Name | GitHub |
|---|---|
| Abdulvahhab Alaskarov | @BillerPlay |
| Islam Samadov | @IslamSamadov |
| Lala Aliyeva | @lalocchi |