{"id":23429994,"url":"https://github.com/mikeparcewski/reactiveopenapi","last_synced_at":"2026-04-10T11:32:06.719Z","repository":{"id":43471795,"uuid":"458691510","full_name":"mikeparcewski/reactiveOpenAPI","owner":"mikeparcewski","description":"Some examples of building reactive API's based on Spring Reactor, OpenAPI and other modern technologies","archived":false,"fork":false,"pushed_at":"2022-03-19T08:42:07.000Z","size":492,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-20T10:36:40.721Z","etag":null,"topics":["aws","azure","domain-driven-design","event-driven","gcp","kafka","mongodb","no-sql","openapi","rabbitmq","reactive-programming","spring-reactive"],"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/mikeparcewski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-13T02:41:18.000Z","updated_at":"2022-12-11T07:02:27.000Z","dependencies_parsed_at":"2022-08-23T13:31:26.276Z","dependency_job_id":null,"html_url":"https://github.com/mikeparcewski/reactiveOpenAPI","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mikeparcewski/reactiveOpenAPI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2FreactiveOpenAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2FreactiveOpenAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2FreactiveOpenAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2FreactiveOpenAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikeparcewski","download_url":"https://codeload.github.com/mikeparcewski/reactiveOpenAPI/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeparcewski%2FreactiveOpenAPI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31641114,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["aws","azure","domain-driven-design","event-driven","gcp","kafka","mongodb","no-sql","openapi","rabbitmq","reactive-programming","spring-reactive"],"created_at":"2024-12-23T08:14:02.901Z","updated_at":"2026-04-10T11:32:06.697Z","avatar_url":"https://github.com/mikeparcewski.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"```diff\n- This is a work in progress, if you bave any issues please raise an issue or pull request\n```\n\n# Reactive Application Reference Implementation \n\n```mermaid\ngraph LR\n    A[OpenAPI] --\u003e|Contract| C(Reactive API)\n    B[BDD] --\u003e |Smoke Tests| C(Reactive API)\n    C --\u003e|Persistence| E[(MongoDB)]\n    E --\u003e|Producer| G([Spring DomainEvent])\n    G --\u003e|Subscriber| H([Spring DomainEvent])\n```\n\n## OpenAPI/BDD/Spring Reactor/MongoDB/Spring Domain Events (and a little magic)\n\nA reference application that shows some real world hacks and tricks needed to make some of the cooler tech work in \nreal world situations. As far as the app goes, it's a simple Reactive CRUD application developed using OpenAPI that \ndemonstrates how you might use NoSQL DB (MongoDB), spring domain messaging, BDD and a bunch of other useful stuff.\n\n### The Technology\n\nTo name a few...\n\n* [Spring Reactor](https://projectreactor.io/) - The core for our reactive microservice\n* [OpenAPI Tools](https://github.com/openapitools/openapi-generator) - Bringing our API-First approach to life\n* [BDD For All](https://github.com/Accenture/bdd-for-all/) - Enabling our Test-First (or TDD) approach\n* [MongoDB](https://www.mongodb.com/) - How we're persisting data\n* [Spring Domain Events](https://www.baeldung.com/spring-data-ddd) - Fun way of handling domain events internally or externally\n* [Lombok](https://projectlombok.org/) - Write less code\n* [Mapstruct](https://mapstruct.org/) - Fast way to map our objects\n* [JUnit](https://junit.org/junit5/) - For all those other things we need to test\n\n### Prerequisites\n\nTo compile \u0026 run, you'll need...\n\n* JDK 11\n* Maven\n* [MongoDB](https://docs.mongodb.com/guides/server/install/) or if you're me [use brew](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/)\n\n#### OpenAPI - An API-First Approach\n\nThis project utilizes the OpenAPITools generator to create the base of the application.  Based on the OpenAPI 3.0 spec\nlocated in [src/main/resources/openapi.yaml](src/main/resources/openapi.yaml) and a simple configuration in\nthe [pom.xml](pom.xml) we create...\n\n* All of the DTO models\n* The controller, API and delegate classes\n* Documentation endpoint\n\nBy running\n\n```shell\nmvn compile\n```\n\nYou can see the code generated in **target/generated-sources/**.  This code will handle most of the plumbing, so you can focus on\nthe implementation.\n\nIn this case, all you need to do is create a delegate implementation (see *com.wickedagile.apis.reference.reactoropenapi.api.VendorAPIDelegateImpl*\nin the generated sources directory).  The reference implementation can be found at\n[src/main/java/com/wickedagile/apis/reference/reactoropenapi/api/PatientAPIDelegateImpl.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/api/VendorAPIDelegateImpl.java).\n\n90% of the plumbing you need is generated by this process.  We do create some domain objects to map these, but in an ideal world these would be generated as well.\n\nTo learn more about generation, check out...\n\n* Main plugin - https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin\n* Spring specific configuration options - https://openapi-generator.tech/docs/generators/spring/\n\n\u003e You can switch back and forth from a reactive project to standard blocking API's by changing **\u0026lt;reactive\u0026gt;true\u0026lt;/reactive\u0026gt;** to false.\n\u003e You will need to change the Delegate implementation when swapping back/forth, though.\n\n#### MongoDB\n\nThe default database name is **reactiveOpenAPIMongo**, port **27017** on localhost and isn't password protected.  You can change any of this in the [application.yml](src/main/resources/application.yml).\n\n\u003e Check out our [MongoDB docs](docs/MONGODB.md) for more information on configuration.\n\nFor testing, we're using an in-memory version of MongoDB so there's really nothing to do either.\n\n\u003e If you don't want to install MongoDB or use Atlas, you can actually use the in memory version of MongoDB by simply removing \n\u003e \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; from the de.flapdoodle.embed dependency in the pom file\n\nBecause we wanted to hook into change events from the repository to create and broadcast \"domain\" events, \nwe had to hardcode in MongoDB to the app.  This is because we ran into issues with DomainEvents and some of the \nother generic ways of capturing changes.  Mostly due to bugs between Lombok, Spring Data, etc...\n\nThis means that if you want to change DB's, you'll need to change...\n\n* [src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/PatientRepository.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/PatientRepository.java)\n* [src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/RepositoryListener.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/RepositoryListener.java)\n* and of course the configurations\n\nThere's not a lot of code and what is there is pretty generic (and many other Spring Data implementations have). \nIn a perfect world, we would have 0 code changes, but the things about using the latest and greatest of each \nmeans interopability you might have found in older version gets a bit tricky.\n\n#### Events\n\nOut of the box, we're using [Spring Domain Events](https://www.baeldung.com/spring-data-ddd) \nwhich aren't durable, but don't require configuring something else.\n\nThese local events are easy to use and can be published/consumed without explicitly linking our code (e.g. method chaining).  Now these events ARE NOT\ndurable and if the publisher throws an exception the subscribers will never know :( which means...\n\n\u003e Be smart about using this option.  If you need truly durable change events, would recommend looking at\n\u003e the Change Feed options from your cloud providers - almost every provider has these now for every DB (Sql or not)\n\nThe simple example of an internal processor is [src/main/java/com/wickedagile/apis/reference/reactoropenapi/event/Auditor.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/event/Auditor.java)\nwhich literally just logs the messages it receives, and although there are some better [auditing mechanisms](https://medium.com/swlh/data-auditing-with-spring-data-r2dbc-5d428fc94688)\navailable, the idea was to just showcase one potential use case for why you might want an internal event processor.\n\nIf you're interested in expanding to Kafka (or Azure Event Hubs, RabbitMQ, GCP Pub/Sub or AWS Kinesis) \nplease check out [docs/MESSAGING.md](docs/MESSAGING.md).  The implementation is based on Spring Cloud \nStreams Binder solution, which makes it easy to switch providers without changing code (just config).\n\n### Running the Application\n\nFor running (make sure mongodb is started), just execute...\n\n```shell\nmvn clean spring-boot:run\n```\n\nIf it works, you should be able to go to http://localhost:8080/docs and see the docs for the API's.  The \n\"Try It Out\" feature will let you experiment with the API's and you can check the log (in [logs/](logs/)) or \nSTDOUT to check out the messages firing.\n\n### How it Works\n\nThis reference uses a few different techniques to minimize code (and improve quality).\n\n\n#### Shifting Left\n\nBefore a line of code is written, we've included a bunch of quality and security into the project to ensure that \nfrom the first lines of code written, we are keeping things clean and secure.\n\n* [Checkstyle](https://checkstyle.sourceforge.io/google_style.html) (Google Java Style) - combines aesthetic and coding\n  conventions that make code easier to read and merge across the team\n* [Maven Enforcer](https://maven.apache.org/enforcer/maven-enforcer-plugin/) - keeps your dependencies clean (e.g.\n  duplicates, competing versions, etc...)\n* [OWASP Dependency Check](https://jeremylong.github.io/DependencyCheck/dependency-check-maven/index.html) - see what \n  vulnerabilities the libraries you're using have\n* [Spotbugs](https://spotbugs.github.io/) - Open source static analysis for Java code combined\n  with [Find Security Bugs](https://find-sec-bugs.github.io/) for security audits\n  and [fb-contrib](http://fb-contrib.sourceforge.net/) for some auxiliary audits.\n* [PMD/CPD](https://pmd.github.io/) - Another static analyzer focused on things like unused variables/imports, \n  empty catch blocks and other bad (or hacky) practices.\n* [JaCoCo](https://www.eclemma.org/jacoco/) - Code coverage that looks at our BDD \u0026 JUnit reports to make sure we're\n  testing our code. Alternative here is [OpenClover](http://openclover.org/), but JaCoCo seems to be the goto in a lot\n  of orgs these days (been around longer)\n\nThese are all configured in [pom.xml](pom.xml), and although some of these are run during the test phase, you can get \ndetailed reporting by...\n\n```shell\nmvn clean verify\n```\n\nwill tell you if there are any errors and...\n\n```shell\nmvn clean site\n```\n\nWill provide a full report, you can see it by going to `target/site/index.html` in your browser and \ncheckout the what's under the \"Project Reports\" section.\n\n##### Checkstyle\n\nIt's recommended you configure you editor to use checkstyle, for rules you don't agree with you can just update \nyour [checkstyle-suppressions.xml](checkstyle-suppressions.xml).  Recommendation is to keep this to a minimum, \nthough, since the editor plugin will automatically correct most issues.\n\nhttps://checkstyle.sourceforge.io/google_style.html\n\n##### Maven Enforcer \n\nThis is one of the reasons our *dependencyManagement* in the pom is so big and also why we have exclusions with \nthe Spring Webflux depdency.  This doesn't just check our primary dependencies for [collision](https://www.baeldung.com/maven-version-collision), \nit checks their dependencies as well. The potential issues can be negligible from this, but do you really \nwant to find out the hard way?\n\nThis can lead to a lot of cruft in the pom file, though, and can make upgrading versions a bit messy, so you need to \nbe really thoughtful here and decide what works best for your team.\n\nhttps://maven.apache.org/enforcer/maven-enforcer-plugin/\n\n##### OWASP Dependency Check\n\nWhy wait till your Veracode or Blackduck scan is complete to find out you need to change or upgrade a dependency?\n\nTo fix the issues, you have two options (well three)...\n\n* Upgrade the lib to a secure version, by adding it to the *dependencyManagement* in the [pom.xml](pom.xml)\n* Add it to the excludes (just ignores the problem) [spotbugs-exclude.xml](spotbugs-exclude.xml)\n* Find a different (secure) library - not always easy/reccomended\n\nhttps://jeremylong.github.io/DependencyCheck/dependency-check-maven/index.html\n\n##### Spotbugs \u0026 PMD/CPD\n\nWhy waste time on catching things in your manual code reviews, these, combined with some other plugins will pretty \nmuch guarantee a pass from analyzers like Sonarqube and in combination with the other plugins will have you \nsome pretty clean code in your pull requests.\n\n\u003e For those that you just don't want to deal with, [spotbugs-exclude.xml](spotbugs-exclude.xml) is there to override.\n\nhttps://spotbugs.github.io/ \u0026 https://pmd.github.io/\n\n##### JaCoCo\n\nWonder how much of your code is being tested?  If you're doing BDD/TDD right this should be a no brainer.  \nI'm a strong believer in functional testing over unit and if done right, your code coverage should be right, \nsince functional tests should flex the muscle of most of your code.  If it's not, two things...\n\n* You've written code you didn't need to\n* Your missing some test cases\n\nTo see the report, you have two options...\n\n1. `mvn site` will give you the full set of reports, you just need to open up [target/site/project-reports.html](target/site/project-reports.html)\n2. `mvn test jacoco:report` will generate the stand alone report in [target/site/jacoco/index.html](target/site/jacoco/index.html)\n\n#### Test-first\n\nFor our tests we use a BDD style (Gherkin) approach with [BDD For All](https://github.com/Accenture/bdd-for-all).  \nFocused on some positive and negative smoke tests, we make sure that our application is functioning as expected \nbefore we write a line of code.  This is done quite simply by...\n\n1. Creating a test runner [src/test/java/RunCucumberTests.java](src/test/java/RunCucumberTests.java) responsible for starting up the spring app and executing the feature files\n2. Then you'll need add some configuration [src/test/resources/application.yml](src/test/resources/application.yml), this will be pretty much be the same for most implementations.  It sets the server/port, but you can do a lot in this.\n3. Finally, you'll need one or more feature files.  These are currently found in [src/test/resources/features](src/test/resources/features)\n\nAfter running tests, you can see the full report in [target/cucumber/cucumber-html-reports/overview-features.html](target/cucumber/cucumber-html-reports/overview-features.html)\n\n##### Creative Component Testing\n\nIn addition to executing the functional tests, we also \"hook\" into the eventing framework to see if we're generating \nthe number of events we'd expect from all these CRUD requests.  This is done via the [src/test/java/com/wickedagile/apis/reference/reactoropenapi/event/EventsConfig.java](src/test/java/com/wickedagile/apis/reference/reactoropenapi/event/EventsConfig.java) \nclass.  We simply collect the events (and their types) and match them against an expected output.\n\nThis allows us to write a lot less test code, but test important functionality as part of our functional tests since \nwe're still trying to figure out how BDD and Event Driven Architectures can place nicely.\n\nRecommend reviewing the user guide - https://github.com/Accenture/bdd-for-all/blob/develop/docs/USERGUIDE.md - as BDD For All can do a lot \nand to put in perspective, the better your BDD tests are, the better your code coverage will be, which means less Unit tests (Yay!).\n\n## Some More Background\n\nThere's a lot happening in here, so want to make sure I cover some more features...\n\n#### Reactive Data Repositories\n\nYou can't be a true reactive (or streaming) application if you block.  One of the hardest part of designing transactional \nsystems in a \"reactive\" environment is that you have to deal with data sources.\n\nDatastores traditionally were designed to block (e.g. request -\u003e wait \u003c- respond), but between a multitude of vendors \n(including our friends @ [MongoDB](https://www.mongodb.com/)) and Spring, they've made this pretty easy to do and \nsince there are better writers than me documenting this stuff, and really \"reactive repositories\" are just\n[JPA](https://spring.io/projects/spring-data-jpa) on steroids.\n\n\u003e Need more detail on reactive repositories?  Go visit https://www.baeldung.com/spring-data-mongodb-reactive.\n\nAll that aside, I will mention here that we made our code specific to Mongo with two classes, something I didn't \nwant to do, but had to even though the code is pretty easy to tweak.  These classes are...\n\n* [src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/VendorRepository.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/VendorRepository.java) - A simple spring repo\n* [src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/RepositoryListener.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/repository/RepositoryListener.java) - Our change event listener\n\nNow, in a perfect world we would have used a [generic type](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/reactive/package-summary.html), which would \nallow us to switch between DB's easily with just configuration changes.  But the world isn't perfect and we needed \nto make this work.  To this end, we used the Vendor specific implementations so we could capture the \nchange (insert/update/delete/view) events.  Check out the comments in RepositoryListener for more on why.\n\n\u003e Final word - Don't ever block a Mono or Flux, a lot of first timers try to work with these objects like they're\n\u003e normal Java POJO's.  They're not.  Do some homework before attempting at home!\n\n#### Centralized Exception Handling\n\nNow the folks at [Baeldung might disagree](https://www.baeldung.com/exception-handling-for-rest-with-spring) with our approach, \nbut when building enterprise software, centralizing anything is usually super helpful.   It's for this reason \nwe used the @ControllerAdvice option for error handling.\n\nYou can check out [src/main/java/com/wickedagile/apis/reference/reactoropenapi/domain/exception/InvalidEntityHandler.java](src/main/java/com/wickedagile/apis/reference/reactoropenapi/domain/exception/InvalidEntityHandler.java) \nfor more detail, but it's really simple...\n\n```java\n\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\n\n@ControllerAdvice\npublic class MyExceptionHandler {\n\n  @ExceptionHandler(IllegalArgumentException.class)\n  public ResponseEntity myHandlerMethod(IllegalArgumentException ex) {\n    return ResponseEntity.status(HttpStatus.NOT_FOUND)\n            .contentType(MediaType.APPLICATION_JSON)\n            .body(Arrays.asList(errorMapper.argErrorToError(ex).code(INVALID_PAYLOAD)));\n  }\n  \n}\n\n```\n\nThe important parts of the code are the annotations.  First, we have @ControllerAdvice, and this just tells \nSpring that we may have some code to execute should certain situations arise (e.g. exception).\n\nThe next annotation is the @ExceptionHandler one, and for this we provide an exception (e.g. IllegalArgumentException).  \nAll this does is tell Spring that any time an IllegalArgumentException is thrown by any controller, catch it \nand do this.\n\nNow the argument to use something like ResponseStatusException is that you can standardize the exception response \nand provide engineers more control over the handling itself.  I find in most cases this is theory, not the reality. \nThe security of ensuring your capturing exceptions from everywhere vs leaving it up to someone who is in a rush \nto deliver a feature, seems like a bigger problem.\n\n##  The End Goal\n\nI don't necessarily believe that reference implementations like this work well if you're just trying to pull \ncode to get something to work or fork and try to modify for your own API spec.  My overall goal is to turn this \ninto a Maven Archetype before Spring deprecates the code :)\n\nIf you want to help, ping me.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeparcewski%2Freactiveopenapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikeparcewski%2Freactiveopenapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeparcewski%2Freactiveopenapi/lists"}