Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Spring Boot API Demo

A secure Spring Boot 4 REST API built around a simple blog-style domain model containing users, posts, and comments. The application supports JWT authentication, protected endpoints, JPA persistence, and both H2 and MySQL database configurations.

Project Overview

This API provides public registration and login endpoints. Post and comment endpoints are protected and require a valid JWT bearer token.

The project is suitable for learning, prototyping, Postman API testing, and use as a foundation for a larger backend application.

Technology Stack

  • Java 25 runtime
  • Spring Boot 4.0.2
  • Spring Framework 7.0.3
  • Spring Security
  • Spring Data JPA and Hibernate
  • H2 Database for in-memory development
  • MySQL 8 for persistent storage
  • Maven Wrapper
  • JJWT for JSON Web Tokens
  • Lombok

Java version note: Spring Boot 4.0 requires Java 17 or later and provides first-class support for Java 25. This project is currently configured and tested with JDK 25. Java 17 or newer can also be used if the Maven compiler configuration permits it.[web:143][web:146]

Prerequisites

Install the following software:

  1. JDK 25, or Java 17 or newer.
  2. MySQL Server 8 if using the MySQL profile.
  3. MySQL Workbench, optional.
  4. Postman.
  5. Visual Studio Code or IntelliJ IDEA.

Verify the active Java version:

java -version

Expected output should contain Java 25, for example:

java version "25..."

Verify the Java compiler:

javac -version

Project Structure

src/
β”œβ”€β”€ main/
β”‚   β”œβ”€β”€ java/com/example/demo/
β”‚   β”‚   β”œβ”€β”€ DemoApplication.java
β”‚   β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”‚   └── SecurityConfig.java
β”‚   β”‚   β”œβ”€β”€ controller/
β”‚   β”‚   β”‚   β”œβ”€β”€ AuthController.java
β”‚   β”‚   β”‚   β”œβ”€β”€ PostController.java
β”‚   β”‚   β”‚   └── CommentController.java
β”‚   β”‚   β”œβ”€β”€ dto/
β”‚   β”‚   β”‚   β”œβ”€β”€ AuthRequest.java
β”‚   β”‚   β”‚   β”œβ”€β”€ AuthenticationResponse.java
β”‚   β”‚   β”‚   β”œβ”€β”€ PostResponse.java
β”‚   β”‚   β”‚   └── CommentResponse.java
β”‚   β”‚   β”œβ”€β”€ model/
β”‚   β”‚   β”‚   β”œβ”€β”€ User.java
β”‚   β”‚   β”‚   β”œβ”€β”€ Post.java
β”‚   β”‚   β”‚   └── Comment.java
β”‚   β”‚   β”œβ”€β”€ repository/
β”‚   β”‚   β”‚   β”œβ”€β”€ UserRepository.java
β”‚   β”‚   β”‚   β”œβ”€β”€ PostRepository.java
β”‚   β”‚   β”‚   └── CommentRepository.java
β”‚   β”‚   └── security/
β”‚   β”‚       β”œβ”€β”€ JwtService.java
β”‚   β”‚       β”œβ”€β”€ JwtAuthenticationFilter.java
β”‚   β”‚       └── UserDetailsServiceImpl.java
β”‚   └── resources/
β”‚       └── application.properties
└── test/
    └── java/com/example/demo/
        └── DemoApplicationTests.java

Authentication

The application uses stateless JWT bearer authentication. Passwords are hashed with BCrypt before they are stored.

Public endpoints:

POST /api/auth/register
POST /api/auth/login

Protected endpoints require:

Authorization: Bearer YOUR_JWT_TOKEN

Register

POST http://localhost:8080/api/auth/register
Content-Type: application/json

Body:

{
  "email": "razak@domain.com",
  "password": "123456"
}

Response:

{
  "token": "<jwt-token>"
}

Copy the token and use it in the Authorization header for protected requests.

Login

POST http://localhost:8080/api/auth/login
Content-Type: application/json

Body:

{
  "email": "razak@domain.com",
  "password": "123456"
}

Response:

{
  "token": "<jwt-token>"
}

Protected Endpoints

Posts

GET    /api/posts
GET    /api/posts/{id}
GET    /api/posts/my
POST   /api/posts
PUT    /api/posts/{id}
DELETE /api/posts/{id}

Create a post:

POST http://localhost:8080/api/posts
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json

Body:

{
  "title": "Welcome to the API",
  "body": "This is a sample post created through the API."
}

Example response:

{
  "id": 1,
  "title": "Welcome to the API",
  "body": "This is a sample post created through the API.",
  "authorId": 1,
  "authorEmail": "razak@domain.com"
}

The author is obtained from the JWT. Do not send an author object when creating a post.

