Skip to content

CWACoderWithAttitude/dc-spring-boot-all-in-one

Repository files navigation

TL;DR

DevContainer for Spring Boot development that gets you covered for all major challenges of building production grade REST services.

What’s inside?

This is an opinionated devcontainer for building REST APIs with Spring Boot. It is not meant to be a complete solution for all use cases. It rather provides starting points tp get you started on all of challenges of building production grade REST services. If you have any suggestions or feedback, please let me know.

Let’s have a look at the main components:

  • OpenJDK 21

  • Spring Boot 3.5.0

  • Maven 3.9.9

  • MS SQL DB 2022

  • Prometheus

  • Grafana

  • Alertmanager

  • Mailcatcher

  • Adminer

  • JaCoCo

  • Bruno

Components

Spring Boot - OpenJDK 21

Develop your Spring Boot 3.5 Service on OpenJDK 21.

For illustration I added an example REST-Service that manages data on games. This service exposes some technical metrics: JVM, Hibernate, Spring-Booot (Requests, Errors, etc.) and application specific metrics like the number of games in the database.

To assist your journey of building high quality web services: - the service exposes a self documenting API using OpenAPI aka Swagger. You can access the API documentation at http://localhost:8088/swagger-ui/index.html. - I added JaCoCo maven plugin. Each time you run ./mvnw package the code coverage is calculated and stored in target/site/jacoco/index.html. Use the included Live server extension to view the report in your browser. image::https://github.com/CWACoderWithAttitude/dc-spring-boot-all-in-one/blob/what-the-heck/images/games-jacoco-report.png[JaCoCo Report] - basic build pipeline based on GitHub Actions is included. It runs the tests, builds the app and generates the JaCoCo report. The pipeline is triggered on every push to the main branch and on every pull request.

Architecture Diagram

A picture is worth a thousand words. So let’s have a look at the architecture diagram of the devcontainer.

architecture-beta
group games_service(cloud)[Games Service DevContainer]
    service db(database)[Database] in games_service
    service apiserver(server)[GamesAPI] in games_service

    service prometheus(server)[Prometheus] in games_service
    prometheus:L -- R:apiserver
    db:R -- L:apiserver
    service grafana(server)[Grafana] in games_service
    service alert_manager(server)[Alertmanager] in games_service

    service mailcatcher(server)[Mailcatcher] in games_service
    alert_manager:L -- R:mailcatcher
    service adminer(server)[Adminer] in games_service
    db:L -- R:adminer
    prometheus:T -- B:grafana
    alert_manager:T -- B:prometheus
    service mssql_tools(server)[MSSQL_Tools]
    db:T -- B:mssql_tools

    service bruno(cloud)[Bruno]
    apiserver:B -- B:bruno
Loading

Testing

I ship my examples with Bruno collections.

Please find the collections in the bruno folder. You can import them into Bruno by clicking on the + icon in the top left corner and selecting Import Collection.

There’s a CLI tool to run collections, too:

❯ bru run . --reporter-html results.html
Running Folder

Create Game (200 ) - 71 ms
   ✓ assert: res.status: eq 200
   ✓ should return status 200 (OK)
   ✓ id of the create game entity should be greater than 0
Get all games (200 ) - 87 ms
   ✓ assert: res.status: eq 200
Get game by existing id (200 ) - 10 ms
   ✓ assert: res.status: eq 200
Get game by non-existing id (404 ) - 7 ms
   ✓ assert: res.status: eq 404
Update Game - existing id (200 ) - 16 ms
Monitoring - Metrics (200 ) - 11 ms
Monitoring - Info (200 ) - 2 ms
Monitoring - Health (200 ) - 4 ms
Delete Game by existing id (204 ) - 12 ms
   ✓ assert: res.status: eq 204
Delete Game by non existing id (404 ) - 9 ms
   ✓ assert: res.status: eq 404
Upload Games from JSON File (415 ) - 9 ms
Update Game - non existing id (200 ) - 7 ms

Requests:    12 passed, 12 total
Tests:       2 passed, 2 total
Assertions:  6 passed, 6 total
Ran all requests - 245 ms

Requests:    12 passed, 12 total
Tests:       2 passed, 2 total
Assertions:  6 passed, 6 total
Bruno CLI Report

I like Bruno - open source, local execution, no cloud services required. Support for GUI and CLI. Excellent support for adding asserts and test to your requests.

Persistence

Is implemented by MS SQL 2022. This setup ships with an empty database. Using Bruno you can easily create items or upload the a set of default games. By default the service default games are loaded from file:///./games-service/src/(resources/board-games.json on startup if the db is empty.

Monitoring

The devcontainer includes Prometheus, Grafana and Alertmanager to monitor your app. Never underestimate the importance of monitoring your app. It is crucial to know how your app is doing in production. This setup includes everything you need to get started to monitor your app and to be notified when something goes wrong.

