A Spring Boot REST API for a blog platform with authentication, post/category/comment management, JWT security, database persistence, OpenAPI documentation, and Docker support.
- User registration and login with JWT authentication
- Refresh token and logout support
- Public read access for posts, categories, and comments
- Authenticated create/update/delete for posts and comments
- Admin-only category management
- Pagination, sorting, and search for posts
- Nested comment threads with reply support
- PostgreSQL persistence with Docker Compose setup
- Swagger/OpenAPI UI for API docs
- Spring Boot Actuator health endpoint
- Java 21
- Spring Boot 3.2.5
- Spring Security
- Spring Data JPA / Hibernate
- Spring Web
- Spring Validation
- PostgreSQL
- JWT via JJWT
- SpringDoc OpenAPI / Swagger UI
- Docker / Docker Compose
- Lombok
- Docker
- Docker Compose
- Maven (for local build without Docker)
From the project root where docker-compose.yml is located:
docker compose up -d --buildThis starts:
blog-postgres— PostgreSQL databaseblog-api— Spring Boot application on port8080
pgAdmin is defined in the compose file under the tools profile. Start it with:
docker compose --profile tools up -dThen open:
http://localhost:5050
pgAdmin credentials:
- Email:
admin@gmail.com - Password:
admin
mvn clean package -DskipTests
java -jar target/blog-api-1.0.0.jarThe application reads database and JWT settings from environment variables and application.yml.
Environment variables used by Docker Compose:
DB_HOST— database hostDB_PORT— database portDB_NAME— database nameDB_USERNAME— database usernameDB_PASSWORD— database passwordJWT_SECRET— JWT signing secretSPRING_PROFILES_ACTIVE— active Spring profile
Swagger UI is available at:
http://localhost:8080/swagger-ui.html
OpenAPI docs:
http://localhost:8080/v3/api-docs
Health endpoint:
http://localhost:8080/actuator/health
- Public routes are accessible without auth
- Protected routes require
Authorization: Bearer <accessToken> - Use
/api/v1/auth/loginto get a JWT access token - Use
/api/v1/auth/refreshto refresh the access token
-
POST /api/v1/auth/register- Request:
{ "username": "...", "email": "...", "password": "..." } - Creates a new user
- Request:
-
POST /api/v1/auth/login- Request:
{ "username": "...", "password": "..." } - Returns
accessToken,refreshToken,tokenType, and user info
- Request:
-
POST /api/v1/auth/refresh- Request:
{ "refreshToken": "..." } - Returns a new access token
- Request:
-
POST /api/v1/auth/logout- Request:
{ "refreshToken": "..." } - Invalidates the refresh token
- Request:
-
GET /api/v1/posts- Query params:
page,size,sort - Public list of published posts
- Query params:
-
GET /api/v1/posts/{id}- Get a single post by its ID
-
GET /api/v1/posts/slug/{slug}- Get a single post by slug
-
GET /api/v1/posts/category/{categoryId}- Posts filtered by category
-
GET /api/v1/posts/author/{authorId}- Posts filtered by author
-
GET /api/v1/posts/search?q=keyword- Search posts by keyword
-
GET /api/v1/posts/me- Authenticated user’s own posts
-
POST /api/v1/posts- Create a new post (authenticated)
-
PUT /api/v1/posts/{id}- Update a post (authenticated)
-
DELETE /api/v1/posts/{id}- Delete a post (authenticated)
-
GET /api/v1/categories- List categories
-
GET /api/v1/categories/{id}- Get category details
-
GET /api/v1/categories/slug/{slug}- Get category by slug
-
POST /api/v1/categories- Create category (ADMIN only)
-
PUT /api/v1/categories/{id}- Update category (ADMIN only)
-
DELETE /api/v1/categories/{id}- Delete category (ADMIN only)
-
GET /api/v1/posts/{postId}/comments- List paginated comments for a post
-
GET /api/v1/comments/{id}- Get a comment by ID with nested replies
-
POST /api/v1/posts/{postId}/comments- Create a comment or reply (authenticated)
- Body example:
{ "content": "...", "parentId": null }
-
PUT /api/v1/comments/{id}- Update a comment (authenticated)
-
DELETE /api/v1/comments/{id}- Delete a comment (authenticated)
id,name,slug,description,postCount,createdAt
id,title,slug,content,summary,status,author,category,commentCount,createdAt,updatedAt
id,content,deleted,author,parentId,depth,replies,createdAt,updatedAt
accessToken,refreshToken,tokenType,user
- The project uses Spring Boot 3, so Jakarta EE APIs are provided transitively by the Spring Boot starters.
- Category management is secured with role-based access: only users with
ADMINcan create, update, or delete categories. - Comments support nested reply trees and preserve thread structure on deletion.
# Build and run in Docker
docker compose up -d --build
# Start pgAdmin as well
docker compose --profile tools up -d
# Stop all compose services
docker compose down
# View logs for all services
docker compose logs -f
# Build without Docker
mvn clean package -DskipTests