{"id":18048058,"url":"https://github.com/ivangfr/spring-webflux-reactive-databases","last_synced_at":"2025-04-10T09:48:36.175Z","repository":{"id":111328566,"uuid":"205703117","full_name":"ivangfr/spring-webflux-reactive-databases","owner":"ivangfr","description":"The goal of this project is to play with Spring WebFlux on client and server side. For it, we will implement some Spring Boot Java Web applications, product-api, customer-api, order-api and client-shell, and use reactive NoSQL database like Cassandra, MongoDB, Postgres and MySQL.","archived":false,"fork":false,"pushed_at":"2025-04-03T20:58:27.000Z","size":3565,"stargazers_count":23,"open_issues_count":0,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-03T21:32:58.505Z","etag":null,"topics":["cassandra","docker","http-interface","java","mongodb","mysql","postgresql","spring-aop","spring-boot","spring-data-cassandra-reactive","spring-data-mongodb-reactive","spring-data-r2dbc","spring-shell","spring-webflux","springdoc-openapi"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivangfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ivangfr"}},"created_at":"2019-09-01T16:29:27.000Z","updated_at":"2025-04-03T21:09:31.000Z","dependencies_parsed_at":"2025-04-03T21:38:45.478Z","dependency_job_id":null,"html_url":"https://github.com/ivangfr/spring-webflux-reactive-databases","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspring-webflux-reactive-databases","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspring-webflux-reactive-databases/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspring-webflux-reactive-databases/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspring-webflux-reactive-databases/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivangfr","download_url":"https://codeload.github.com/ivangfr/spring-webflux-reactive-databases/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248197422,"owners_count":21063619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cassandra","docker","http-interface","java","mongodb","mysql","postgresql","spring-aop","spring-boot","spring-data-cassandra-reactive","spring-data-mongodb-reactive","spring-data-r2dbc","spring-shell","spring-webflux","springdoc-openapi"],"created_at":"2024-10-30T20:11:06.916Z","updated_at":"2025-04-10T09:48:36.165Z","avatar_url":"https://github.com/ivangfr.png","language":"Java","funding_links":["https://github.com/sponsors/ivangfr"],"categories":[],"sub_categories":[],"readme":"# spring-webflux-reactive-databases\n\nThe goal of this project is to play with [`Spring WebFlux`](https://docs.spring.io/spring-framework/reference/web/webflux.html) both on client and server side. For it, we will implement [`Spring Boot`](https://docs.spring.io/spring-boot/index.html) Java Web applications (`product-api`, `customer-api`, `order-api`, `notification-api` and `client-shell`) and use different databases like [`Cassandra`](https://cassandra.apache.org/), [`MongoDB`](https://www.mongodb.com/), [`Postgres`](https://www.postgresql.org/) and [`MySQL`](https://www.mysql.com/).\n\n## Proof-of-Concepts \u0026 Articles\n\nOn [ivangfr.github.io](https://ivangfr.github.io), I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.\n\n## Additional Readings\n\n- \\[**Medium**\\] [**Reactive Book API Tutorial w/ Spring Boot**](https://medium.com/@ivangfr/list/reactive-book-api-tutorial-w-spring-boot-b56befd9e647)\n\n## Project Architecture\n\n![project-diagram](documentation/project-diagram.jpeg)\n\n## Applications\n\n- ### product-api\n\n  `Spring Boot` Java Web application that exposes a REST API to manage `products`. It uses `MongoDB` as storage.\n  \n  ![product-api-swagger](documentation/product-api-swagger.jpeg)\n\n- ### customer-api\n\n  `Spring Boot` Java Web application that exposes a REST API to manage `customers`. It uses `Postgres` as storage.\n  \n  ![customer-api-swagger](documentation/customer-api-swagger.jpeg)\n\n- ### order-api\n\n  `Spring Boot` Web Java application that exposes a REST API to manage `orders`. It uses `Cassandra` as storage. In order to get more information about an `order`, i.e, the `name` of the customer who placed it or the `name` or `price` of the products in the order, `order-api` uses [`WebClient`](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client) and [`CompletableFuture`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) to fetch this information from `customer-api` and `product-api`.\n  \n  ![order-api-swagger](documentation/order-api-swagger.jpeg)\n\n- ### notification-api\n\n  `Spring Boot` Web Java application that exposes a REST API to manage `notifications`.\n\n  ![notification-api-swagger](documentation/notification-api-swagger.jpeg)\n\n- ### client-shell\n\n  `Spring Boot` Shell Java application that has a couple of commands to interact with `product-api`, `customer-api`, `order-api` and `notification-api`. The picture below shows those commands.\n\n  ![client-shell](documentation/client-shell.jpeg)\n  \n## Prerequisites\n\n- [`Java 21`](https://www.oracle.com/java/technologies/downloads/#java21) or higher;\n- A containerization tool (e.g., [`Docker`](https://www.docker.com), [`Podman`](https://podman.io), etc.)\n\n## Initialize Environment\n\n- Open a terminal and inside the `spring-webflux-reactive-databases` root folder, run\n  ```bash\n  ./init-environment.sh\n  ```\n\n- Wait for the script to finish.\n\n## Run applications with Maven\n\n- **product-api**\n\n  Open a new terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following command\n  ```bash\n  ./mvnw clean spring-boot:run --projects product-api\n  ```\n\n- **customer-api**\n\n  Open a new terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following command\n  ```bash\n  ./mvnw clean spring-boot:run --projects customer-api\n  ```\n\n- **order-api**\n\n  Open a new terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following command \n  ```bash\n  ./mvnw clean spring-boot:run --projects order-api\n  ```\n\n- **notification-api**\n\n  Open a new terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following command\n  ```bash\n  ./mvnw clean spring-boot:run --projects notification-api\n  ```\n\n- **client-shell**\n\n  Open a new terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following command to build the executable jar file\n  ```bash\n  ./mvnw clean package --projects client-shell -DskipTests\n  ```\n\n  To start `client-shell`, run:\n  ```bash\n  ./client-shell/target/client-shell-1.0.0.jar\n  ```\n\n## Run applications as Docker containers\n\n- ### Build Docker Images\n  \n  - In a terminal, make sure you are in the `spring-webflux-reactive-databases` root folder/\n  - Run the following script to build the Docker images:\n    ```bash\n    ./build-docker-images.sh\n    ```\n\n- ### Environment Variables\n\n  - **product-api**\n\n    | Environment Variable | Description                                                       |\n    |----------------------|-------------------------------------------------------------------|\n    | `MONGODB_HOST`       | Specify host of the `Mongo` database to use (default `localhost`) |\n    | `MONGODB_PORT`       | Specify port of the `Mongo` database to use (default `27017`)     |\n\n  - **customer-api**\n\n    | Environment Variable | Description                                                          |\n    |----------------------|----------------------------------------------------------------------|\n    | `POSTGRES_HOST`      | Specify host of the `Postgres` database to use (default `localhost`) |\n    | `POSTGRES_PORT`      | Specify port of the `Postgres` database to use (default `5432`)      |\n\n  - **order-api**\n\n    | Environment Variable | Description                                                           |\n    |----------------------|-----------------------------------------------------------------------|\n    | `CASSANDRA_HOST`     | Specify host of the `Cassandra` database to use (default `localhost`) |\n    | `CASSANDRA_PORT`     | Specify port of the `Cassandra` database to use (default `9042`)      |\n    | `PRODUCT_API_HOST`   | Specify host of the `product-api` to use (default `localhost`)        |\n    | `PRODUCT_API_PORT`   | Specify port of the `product-api` to use (default `9080`)             |\n    | `CUSTOMER_API_HOST`  | Specify host of the `customer-api` to use (default `localhost`)       |\n    | `CUSTOMER_API_PORT`  | Specify port of the `customer-api` to use (default `9081`)            |\n\n  - **notification-api**\n\n    | Environment Variable | Description                                                       |\n    |----------------------|-------------------------------------------------------------------|\n    | `MYSQL_HOST`         | Specify host of the `MySQL` database to use (default `localhost`) |\n    | `MYSQL_PORT`         | Specify port of the `MySQL` database to use (default `3306`)      |\n    | `CUSTOMER_API_HOST`  | Specify host of the `customer-api` to use (default `localhost`)   |\n    | `CUSTOMER_API_PORT`  | Specify port of the `customer-api` to use (default `9081`)        |\n    | `ORDER_API_HOST`     | Specify host of the `order-api` to use (default `localhost`)      |\n    | `ORDER_API_PORT`     | Specify port of the `order-api` to use (default `9082`)           |\n\n  - **client-shell**\n\n    | Environment Variable    | Description                                                         |\n    |-------------------------|---------------------------------------------------------------------|\n    | `PRODUCT_API_HOST`      | Specify host of the `product-api` to use (default `localhost`)      |\n    | `PRODUCT_API_PORT`      | Specify port of the `product-api` to use (default `9080`)           |\n    | `CUSTOMER_API_HOST`     | Specify host of the `customer-api` to use (default `localhost`)     |\n    | `CUSTOMER_API_PORT`     | Specify port of the `customer-api` to use (default `9081`)          |\n    | `ORDER_API_HOST`        | Specify host of the `order-api` to use (default `localhost`)        |\n    | `ORDER_API_PORT`        | Specify port of the `order-api` to use (default `9082`)             |\n    | `NOTIFICATION_API_HOST` | Specify host of the `notification-api` to use (default `localhost`) |\n    | `NOTIFICATION_API_PORT` | Specify port of the `notification-api` to use (default `9083`)      |\n\n- ### Start Docker Containers\n\n  - In a terminal, make sure you are inside the `spring-webflux-reactive-databases` root folder.\n  - Run following command:\n    ```bash\n    ./start-apis.sh \u0026\u0026 ./start-shell.sh\n    ```\n    \n## Application's URL\n\n| Application      | URL                                   |\n|------------------|---------------------------------------|\n| product-api      | http://localhost:9080/swagger-ui.html |\n| customer-api     | http://localhost:9081/swagger-ui.html |\n| order-api        | http://localhost:9082/swagger-ui.html |\n| notification-api | http://localhost:9083/swagger-ui.html |\n\n## Playing around\n\n\u003e **Warning**: the ids shown below will be different when you run it\n\n- In `client-shell` terminal, import some products and customers by running the following command:\n  - If you are running using `Maven`:\n    ```bash\n    script ../src/main/resources/samples.txt\n    ```\n  - If you are running as Docker container:\n    ```bash\n    script /workspace/BOOT-INF/classes/samples.txt\n    ```\n    \n- Get all customers\n  ```bash\n  get-customers\n  ```\n  \n  It should return:\n  ```bash\n  {\"id\":\"1\",\"name\":\"Customer A\",\"email\":\"customer.a@test.com\",\"city\":\"Berlin\",\"street\":\"NYC Strasse\",\"number\":\"123\"}\n  {\"id\":\"2\",\"name\":\"Customer B\",\"email\":\"customer.b@test.com\",\"city\":\"Berlin\",\"street\":\"LA Strasse\",\"number\":\"234\"}\n  {\"id\":\"3\",\"name\":\"Customer C\",\"email\":\"customer.c@test.com\",\"city\":\"Berlin\",\"street\":\"DC Strasse\",\"number\":\"345\"}\n  ...\n  ```\n  \n- Get all products\n  ```bash\n  get-products\n  ```\n  \n  It should return:\n  ```bash\n  {\"id\":\"5ee3ee31b460d868af49f389\",\"name\":\"product-1\",\"price\":199.99}\n  {\"id\":\"5ee3ee32b460d868af49f38a\",\"name\":\"product-2\",\"price\":299.99}\n  ...\n  ```\n  \n- Create an order where `Customer A` buys `1 unit` of `product-1` and `2 units` of `product-2`\n  \u003e **Warning**: the product ids informed here are just a sample. You will have different ones.\n  ```bash\n  create-order --customerId 1 --products 5ee3ee31b460d868af49f389:1;5ee3ee32b460d868af49f38a:2\n  ```\n  \n  It should return:\n  ```bash\n  {\n    \"orderId\":\"5aaad64c-4e80-48e0-926d-8f1b7027955a\",\n    \"status\":\"OPEN\",\n    \"created\":\"2020-06-12T22:09:59.558232\",\n    \"products\": [\n      {\"id\":\"5ee3ee31b460d868af49f389\", \"quantity\":1},\n      {\"id\":\"5ee3ee32b460d868af49f38a\", \"quantity\":2}\n    ],\n    \"customerId\":\"1\"\n  }\n  ```\n  \n- Get details about the order created\n  ```bash\n  get-order-detailed 5aaad64c-4e80-48e0-926d-8f1b7027955a\n  ```\n  \n  It should return:\n  ```bash\n  {\n    \"orderId\":\"5aaad64c-4e80-48e0-926d-8f1b7027955a\",\n    \"status\":\"OPEN\",\n    \"created\":\"2020-06-12T22:09:59.558\",\n    \"products\": [\n      {\"id\":\"5ee3ee32b460d868af49f38a\", \"name\":\"product-2\", \"quantity\":2, \"price\":299.99},\n      {\"id\":\"5ee3ee31b460d868af49f389\", \"name\":\"product-1\", \"quantity\":1, \"price\":199.99}\n    ],\n    \"customer\": {\n      \"id\":\"1\",\n      \"name\":\"Customer A\",\n      \"email\":\"customer.a@test.com\",\n      \"city\":\"Berlin\",\n      \"street\":\"NYC Strasse\",\n      \"number\":\"123\"\n    }\n  }\n  ```\n\n- To create a notification for the order created above\n  ```bash\n  create-notification 5aaad64c-4e80-48e0-926d-8f1b7027955a\n  ```\n\n- To check how fast `order-api` get details about the customer and products of an order, create another order where `Customer A` order `50` random products\n  ```bash\n  create-order-random --customerId 1 --numProducts 50\n  ```\n  \n  It should return:\n  ```\n  {\n    \"orderId\":\"87133d36-67f0-4388-b15b-7d66ad739374\",\n    \"status\":\"OPEN\",\n    \"created\":\"2020-06-12T22:14:08.342338\",\n    \"products\": [\n      {\"id\":\"5ee3ee32b460d868af49f38a\", \"quantity\":4},\n      ...\n      {\"id\":\"5ee3ee32b460d868af49f396\", \"quantity\":3}\n    ],\n    \"customerId\":\"1\"\n  }\n  ```\n  \n- In another terminal, to get the details of the previously created order and the response time of this call, use `order-api`'s endpoint `GET /api/orders/{orderId}/detailed`\n  ```bash\n  curl -w \"\\n\\nResponse Time: %{time_total}s\" -s localhost:9082/api/orders/87133d36-67f0-4388-b15b-7d66ad739374/detailed\n  ```\n  \n  It will return something like:\n  ```bash\n  {\n    \"orderId\":\"87133d36-67f0-4388-b15b-7d66ad739374\",\n    \"status\":\"OPEN\",\n    \"created\":\"2020-06-12T22:14:08.342338\",\n    \"products\": [\n      {\"id\":\"5ee3ee32b460d868af49f395\", \"name\":\"product-13\", \"quantity\":4, \"price\":1399.99},\n      ...\n    ],\n    \"customer\": {\n      \"id\":\"1\",\n      \"name\":\"Customer A\",\n      \"email\":\"customer.a@test.com\",\n      \"city\":\"Berlin\",\n      \"street\":\"NYC Strasse\",\n      \"number\":\"123\"\n    }\n  }\n  \n  Response Time: 0.292698s\n  ```\n\n## Useful Commands\n\n- **Cassandra**\n\n  ```bash\n  docker exec -it cassandra cqlsh\n  USE mycompany;\n  SELECT * FROM orders;\n  ```\n  \u003e Type `exit` to get out of `cqlsh`\n\n- **MongoDB**\n\n  ```bash\n  docker exec -it mongodb mongosh productdb\n  db.products.find()\n  ```\n  \u003e Type `exit` to get out of `MongoDB shell`\n\n- **Postgres**\n\n  ```bash\n  docker exec -it postgres psql -U postgres -d customerdb\n  \\dt customer\n  SELECT * FROM CUSTOMER;\n  ```\n  \u003e Type `exit` to get out of `psql`\n\n- **MySQL**\n\n  ```bash\n  docker exec -it -e MYSQL_PWD=secret mysql mysql -uroot --database notificationdb\n  SELECT * FROM notification;\n  ```\n  \u003e Type `exit` to get out of `MySQL monitor`\n\n## Shutdown\n\n- To stop `client-shell`, go to the terminal where it is running and type `exit`.\n- To stop `product-api`, `customer-api`, and `order-api`:\n  - If you start them with `Maven`, go to the terminals where they are running and press `Ctrl+C`.\n  - If you start them as Docker containers, go to a terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following script:\n    ```bash\n    ./stop-apis.sh\n    ```\n- To stop and remove the database containers, network, and volumes, go to a terminal and, inside the `spring-webflux-reactive-databases` root folder, run the script below:\n  ```bash\n  ./shutdown-environment.sh\n  ```\n\n## Cleanup\n\nTo remove all Docker images created by this project, go to a terminal and, inside the `spring-webflux-reactive-databases` root folder, run the following script:\n```bash\n./remove-docker-images.sh\n```\n\n## References\n\n- https://projectreactor.io/docs/core/release/reference/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspring-webflux-reactive-databases","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivangfr%2Fspring-webflux-reactive-databases","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspring-webflux-reactive-databases/lists"}