For me gathering metrics & generating appropriate alerts is key to enable us to run a reliable platform. Dashboards are great to visualize the metrics, but alerts are crucial to be notified when something goes wrong. Dashboards should be build in a way that makes it easy to spot issues. Maybe even more important than just sending alerts it is imperative to send usefull alerts - and not too many of them to prevent alert fatigue.

Prometheus

is configured to scrape metrics from the app and from the host system

Grafana

is used to visualize the collected metrics. This setup ships with a preconfigured datasource connection to prometheus. You only need to add a dashboard to show Spring boot metrics. For starters you can try dashboard 19004:

  1. Open Grafana - default credentials are admin/admin: .env file contains the default password → GF_SECURITY_ADMIN_PASSWORD.

  2. You can import this dashboard by clicking on the + icon in the left sidebar and selecting Import. Then paste the dashboard ID 19004 into the input field and click on Load. You can then select the Prometheus datasource and click on Import.

Alertmanager

is used to send notifications when an alert is triggered. Since you definitely want to be notified when your app is down or when something goes wrong, I added a simple alerting rule that will trigger an alert when the app is down. To keep it simple the alerts will be sent via email to a local mailtcatcher. image::https://github.com/CWACoderWithAttitude/dc-spring-boot-all-in-one/blob/main/images/mailcatcher-alert-messages.png[Mailcatcher Alert Messages]

Mailcatcher

can be reached at http://localhost:1080 (You can test the email notification by sending a test email to the configured SMTP server.) This is an app that accepts SMTP mail connections.Received mails are shown in a web gui. This is a great way to test email notifications without having to set up a real SMTP server.

DB Frontend

To make is as easy for you as possible i included difffent ways to peek into the datase. One is a web based GUI, the other is a CLI tool.

GUI

Adminer is a web based DB management tool that can be used to manage your database. It can be reached at http://localhost:8010. Please lookup the DB password fron .env file - look out for property mssql_sa_password.

CLI

In case you prefer CLI I included mssql-tools:

The DB password for the sa user is stored in the .env file as mssql_sa_password. It’s injected into the mssql-tools container in docker-compoose as MSSQL_PASSWORD.

docker exec -it mssql.local /bin/bash
root@2f8bd524f7bf:/# sqlcmd -S mssql.local -U sa -P ${MSSQL_PASSWORD}
1> SELECT name FROM master.dbo.sysdatabases
2> go
name
-----
master
tempdb
model
msdb

(4 rows affected)
1> USE msdb
2> go
Changed database context to 'msdb'.

1> SELECT top 5 id, title, ean13 FROM dbo.game WHERE title != "" and ean13 != ""
2> go
id      title              ean13
--------------------------
34 Catan, Das Würfelspiel 4002051699093
52 Catan, Das Würfelspiel 4002051699093
53 Catan, Das Würfelspiel 4002051699093
54 Catan, Das Würfelspiel 4002051699093

(4 rows affected)

Why?

When developing a REST API you need to think about a lot of things. You need to think about how to test your code, how to monitor it, how to deploy it and how to make sure it runs in a container. This is a lot of stuff to think about. So I thought it would be a good idea to build a full blown REST API that covers all these topics. The goal is to show you how to do all this stuff in a simple way. The goal is not to build the best API ever.

Why devcontainers?

We all know "Works on my machine" is a bad slogan. What if "works on my machine" simply means: great - ship it. What if we could turn "works on my machine" into "works in a container"? An envirnment that is consistent regardless of the host system. I want to show you why we should embrace the slogan "It works on my machine". Using devcontainers it is easy to build your product in an environment that’s pretty close to your prod env. Let’s face it - we all have different machines and different setups. When using containers starting from day one you can be suree

OpenAPI aka Swagger

OK

http://localhost:8010 DB Admin Frontend

OK

Prometheus Targets Check scraping metrics from endpoints is healthy

OK

Grafana Visualize Metrics

OK

AlertManager

OK

Mailcatcher - Fake SMTP Apps may send SMTP Mails to Pot 1025

OK

ToDos

  • Test Guhub Actions locally w act

  • Integrate alerting into the setup. This will be done with

  • ❏ - publish JaCoCo Report

  • ❏ - Integrate Keycloak for authentication and authorization

  • ❏ - Run app on Firebase

  • ❏ - Deploy app on AWS using CDK and AWS Lambda

  • ❏ - Add Kong API Gateway

  • ❏ - Automate conversion of asciidoc 2 markdown. Makefile contains generate_markdown: clean asciidoc2docbook docbook2md to do exactly that. It should be added to the build pipeline to generate the markdown file automatically…​

  • ❏ - addd appropriate icons to the architecture diagram

  • ❏ - fix test mocks for metrics and counters

About

Dev container project to get you started on production grade spring boot based REST web service.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages