{"id":15595457,"url":"https://github.com/cdimascio/openapi-spring-webflux-validator","last_synced_at":"2025-04-05T15:07:38.930Z","repository":{"id":27491098,"uuid":"112494052","full_name":"cdimascio/openapi-spring-webflux-validator","owner":"cdimascio","description":"🌱 A friendly kotlin library to validate API endpoints using an OpenApi 3.0 and Swagger 2.0 specification","archived":false,"fork":false,"pushed_at":"2024-12-19T22:36:55.000Z","size":353,"stargazers_count":97,"open_issues_count":6,"forks_count":13,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-29T14:09:44.626Z","etag":null,"topics":["functional","hacktoberfest","java","openapi","openapi3","rest","spring","swagger","swagger-validator","validation","webflux"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cdimascio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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}},"created_at":"2017-11-29T15:41:04.000Z","updated_at":"2025-02-09T11:27:52.000Z","dependencies_parsed_at":"2024-11-15T22:28:14.560Z","dependency_job_id":"aa1f3c36-d110-4ece-9083-6e9b0251181a","html_url":"https://github.com/cdimascio/openapi-spring-webflux-validator","commit_stats":{"total_commits":195,"total_committers":14,"mean_commits":"13.928571428571429","dds":0.5897435897435898,"last_synced_commit":"bd1e80a848d0fe1c245d0db626e50100e8852038"},"previous_names":["cdimascio/swagger-spring-functional"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdimascio%2Fopenapi-spring-webflux-validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdimascio%2Fopenapi-spring-webflux-validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdimascio%2Fopenapi-spring-webflux-validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdimascio%2Fopenapi-spring-webflux-validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cdimascio","download_url":"https://codeload.github.com/cdimascio/openapi-spring-webflux-validator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247353745,"owners_count":20925329,"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":["functional","hacktoberfest","java","openapi","openapi3","rest","spring","swagger","swagger-validator","validation","webflux"],"created_at":"2024-10-03T01:00:24.034Z","updated_at":"2025-04-05T15:07:38.900Z","avatar_url":"https://github.com/cdimascio.png","language":"Kotlin","readme":"# openapi-spring-webflux-validator\n![](https://travis-ci.org/cdimascio/openapi-spring-webflux-validator.svg?branch=master)[![Maven Central](https://img.shields.io/maven-central/v/io.github.cdimascio/openapi-spring-webflux-validator.svg?label=Maven%20Central)](https://search.maven.org/artifact/io.github.cdimascio/openapi-spring-webflux-validator/4.2.0/jar) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f78b72ca90104e42b111723a7720adf3)](https://www.codacy.com/app/cdimascio/openapi-spring-webflux-validator?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=cdimascio/openapi-spring-webflux-validator\u0026amp;utm_campaign=Badge_Grade) ![](https://img.shields.io/badge/license-Apache%202.0-blue.svg)\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e \n\nA friendly kotlin library to validate API endpoints using an _OpenApi 3_ or _Swagger 2_ specification. Great with webflux functional. \nIt **works happily with Spring Webflux 6's baseline of Jakarta JVM runtime \u003e=17**. \n\u003cp align=\"center\"\u003e\n\t\u003cimg width=\"300\" src=\"https://raw.githubusercontent.com/cdimascio/openapi-spring-webflux-validator/master/assets/openapi-webflux-validator-logo2.png\" width=\"600\"/\u003e\n\u003c/p\u003e\n\nSupports specifications in _YAML_ and _JSON_\n\n## Prequisites\n\nand Spring Webflux 6 + Java \u003e=17\n\n_For use with Spring Boot 2 and Webflux 5, use `openapi-spring-webflux-validator` version `3.5.0`. Java 8 or greater is required._ \n\n## Install\n\n### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.cdimascio\u003c/groupId\u003e\n    \u003cartifactId\u003eopenapi-spring-webflux-validator\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Gradle\n\n```groovy\ncompile 'io.github.cdimascio:openapi-spring-webflux-validator:4.2.0'\n```\n\nFor sbt, grape, ivy and more, see [here](https://search.maven.org/#artifactdetails%7Cio.github.cdimascio%7Copenapi-spring-webflux-validator%7C2.0.0%7Cjar)\n\n## Usage (Kotlin)\n\nThis section and the next describe usage with Kotlin and Java respectively.\n\nSee this [complete Spring Webflux example that uses openapi-spring-webflux-validator](https://github.com/cdimascio/kotlin-swagger-spring-functional-template).\n\n### Configure (Kotlin)\n\nThis one-time configuration requires you to provide the _location of the openapi/swagger specification_ and an optional _custom error handler_.\n\nSupports `JSON` and `YAML`\n\n```kotlin\nimport io.github.cdimascio.openapi.Validate\n\nval validate = Validate.configure(\"static/api.yaml\")\n```\n\nwith custom error handler\n\n```kotlin\nimport org.springframework.web.reactive.function.server.ServerRequest\n\ndata class MyError(val request: ServerRequest, val code: String, val messages: List\u003cString\u003e)\nval validate = Validate.configure(\"static/api.json\") { request, status, messages -\u003e\n   MyError(request, status.name, messages)\n}\n```\n\nwith custom ObjectMapper factory:\n\n```kotlin\nval validate = Validate.configure(\n   openApiSwaggerPath = \"api.yaml\",\n   errorHandler = { request, status, message -\u003e ValidationError(request, status.value(), message[0]) },\n   objectMapperFactory = { ObjectMapper()\n       .registerKotlinModule()\n       .registerModule(JavaTimeModule())\n       .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) }\n)\n```\n\n### Validate a request (Kotlin + Reactor)\n\nYou can now validate a request in a coroutine style,\nusing the `validate` instance created [above](#configure-kotlin):\n\nwithout a body\n\n```kotlin\nvalidate.request(req) {\n    // Do stuff e.g. return a list of names \n    ok().body(Mono.just(listOf(\"carmine\", \"alex\", \"eliana\")))\n}\n```\n\nwith body\n\n```kotlin\nvalidate.request(req).withBody(User::class.java) { body -\u003e\n    // Note that body is deserialized as User!\n    // Now you can do stuff. \n    // For example, lets echo the request as the response \n    ok().body(Mono.just(body))\n}\n```\n\nwith body you want to process as string (e.g. for computing a request signature), or that you want to deserialize somehow specifically\n\n```kotlin\nval identity: (String) -\u003e String = { it }\nvalidate.request(req).withBody(String::class.java, readValue = identity) { body -\u003e\n    ok().body(Mono.just(\"content length is ${body.length}\"))\n}\n```\n\n### Validate a request (Kotlin + coroutines)\n\nOr you can validate a request in a coroutine style,\nusing the `validate` instance created [above](#configure-kotlin):\n\n\nwithout a body\n\n```kotlin\nvalidate.requestAndAwait(req) {\n    // Do stuff e.g. return a list of names \n    ok().bodyValueAndAwait(listOf(\"carmine\", \"alex\", \"eliana\"))\n}\n```\n\nwith body\n\n```kotlin\nvalidate.request(req).awaitBody(User::class.java) { body: User -\u003e\n    // Note that body is deserialized as User!\n    // Now you can do stuff. \n    // For example, lets echo the request as the response \n    ok().bodyValueAndAwait(body)\n}\n```\n\nwith body you want to process as string (e.g. for computing a request signature), or that you want to deserialize somehow specifically\n\n```kotlin\nval identity: (String) -\u003e String = { it }\nvalidate.request(req).awaitBody(String::class.java, identity) { body: String -\u003e\n    ok().bodyValueAndAwait(\"content length is ${body.length}\")\n}\n```\n\n## Usage\n\n### Configure (Java)\nThis one-time configuration requires you to provide the _location of the openapi/swagger specification_ and an optional _custom error handler_.\n\n```java\nimport io.github.cdimascio.openapi.Validate;\n\nValidate\u003cValidationError\u003e validate = Validate.configure(\"static/api.json\")\n```\n\nwith custom error handler\n\n```java\nimport org.springframework.web.reactive.function.server.ServerRequest;\n\nclass MyError {\n    private ServerRequest request;\n    private String id;\n    private  String messages;\n    public MyError(ServerRequest request, String id, List\u003cString\u003e messages) {\n        this.request = request;\n        this.id = id;\n        this.messages = messages;\n    }\n    public ServerRequest getRequest() {\n        return request;\n    }\n    public String getId() {\n        return id;\n    }\n    public void setId(String id) {\n        this.id = id;\n    }\n    public List\u003cString\u003e getMessages() {\n        return messages;\n    }\n    public void setMessages(List\u003cString\u003e messages) {\n        this.messages = messages;\n    }     \n}\n```\n\n```java\nValidate\u003cValidationError\u003e validate = Validate.configure(\"static/api.json\", (request, status, messages) -\u003e\n    new MyError(request, status.getName(), messages)\n);\n```\n\n### Validate a request (Java)\n\nUsing the `validate` instance created above, you can now validate a request:\n\nwithout a body\n\n```java\nArrayList\u003cString\u003e users = new ArrayList\u003cString\u003e() {{\n    add(\"carmine\");\n    add(\"alex\");\n    add(\"eliana\");\n}};\n\nvalidate.request(req, () -\u003e\n    // Do stuff e.g. return a list of user names\n    ServerResponse.ok().bodyValue(users)\n);\n```\n\nwith body\n\n```java\nvalidate\n    .request(req)\n    .withBody(User.class, user -\u003e \n        // Note that body is deserialized as User!\n        // Now you can do stuff. \n        // For example, lets echo the request as the response\n        ServerResponse.ok().bodyValue(user)\n    );\n```\n\nwith body you want to process as string (e.g. for computing a request signature)\n\n```java\nvalidate\n    .request(req)\n    .withBody(String.class, s -\u003e s, body -\u003e\n        ServerResponse.ok().bodyValue(\"content length is \" + body.length())\n    );\n```\n\n## Example Validation Output\n\nLet's assume a `POST` request to create a user requires the following request body:\n\n```json\n{\n  \"firstname\": \"carmine\",\n  \"lastname\": \"dimasico\"\n}\n```\n\nLet's now assume an API user misspells `lastname` as `lastnam`\n\n```shell\ncurl -X POST http://localhost:8080/api/users -H \"Content-Type: application/json\" -d'{ \n  \"firstname\": \"c\", \n  \"lastnam\": \"d\" \n}'\n```\n\n`openapi-spring-webflux-validator` automatically validates the request against a Swagger spect and returns:\n\n```json\n{\n  \"code\": 400,\n  \"messages\":[\n\t  \"Object instance has properties which are not allowed by the schema: [\\\"lastnam\\\"]\",\n\t  \"Object has missing required properties ([\\\"lastname\\\"])\"\n  ]\n} \n```\n\n**Woah! Cool!!** :-D \n\n## Example\n\nLet's say you have an endpoint `/users` that supports both `GET` and `POST` operations.\n\nYou can create those routes and validate them like so:\n\n**Create the routes in a reactive or coroutine style:**\n\n```kotlin\npackage myproject.controllers\n\nimport org.springframework.core.io.ClassPathResource\nimport org.springframework.http.MediaType.*\nimport org.springframework.web.reactive.function.server.ServerResponse.permanentRedirect\nimport org.springframework.web.reactive.function.server.coRouter\nimport org.springframework.web.reactive.function.server.plus\nimport org.springframework.web.reactive.function.server.router\nimport java.net.URI\n\nclass Routes(private val userHandler: UserHandler) {\n    fun router() = router {\n        \"/api\".nest {\n            accept(APPLICATION_JSON).nest {\n                POST(\"/users\", userHandler::create)\n            }\n            accept(TEXT_EVENT_STREAM).nest {\n                GET(\"/users\", userHandler::findAll)\n            }\n        }\n    } + coRouter { \n        \"/coApi\".nest {\n            accept(APPLICATION_JSON).nest {\n                POST(\"/users\", userHandler::coCreate)\n            }\n            accept(TEXT_EVENT_STREAM).nest {\n                GET(\"/users\", userHandler::coFindAll)\n            }\n        }\n    }\n}\n```\n\n```kotlin\npackage myproject\n\nimport io.github.cdimascio.openapi.Validate\n\nval validate = Validate.configure(\"static/api.yaml\")\n```\n\n**Validate with openapi-spring-webflux-validator**\n\n```kotlin\npackage myproject.controllers\n\nimport myproject.models.User\nimport myproject.validate\nimport org.springframework.web.reactive.function.server.ServerRequest\nimport org.springframework.web.reactive.function.server.ServerResponse\nimport org.springframework.web.reactive.function.server.ServerResponse.ok\nimport org.springframework.web.reactive.function.server.bodyValueAndAwait\nimport reactor.core.publisher.Flux\nimport reactor.core.publisher.Mono\n\nclass UserHandler {\n\n    fun findAll(req: ServerRequest): Mono\u003cServerResponse\u003e {\n        return validate.request(req) {\n            ok().bodyValue(listOf(\"carmine\", \"alex\", \"eliana\"))\n        }\n    }\n\n    fun create(req: ServerRequest): Mono\u003cServerResponse\u003e {\n        return validate.request(req).withBody(User::class.java) {\n            // it is the request body deserialized as User\n            ok().bodyValue(it)\n        }\n    }\n\n    suspend fun coFindAll(req: ServerRequest): ServerResponse {\n        return validate.requestAndAwait(req) {\n            ok().bodyValueAndAwait(listOf(\"carmine\", \"alex\", \"eliana\"))\n        }\n    }\n\n    suspend fun coCreate(req: ServerRequest): ServerResponse {\n        return validate.request(req).awaitBody(User::class.java) {\n            // it is the request body deserialized as User\n            ok().bodyValueAndAwait(it)\n        }\n    }\n}\n```\n\n## License\n\n[Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)\n\n\u003ca href=\"https://www.buymeacoffee.com/m97tA5c\" target=\"_blank\"\u003e\u003cimg src=\"https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/orange_img.png\" alt=\"Buy Me A Coffee\" style=\"height: auto !important;width: auto !important;\" \u003e\u003c/a\u003e\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/cdimascio\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/4706618?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eCarmine DiMascio\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=cdimascio\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=cdimascio\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=cdimascio\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/krzykrucz\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/18364177?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKrzysiek Kruczyński\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=krzykrucz\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=krzykrucz\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=krzykrucz\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/chejerlakarthik\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/12871079?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eChejerla Karthik\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=chejerlakarthik\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://www.katielevy.com\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/8975181?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKatie Levy\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=katielevy1\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/reinterpretcat\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/1611077?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eIlya Builuk\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=reinterpretcat\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://simon.zambrovski.org/\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/673128?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSimon Zambrovski\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=zambrovski\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/cdimascio/openapi-spring-webflux-validator/commits?author=zambrovski\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-enable --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","funding_links":["https://www.buymeacoffee.com/m97tA5c"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdimascio%2Fopenapi-spring-webflux-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcdimascio%2Fopenapi-spring-webflux-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdimascio%2Fopenapi-spring-webflux-validator/lists"}