Skip to content

Repository files navigation

RealWorld Example App using Spring

A Spring Boot implementation of the RealWorld API specification.

Built with modern Java 25, Spring Boot 4, and GraalVM native image support for instant startup and minimal resource footprint.

CI Codecov

A complete implementation of the RealWorld API spec on Spring Boot 4 and Java 25, built and shipped as a GraalVM native image alongside the usual JVM jar. Every release is checked against the upstream spec in CI on both, so "complete" is machine-verified rather than asserted, and it works with any RealWorld frontend.

What it demonstrates: JWT authentication, a CQRS-inspired command and query split, Spring Data JDBC, schema versioning with Liquibase, layered testing, and native binaries for four platforms produced on every release.

What it does not: the demo runs H2 in memory on a free instance, so read this as a worked reference rather than a production deployment.

Live Demo

Check out the live application on Render:

Resource URL
api https://realworld-backend-spring.onrender.com/api
swagger-ui https://realworld-backend-spring.onrender.com/swagger-ui/index.html

💡 The application is deployed on a free tier, so it may take a few seconds to start.

How it works

Architecture & Technologies

Modern Spring Stack:

Application Design:

  • Multi-module Gradle build with Kotlin DSL
  • Command/Query Bus pattern for CQRS-inspired separation of concerns
  • Database aggregate views for optimized read operations
  • Modern Java features: records, sealed interfaces, pattern matching
  • MapStruct with Spring integration for type-safe DTO mapping
  • JSpecify nullability annotations for enhanced type safety

Data & Infrastructure:

Native Compilation:

  • Full GraalVM native image support with optimized runtime hints
  • Multi-platform builds: Linux (AMD64/ARM64), macOS (ARM64), Windows (AMD64)
  • Native Docker images for linux/amd64 and linux/arm64, on a minimal Wolfi base for production deployment

CI/CD Pipeline

The project features a comprehensive automated pipeline:

  • Multi-platform builds: JVM JAR + native executables for four platforms
  • Automated testing with JUnit and integration tests
  • RealWorld spec compliance verification via the upstream hurl collection
  • Code coverage tracking with Codecov
  • Multi-arch Docker image building and publishing to GitHub Container Registry
  • Automated GitHub releases with platform-specific artifacts
  • Continuous deployment to Render

Getting started

Requirements: Java 25

Choose your preferred way to run the application:

JVM Mode

Traditional Spring Boot application with the full JVM:

./gradlew bootRun

Or download the JAR from the releases page:

java -jar realworld-backend-spring-*.jar

Native Image Mode

GraalVM native executable for instant startup and minimal memory footprint:

./gradlew nativeRun

Or download the pre-built native executable for your platform from the releases page:

./realworld-backend-spring

Available platforms: Linux (AMD64/ARM64), macOS (ARM64), Windows (AMD64)

Docker

Run the containerized native image, published for linux/amd64 and linux/arm64:

docker run -p 8080:8080 ghcr.io/alexey-lapin/realworld-backend-spring:latest

The application will be available at:

Frontend Integration

This backend implements the complete RealWorld API specification and works seamlessly with any RealWorld frontend.

API Base URL: http://localhost:8080/api

Point your frontend to this endpoint and you're ready to go. All authentication, CRUD operations, pagination, and filtering are fully supported.

Testing

Three layers of tests: unit tests, integration tests, and compliance against the RealWorld spec itself.

# Unit tests
./gradlew test

# Integration tests, which are a separate suite and do not run as part of `test`
./gradlew integrationTest

# Both suites plus Spotless, the same verification the CI build runs
./gradlew check

# Verify against the RealWorld API spec (needs https://hurl.dev installed).
# The spec lives upstream; check it out into .realworld-spec, the same path CI
# uses. The revision is read from the workflow rather than repeated here, so a
# local run and a CI run cannot drift onto different specs.
SPEC_REF=$(grep -E '^  SPEC_REF:' .github/workflows/main.yml | awk '{print $2}')

# First time only:
git clone --filter=blob:none --sparse https://github.com/realworld-apps/realworld .realworld-spec
git -C .realworld-spec sparse-checkout set specs/api

# Before each run (also refreshes an existing checkout):
git -C .realworld-spec fetch origin && git -C .realworld-spec checkout --detach "$SPEC_REF"

./gradlew build
java -jar service/build/libs/realworld-backend-spring*.jar &
hurl --test --jobs 1 \
  --variable host=http://localhost:8080 \
  --variable uid=$(date +%s) \
  .realworld-spec/specs/api/hurl/*.hurl

.realworld-spec is a foreign clone with its own .git, so it is gitignored and excluded from the Docker build context. It is about 2 MB.

Two things worth knowing:

  • host is the origin without /api. The .hurl files append the prefix themselves, and upstream's own README example gets this wrong.
  • Check out SPEC_REF, don't just run whatever the checkout happens to be on. The spec is a moving target and its requirements change: duplicate article titles once had to return 409, and now must be accepted with distinct slugs. An old checkout still enforces rules the spec has since dropped, so tests fail against a service that is correct. To move to a newer spec, bump SPEC_REF in .github/workflows/main.yml deliberately and fix whatever it turns red.

A Bruno collection generated from the same files is available upstream if you prefer to explore the requests interactively; the hurl files are the source of truth and are what CI runs.

Test suite includes:

  • Unit tests for business logic and handlers
  • Integration tests using Spring's declarative HTTP clients
  • RealWorld API spec validation with hurl
  • Code coverage reporting via JaCoCo and Codecov

Manual API Testing

For interactive API exploration and testing, use the included IntelliJ IDEA HTTP Client file:

File: api.http

This file contains ready-to-use requests for all API endpoints:

  • User registration and authentication
  • Profile management (follow/unfollow)
  • Article CRUD operations with feed and filtering
  • Comments and favorites
  • Tags listing

Open the file in IntelliJ IDEA or any compatible IDE and execute requests directly. The file uses environment variables and response handlers to chain requests automatically (e.g., capturing tokens for authenticated requests).

Performance Testing

Load test the application with the included k6 script:

k6 run k6-create-articles.js

The script simulates realistic article creation workload:

  • 5 virtual users for 30 seconds
  • Performance thresholds: <1% error rate, p95 latency <750ms
  • Automatic user registration and JWT token management
  • Random tag generation for realistic data distribution

Customize the test by setting the BASE_URL environment variable:

k6 run -e BASE_URL=https://your-api.com/api k6-create-articles.js

Releases

Packages

Used by

Contributors

Languages