Comments

GET    /api/comments
GET    /api/comments/{id}
POST   /api/comments
PUT    /api/comments/{id}
DELETE /api/comments/{id}

Create a comment for post 1:

POST http://localhost:8080/api/comments
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json

Body:

{
  "text": "This comment belongs to the sample post.",
  "post": {
    "id": 1
  }
}

Example response:

{
  "id": 1,
  "text": "This comment belongs to the sample post.",
  "postId": 1,
  "authorId": 1,
  "authorEmail": "razak@domain.com"
}

DTO responses are used so the API does not expose passwords or serialize the complete recursive JPA relationships.

H2 Configuration

H2 is useful for quick local testing. It stores data in memory and resets the data when the application stops.

Open:

src/main/resources/application.properties

Use this configuration:

spring.datasource.url=jdbc:h2:mem:demo;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true

jwt.secret=ThisIsADevelopmentJWTSecretKey1234567890
jwt.expiration=86400000

server.port=8080

Optional H2 console:

http://localhost:8080/h2-console

Use the following H2 console values:

JDBC URL: jdbc:h2:mem:demo
User: sa
Password: leave empty

MySQL Configuration

Create the database in MySQL:

CREATE DATABASE IF NOT EXISTS springdb;

For local development, create a dedicated user:

CREATE USER IF NOT EXISTS 'springapp'@'localhost'
IDENTIFIED BY 'ChangeThisPassword123!';

GRANT ALL PRIVILEGES ON springdb.*
TO 'springapp'@'localhost';

FLUSH PRIVILEGES;

Test the credentials:

& "C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe" -u springapp -p springdb

Replace the H2 datasource section in application.properties with:

spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=springapp
spring.datasource.password=ChangeThisPassword123!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true

jwt.secret=ThisIsADevelopmentJWTSecretKey1234567890
jwt.expiration=86400000

server.port=8080

Use your real MySQL password. Do not commit real credentials or JWT secrets to source control.

Do not use both H2 and MySQL datasource sections simultaneously. Keep only one active datasource configuration.

Maven Dependencies

The project must include Spring Web, Spring Security, Spring Data JPA, JJWT, Lombok, and the database driver being used.

For MySQL, make sure pom.xml contains:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

For H2, make sure it contains:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Running the Application

Configure Java permanently

If Java is already configured in Windows, use only:

.\mvnw.cmd spring-boot:run

If it is not configured, set it for the current PowerShell session:

$env:JAVA_HOME = "C:\Program Files\Java\jdk-25.0.2"
$env:PATH = "$env:JAVA_HOME\bin;$env:PATH"
.\mvnw.cmd spring-boot:run

For a permanent setup, add JAVA_HOME and %JAVA_HOME%\bin to the Windows user environment variables. Then reopen VS Code or PowerShell.

Build the project

From the project root:

.\mvnw.cmd clean install -DskipTests

Run the application

.\mvnw.cmd spring-boot:run

A successful startup includes:

Started DemoApplication
ReadinessState changed to ACCEPTING_TRAFFIC

The application listens at:

http://localhost:8080

Keep the terminal open while the server is running. Stop it with Ctrl+C.

Testing

Run the test suite:

.\mvnw.cmd test

If tests try to connect to MySQL and fail, configure a separate H2 datasource under:

src/test/resources/application.properties

For a quick build without running tests:

.\mvnw.cmd clean install -DskipTests

Troubleshooting

Access denied for user

Check that the username and password in application.properties match a working MySQL login. A dedicated springapp user is recommended instead of root.

Communications link failure or connection refused

Confirm that MySQL is running and listening on port 3306.

Unknown database

Create the database:

CREATE DATABASE springdb;

Cannot load MySQL driver

Confirm the com.mysql:mysql-connector-j dependency exists, then run:

.\mvnw.cmd clean install -DskipTests

JWT expiration conversion error

Use a numeric value without an inline comment:

jwt.expiration=86400000

HTTP 401 Unauthorized

Login again and send the token exactly as:

Authorization: Bearer eyJ...

There must be one space between Bearer and the token.

Notes

  • H2 data is reset when the application restarts.
  • MySQL data persists between application restarts.
  • Passwords are hashed before persistence.
  • DTO responses intentionally exclude passwords and recursive entity relationships.
  • JWT authentication is stateless.
  • A user can update or delete only their own posts and comments.
  • spring.jpa.hibernate.ddl-auto=update is convenient for development. Use database migrations such as Flyway or Liquibase in production.

License

This project is an internal/demo API sample. Extend, adapt, and distribute it according to your organization or personal project standards.

About

This repo contains the spring-boot sample backend app. To know more about it, read the bellow descriptions.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages