Basic example of CQRS implementation in a Java 11 SpringBoot rest api. It uses MySql as DB and RabbitMQ as AMQP to deal with Commands, Queries and Domain events.
- Java 11
- Maven
- Docker and Docker compose (I use Docker version 23.01.1 and docker-compose v2.17.0)
- Make sure to download all Needed tools
- Clone the repository
git clone https://github.com/dasalgadoc/cqrs-java.git
- Build up maven project
mvn dependency:resolve
- Compile the project
mvn compile && mvn package
If you have errors using the previous command try this:
mvn clean install -DskipTests
- Once target file and compile .jar were generated, you can run the docker environment. Note: If you change the project name, make sure to change the Dockerfile as well as follows.
ARG JAR_FILE=./target/<COMPILED NAME>.jar
ADD ${JAR_ILE} <COMPILED NAME>.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/<COMPILED NAME>jar"]
Run the environment use
docker-compose up --build
You can run any docker from compose using:
docker-compose up -d <CONTAINER NAME>
docker-compose up -d mysql-container
Also, you can access to any docker using:
docker exec -it cqrs-java-<CONTAINER NAME>-1 bash
docker exec -it cqrs-java-mysql-container-1 bash
If everything went ok, you can test the ping endpoint, notice that docker forwarded the 8080 docker port to 8085 localhost. You can change this in the docker-compose file
curl --request GET \
--url http://localhost:8085/ping
Expected results:
Pong
Others, API endpoints are:
Create a blog
curl --request POST \
--url http://localhost:8085/blog \
--header 'Content-Type: application/json' \
--data '{
"id": "a9771f2c-7e23-4473-ba7d-ae1db3313d96",
"title": "My title",
"type": "TUTORIAL",
"brief": "My brief",
"url": "http://www.example.com"
}'
Beware! Body structure is important to this endpoint. Async commands and CQRS it's not about validation! So
{
"id": "<UUID STRING>",
"title": "<STRING WITH 140 CHARACTERS OR LESS>",
"type": "<CHOICE ONE IN ALL CAPS (TUTORIAL/NEWS/OPINION/RANT)>",
"brief": "<STRING WITH 400 CHARACTERS OR LESS>",
"url": "<STRING THAT MATCHES WITH THIS ^(http|https)://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$ REGEX>"
}
Find blog by ID
curl --request GET \
--url http://localhost:8085/blog/a9771f2c-7e23-4473-ba7d-ae1db3313d96
curl --request GET \
--url http://localhost:8085/blog/<UUID>
curl --request GET \
--url 'http://localhost:8085/count?entity_type=Blogs'
- Improve async queue definitions using AsyncAPI Topic Definition
- Apply OCP to macrolevel
- 1 Publisher and 1 exchange
- Exchange topic type (this enables using filters)
- 1 queue per consumer and domain event, command and query.
- Handle when message fails and idempotency