A reactive Kotlin and Spring Boot application providing an API for showcasing Server-Sent Events (SSE), with OpenAPI and Swagger UI documentation included.
Built using Spring WebFlux and Reactor for non-blocking and asynchronous performance, and SpringDoc for API documentation.
- Reactive stack – powered by Spring WebFlux and Reactor
- Kotlin-first – concise, idiomatic Kotlin design utilising coroutines and suspense
- OpenAPI documentation – auto-generated using SpringDoc
- Swagger UI – interactive API docs with data schemas
The OpenAPI documentation generated for this application is fully compatible with version 3.2 of OpenAPI Specification (released in September 2025).
This version of the specification adds support for the
text/event-stream media type (used for SSE) and
other sequential media types. In particular, it uses a new
itemSchema field to model the schema of each event's
data field.
Note: Although the docs are compatible with version 3.2 of the specification, the JSON doc still lists the version as 3.1. This is for compatability purposes with other software, such as Swagger UI.
Prerequisites:
- Java 17+
Commands:
./gradlew bootRun
Prerequisites:
- Docker
Commands:
docker build -t sse-api .
docker run -p 8080:8080 sse-api
The application will be available at localhost on port 8080.
- To explore the Swagger UI – http://localhost:8080/docs
- To view the OpenAPI doc – http://localhost:8080/openapi.json
You can configure how the application runs using environment variables.
| Variable | Description | Default |
|---|---|---|
APP_BASE_PATH |
The base URL path for the API. | / |
APP_API_DOCS_ENABLED |
Whether the API docs are enabled. | true |
APP_API_DOCS_PATH |
The URL path for the API docs. | /openapi.json |
APP_SWAGGER_UI_ENABLED |
Whether the Swagger UI is enabled. | true |
APP_SWAGGER_UI_PATH |
The URL path for the Swagger UI. | /docs |
You can set environment variables before running the application commands. For example:
export APP_BASE_PATH=/api
./gradlew bootRun
If using Docker, you can use flags with the run command. For example:
docker build -t sse-api .
docker run \
-p 8080:8080 \
-e APP_API_DOCS_PATH=/docs/api.json \
-e APP_SWAGGER_UI_ENABLED=false \
sse-api
You can configure how the application builds using Gradle properties.
| Property | Description |
|---|---|
api.version |
The version of the API docs*. |
api.contact.name |
The name of the contact person or organisation for the API. |
api.contact.email |
The email address of the contact person or organisation for the API. |
api.contact.url |
The URL for the contact information of the API. |
api.license.name |
The name of the license used for the API. |
api.license.identifier |
The SPDX expression representing the license used for the API. |
api.license.url |
The URL for the license information of the API. |
api.terms-of-service.url |
The URL for the terms of service of the API. |
api.external-docs.description |
The description of the target documentation of the API. |
api.external-docs.url |
The URL for the target documentation of the API. |
*This is the version of the OpenAPI document. It is not (or does not need to be) the same as version property for the
Gradle project, nor the version of the API itself, nor the version of the OpenAPI specification.
You can set Gradle properties by adding to gradle.properties. For example:
# other properties...
api.license.name=MIT License
api.license.identifier=MIT
You can also set Gradle properties using flags with the gradlew command. For example:
./gradlew bootRun -Papi.version=0.1.0
You can also set Gradle properties using environment variables prefixed with ORG_GRADLE_PROJECT_. In this case,
property names must be specified using camel case. For example:
export ORG_GRADLE_PROJECT_apiVersion=0.1.0
export ORG_GRADLE_PROJECT_apiTermsOfServiceUrl=https://example.com/terms
./gradlew bootRun
Key dependencies include:
To view all dependencies and versions, see build.gradle.kts and
libs.versions.toml.
This software is released under the MIT License.
You are free to use, modify, and distribute it under the same terms.
- James Missen (@jamesmissen)