Skip to content

Repository files navigation

Blog API

Spring Boot 3 / Java 17 REST API for a blogging platform. Public read access, JWT-authenticated writes, and role-based admin operations.

Recruiters: start with Security model, then run ./mvnw test. That suite is the proof that unauthenticated writes are rejected and ROLE_USER cannot perform admin actions.

What this service does

  • Users register and log in (/api/auth/register, /api/auth/login)
  • Authors create posts under a category, with pagination, search, comments, and image upload
  • Admins manage categories and user accounts
  • Schema is versioned with Flyway; the HTTP contract is documented in Swagger

Stack

Layer Choice
Runtime Java 17, Spring Boot 3.0
API Spring Web, Bean Validation, springdoc OpenAPI
Security Spring Security 6, JWT (JJWT), BCrypt, method security
Persistence Spring Data JPA, Flyway, MySQL 8 (H2 in tests)
Ops Actuator health/info, Docker Compose, GitHub Actions

Architecture

Client
  -> AuthController / resource controllers
  -> JwtAuthenticationFilter (Bearer token)
  -> SecurityFilterChain + @PreAuthorize
  -> Service interfaces (@Transactional)
  -> Spring Data JPA repositories
  -> MySQL (Flyway migrations)

DTOs (payloads) are mapped with ModelMapper so JPA entities are not returned as-is. Passwords are write-only in JSON and stored hashed.

Security model

Path Rule
POST /api/auth/register, POST /api/auth/login Public
GET /api/posts/**, GET /api/categories/**, GET /api/post/image/** Public
POST /api/user/{id}/category/{id}/posts, comments, image upload Authenticated (ROLE_USER or ROLE_ADMIN)
Category mutations, list/delete users ROLE_ADMIN
DELETE /api/users/{id} ROLE_ADMIN and @PreAuthorize

Tokens are stateless (SessionCreationPolicy.STATELESS). Invalid or missing Bearer tokens return 401; authenticated users without the required role return 403.

Default admin (local/demo only): admin@blog.local / Admin@12345. Override with ADMIN_EMAIL and ADMIN_PASSWORD.

Quick start

Tests (no MySQL)

./mvnw test

Docker Compose (API + MySQL)

cp .env.example .env
docker compose up --build

Local MySQL

Create an empty blog_app database, then:

export MYSQL_PASSWORD=your-password
export JWT_SECRET=a-long-random-secret-of-at-least-32-chars
./mvnw spring-boot:run

Flyway applies V1__init_schema.sql on startup (ddl-auto=validate). Use a fresh database; do not point this at a schema created by older ddl-auto=update runs.

Example calls

# Register
curl -s -X POST http://localhost:8010/api/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"name":"Ada","email":"ada@blog.local","password":"Pass1234","about":"author"}'

# Login
TOKEN=$(curl -s -X POST http://localhost:8010/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"ada@blog.local","password":"Pass1234"}' | jq -r .token)

# Create a post (needs an admin-created category first)
curl -s -X POST http://localhost:8010/api/user/2/category/1/posts \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"title":"Hello","content":"First post"}'

In Swagger, use Authorize and paste Bearer <token>.

Configuration

Variable Purpose
MYSQL_PASSWORD Database password (not committed)
JWT_SECRET HMAC key, at least 32 characters
ADMIN_EMAIL / ADMIN_PASSWORD Bootstrap admin
SPRING_DATASOURCE_URL JDBC URL (Compose sets this to the mysql service)

API surface

Users, categories, posts (CRUD, filter by author/category, title search, pagination), comments, image upload/download. Pagination defaults: page 0, size 10, sort postId.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages