Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v2
uses: actions/setup-java@v4
with:
distribution: zulu
java-version: '11'
- uses: actions/cache@v2
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
Expand Down
165 changes: 119 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,154 @@
# ![RealWorld Example App using Kotlin and Spring](example-logo.png)
# ![RealWorld Example App](example-logo.png)

[![Actions](https://github.com/gothinkster/spring-boot-realworld-example-app/workflows/Java%20CI/badge.svg)](https://github.com/gothinkster/spring-boot-realworld-example-app/actions)
A fully-featured REST API and GraphQL backend built with Spring Boot and MyBatis, implementing the [RealWorld](https://github.com/gothinkster/realworld) specification for a Medium-style blogging platform.

> ### Spring boot + MyBatis codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld-example-apps) spec and API.
[![Java CI](https://github.com/gothinkster/spring-boot-realworld-example-app/workflows/Java%20CI/badge.svg)](https://github.com/gothinkster/spring-boot-realworld-example-app/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

This codebase was created to demonstrate a fully fledged full-stack application built with Spring boot + Mybatis including CRUD operations, authentication, routing, pagination, and more.
## Table of Contents

For more information on how to this works with other frontends/backends, head over to the [RealWorld](https://github.com/gothinkster/realworld) repo.
- [Overview](#overview)
- [Features](#features)
- [Requirements](#requirements)
- [Quick Start](#quick-start)
- [Project Structure](#project-structure)
- [API Documentation](#api-documentation)
- [GraphQL Support](#graphql-support)
- [Database](#database)
- [Testing](#testing)
- [Code Formatting](#code-formatting)
- [Docker](#docker)
- [Using with a Frontend](#using-with-a-frontend)
- [Contributing](#contributing)
- [License](#license)

# *NEW* GraphQL Support
## Overview

Following some DDD principles. REST or GraphQL is just a kind of adapter. And the domain layer will be consistent all the time. So this repository implement GraphQL and REST at the same time.
This codebase demonstrates a production-ready application built with Spring Boot and MyBatis, featuring CRUD operations, JWT authentication, routing, pagination, and more. The project follows Domain-Driven Design (DDD) principles and implements both REST and GraphQL APIs, allowing you to choose the interface that best fits your needs.

The GraphQL schema is https://github.com/gothinkster/spring-boot-realworld-example-app/blob/master/src/main/resources/schema/schema.graphqls and the visualization looks like below.
For more information on how this works with other frontends and backends, visit the [RealWorld](https://github.com/gothinkster/realworld) repository.

![](graphql-schema.png)
## Features

And this implementation is using [dgs-framework](https://github.com/Netflix/dgs-framework) which is a quite new java graphql server framework.
# How it works
This application includes user registration and authentication with JWT tokens, article management with full CRUD operations, commenting system for articles, user profiles with follow/unfollow functionality, article favoriting, tag-based filtering, and feed pagination. Both REST and GraphQL endpoints are available for all operations.

The application uses Spring Boot (Web, Mybatis).
## Requirements

* Use the idea of Domain Driven Design to separate the business term and infrastructure term.
* Use MyBatis to implement the [Data Mapper](https://martinfowler.com/eaaCatalog/dataMapper.html) pattern for persistence.
* Use [CQRS](https://martinfowler.com/bliki/CQRS.html) pattern to separate the read model and write model.
- Java 11 or higher
- Gradle (wrapper included)

And the code is organized as this:
## Quick Start

1. `api` is the web layer implemented by Spring MVC
2. `core` is the business model including entities and services
3. `application` is the high-level services for querying the data transfer objects
4. `infrastructure` contains all the implementation classes as the technique details
Clone the repository and run the application:

# Security
```bash
# Clone the repository
git clone https://github.com/gothinkster/spring-boot-realworld-example-app.git
cd spring-boot-realworld-example-app

Integration with Spring Security and add other filter for jwt token process.
# Run the application
./gradlew bootRun
```

The secret key is stored in `application.properties`.
The application starts on `http://localhost:8080`. Verify it's running:

# Database
```bash
curl http://localhost:8080/tags
```

It uses a ~~H2 in-memory database~~ sqlite database (for easy local test without losing test data after every restart), can be changed easily in the `application.properties` for any other database.
Or open http://localhost:8080/tags in your browser.

# Getting started
## Project Structure

You'll need Java 11 installed.
```
src/main/java/io/spring/
├── api/ # REST API controllers (Spring MVC)
├── application/ # Application services and DTOs for queries
├── core/ # Domain models and business logic
├── graphql/ # GraphQL resolvers and data fetchers
└── infrastructure/ # Database mappers, repositories, and security
```

./gradlew bootRun
The codebase follows Domain-Driven Design principles. The `api` layer handles HTTP requests via Spring MVC. The `core` layer contains domain entities and services, remaining independent of infrastructure concerns. The `application` layer implements the CQRS pattern, separating read and write models. The `infrastructure` layer provides MyBatis mappers implementing the Data Mapper pattern for persistence.

To test that it works, open a browser tab at http://localhost:8080/tags .
Alternatively, you can run
## API Documentation

curl http://localhost:8080/tags
The REST API follows the [RealWorld API Spec](https://github.com/gothinkster/realworld/tree/master/api). Key endpoints include:

# Try it out with [Docker](https://www.docker.com/)
| Endpoint | Description |
|----------|-------------|
| `POST /users` | Register a new user |
| `POST /users/login` | Authenticate user |
| `GET /user` | Get current user |
| `GET /profiles/:username` | Get user profile |
| `GET /articles` | List articles |
| `POST /articles` | Create article |
| `GET /articles/:slug` | Get article |
| `GET /tags` | Get all tags |

You'll need Docker installed.

./gradlew bootBuildImage --imageName spring-boot-realworld-example-app
docker run -p 8081:8080 spring-boot-realworld-example-app
## GraphQL Support

# Try it out with a RealWorld frontend
The application implements GraphQL using the [Netflix DGS Framework](https://github.com/Netflix/dgs-framework). The GraphQL endpoint is available at `/graphql`, and the schema supports all operations available through the REST API.

The entry point address of the backend API is at http://localhost:8080, **not** http://localhost:8080/api as some of the frontend documentation suggests.
![GraphQL Schema](graphql-schema.png)

# Run test
The schema is defined in `src/main/resources/schema/schema.graphqls` and includes queries for articles, users, profiles, and tags, along with mutations for creating, updating, and deleting content.

The repository contains a lot of test cases to cover both api test and repository test.
## Database

./gradlew test
The application uses SQLite by default for easy local development without losing data between restarts. The database file is `dev.db` in the project root.

# Code format
To use a different database, modify `src/main/resources/application.properties`:

Use spotless for code format.
```properties
spring.datasource.url=jdbc:sqlite:dev.db
spring.datasource.driver-class-name=org.sqlite.JDBC
```

./gradlew spotlessJavaApply
## Testing

# Help
Run the test suite:

Please fork and PR to improve the project.
```bash
./gradlew test
```

The repository includes comprehensive tests covering both API endpoints and repository operations.

## Code Formatting

The project uses [Spotless](https://github.com/diffplug/spotless) with Google Java Format for consistent code style:

```bash
./gradlew spotlessJavaApply
```

## Docker

Build and run with Docker:

```bash
# Build the Docker image
./gradlew bootBuildImage --imageName spring-boot-realworld-example-app

# Run the container
docker run -p 8081:8080 spring-boot-realworld-example-app
```

The application will be available at `http://localhost:8081`.

## Using with a Frontend

This backend works with any [RealWorld frontend](https://github.com/gothinkster/realworld#frontends). The API entry point is `http://localhost:8080` (not `/api` as some frontend documentation suggests).

## Contributing

Contributions are welcome. Please fork the repository and submit a pull request with your changes.

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

---

_Originally written and maintained by contributors and [Devin](https://app.devin.ai), with updates from the core team._