Repository: springdoc/springdoc-openapi-demos
Branch: master
Commit: c95efaf3dc48
Files: 238
Total size: 382.0 KB
Directory structure:
gitextract_h9gh0xwv/
├── .gitattributes
├── .gitignore
├── Jenkinsfile
├── LICENSE
├── README.md
├── SUPPORT.md
├── demo-book-service/
│ ├── .gitignore
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── book/
│ │ │ ├── SpringdocApplication.java
│ │ │ ├── controller/
│ │ │ │ └── BookController.java
│ │ │ ├── exception/
│ │ │ │ ├── BookNotFoundException.java
│ │ │ │ └── GlobalControllerExceptionHandler.java
│ │ │ ├── model/
│ │ │ │ └── Book.java
│ │ │ └── repository/
│ │ │ └── BookRepository.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── logback.xml
│ └── test/
│ └── java/
│ └── org/
│ └── springdoc/
│ └── demo/
│ └── services/
│ └── book/
│ └── SwaggerUnitTest.java
├── demo-microservices/
│ ├── .gitignore
│ ├── README.md
│ ├── config-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── config/
│ │ │ └── ConfigApplication.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── config/
│ │ ├── department-service.yml
│ │ ├── discovery-service.yml
│ │ ├── employee-service.yml
│ │ ├── gateway-service.yml
│ │ └── organization-service.yml
│ ├── department-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── department/
│ │ │ ├── DepartmentApplication.java
│ │ │ ├── client/
│ │ │ │ └── EmployeeClient.java
│ │ │ ├── controller/
│ │ │ │ └── DepartmentController.java
│ │ │ ├── model/
│ │ │ │ ├── Department.java
│ │ │ │ └── Employee.java
│ │ │ └── repository/
│ │ │ └── DepartmentRepository.java
│ │ └── resources/
│ │ └── application.yml
│ ├── discovery-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── discovery/
│ │ │ └── DiscoveryApplication.java
│ │ └── resources/
│ │ └── application.yml
│ ├── employee-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── employee/
│ │ │ ├── EmployeeApplication.java
│ │ │ ├── controller/
│ │ │ │ └── EmployeeController.java
│ │ │ ├── model/
│ │ │ │ └── Employee.java
│ │ │ └── repository/
│ │ │ └── EmployeeRepository.java
│ │ └── resources/
│ │ └── application.yml
│ ├── gateway-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── gateway/
│ │ │ ├── ContextPathRewritePathGatewayFilterFactory.java
│ │ │ └── GatewayApplication.java
│ │ └── resources/
│ │ └── application.yml
│ ├── organization-service/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── organization/
│ │ │ ├── OrganizationApplication.java
│ │ │ ├── client/
│ │ │ │ ├── DepartmentClient.java
│ │ │ │ └── EmployeeClient.java
│ │ │ ├── controller/
│ │ │ │ └── OrganizationController.java
│ │ │ ├── model/
│ │ │ │ ├── Department.java
│ │ │ │ ├── Employee.java
│ │ │ │ └── Organization.java
│ │ │ └── repository/
│ │ │ └── OrganizationRepository.java
│ │ └── resources/
│ │ └── application.yml
│ └── pom.xml
├── demo-oauth2/
│ ├── .gitignore
│ ├── README.md
│ ├── oauth-authorization-server/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── auth/
│ │ │ ├── AuthorizationServerApp.java
│ │ │ ├── DefaultSecurityConfig.java
│ │ │ ├── Jwks.java
│ │ │ ├── KeyGeneratorUtils.java
│ │ │ └── SecurityConfig.java
│ │ └── resources/
│ │ └── application.yml
│ ├── oauth-resource-server-webflux/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── resource/
│ │ │ ├── ResourceServerApp.java
│ │ │ ├── config/
│ │ │ │ ├── OpenApiConfig.java
│ │ │ │ └── SecurityConfig.java
│ │ │ ├── model/
│ │ │ │ └── Foo.java
│ │ │ ├── repository/
│ │ │ │ └── IFooRepository.java
│ │ │ ├── service/
│ │ │ │ ├── IFooService.java
│ │ │ │ └── impl/
│ │ │ │ └── FooServiceImpl.java
│ │ │ └── web/
│ │ │ ├── controller/
│ │ │ │ ├── FooController.java
│ │ │ │ └── UserInfoController.java
│ │ │ └── dto/
│ │ │ └── FooDTO.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── data.sql
│ ├── oauth-resource-server-webmvc/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── resource/
│ │ │ ├── ResourceServerApp.java
│ │ │ ├── config/
│ │ │ │ ├── OpenApiConfig.java
│ │ │ │ └── SecurityConfig.java
│ │ │ ├── model/
│ │ │ │ └── Foo.java
│ │ │ ├── repository/
│ │ │ │ └── IFooRepository.java
│ │ │ ├── service/
│ │ │ │ ├── IFooService.java
│ │ │ │ └── impl/
│ │ │ │ └── FooServiceImpl.java
│ │ │ └── web/
│ │ │ ├── controller/
│ │ │ │ ├── FooController.java
│ │ │ │ └── UserInfoController.java
│ │ │ └── dto/
│ │ │ └── FooDTO.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── data.sql
│ └── pom.xml
├── demo-person-service/
│ ├── .gitattributes
│ ├── .gitignore
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── services/
│ │ └── person/
│ │ ├── SampleApplication.java
│ │ ├── config/
│ │ │ └── SampleConfig.java
│ │ ├── controller/
│ │ │ └── PersonController.java
│ │ ├── exceptions/
│ │ │ ├── ErrorMessage.java
│ │ │ ├── GlobalControllerAdvice.java
│ │ │ └── Problem.java
│ │ └── model/
│ │ └── Person.java
│ └── resources/
│ └── application.properties
├── demo-spring-boot-3-webflux/
│ ├── .gitignore
│ ├── .java-version
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── app3/
│ │ ├── WebfluxDemoApplication.java
│ │ ├── controller/
│ │ │ ├── ExceptionTranslator.java
│ │ │ ├── TweetController.java
│ │ │ └── TweetMapper.java
│ │ ├── dto/
│ │ │ └── TweetDTO.java
│ │ ├── exception/
│ │ │ └── TweetNotFoundException.java
│ │ ├── model/
│ │ │ └── Tweet.java
│ │ ├── payload/
│ │ │ └── ErrorResponse.java
│ │ └── repository/
│ │ └── TweetRepository.java
│ └── resources/
│ ├── META-INF/
│ │ └── native-image/
│ │ └── reflect-config.json
│ └── application.yml
├── demo-spring-boot-3-webflux-functional/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── app4/
│ │ ├── AppNativeConfiguration.java
│ │ ├── WebfluxFunctionalDemoApplication.java
│ │ ├── coffee/
│ │ │ ├── Coffee.java
│ │ │ ├── CoffeeOrder.java
│ │ │ ├── CoffeeRepository.java
│ │ │ ├── CoffeeService.java
│ │ │ └── RouteConfig.java
│ │ ├── employee/
│ │ │ ├── Employee.java
│ │ │ ├── EmployeeFunctionalConfig.java
│ │ │ └── EmployeeRepository.java
│ │ └── user/
│ │ ├── RoutingConfiguration.java
│ │ ├── User.java
│ │ ├── UserHandler.java
│ │ ├── UserRepository.java
│ │ └── UserRepositoryImpl.java
│ └── resources/
│ ├── application.yml
│ ├── logback-spring.xml
│ └── schema.sql
├── demo-spring-boot-3-webmvc/
│ ├── .gitignore
│ ├── .java-version
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── app2/
│ │ ├── Application.java
│ │ ├── api/
│ │ │ ├── ApiUtil.java
│ │ │ ├── ExceptionTranslator.java
│ │ │ ├── PetApi.java
│ │ │ ├── PetApiController.java
│ │ │ ├── PetApiDelegate.java
│ │ │ ├── PetApiDelegateImpl.java
│ │ │ ├── StoreApi.java
│ │ │ ├── StoreApiController.java
│ │ │ ├── StoreApiDelegate.java
│ │ │ ├── StoreApiDelegateImpl.java
│ │ │ ├── UserApi.java
│ │ │ ├── UserApiController.java
│ │ │ ├── UserApiDelegate.java
│ │ │ └── UserApiDelegateImpl.java
│ │ ├── model/
│ │ │ ├── Body.java
│ │ │ ├── Body1.java
│ │ │ ├── Category.java
│ │ │ ├── ModelApiResponse.java
│ │ │ ├── Order.java
│ │ │ ├── Pet.java
│ │ │ ├── Tag.java
│ │ │ └── User.java
│ │ └── repository/
│ │ ├── HashMapRepository.java
│ │ ├── OrderRepository.java
│ │ ├── PetRepository.java
│ │ └── UserRepository.java
│ └── resources/
│ ├── application.yml
│ └── petstore.yml
├── demo-spring-boot-webflux-scalar/
│ ├── pom.xml
│ ├── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── app3/
│ │ │ ├── WebfluxDemoApplication.java
│ │ │ ├── controller/
│ │ │ │ ├── ExceptionTranslator.java
│ │ │ │ ├── TweetController.java
│ │ │ │ └── TweetMapper.java
│ │ │ ├── dto/
│ │ │ │ └── TweetDTO.java
│ │ │ ├── exception/
│ │ │ │ └── TweetNotFoundException.java
│ │ │ ├── model/
│ │ │ │ └── Tweet.java
│ │ │ ├── payload/
│ │ │ │ └── ErrorResponse.java
│ │ │ └── repository/
│ │ │ └── TweetRepository.java
│ │ └── resources/
│ │ └── application.yml
│ └── target/
│ └── maven-status/
│ └── maven-compiler-plugin/
│ └── compile/
│ └── default-compile/
│ ├── createdFiles.lst
│ └── inputFiles.lst
├── demo-spring-boot-webmvc-scalar/
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── services/
│ │ └── book/
│ │ ├── SpringdocApplication.java
│ │ ├── controller/
│ │ │ └── BookController.java
│ │ ├── exception/
│ │ │ ├── BookNotFoundException.java
│ │ │ └── GlobalControllerExceptionHandler.java
│ │ ├── model/
│ │ │ └── Book.java
│ │ └── repository/
│ │ └── BookRepository.java
│ └── resources/
│ ├── application.yml
│ └── logback.xml
├── demo-spring-cloud-function/
│ ├── .gitignore
│ ├── pom.xml
│ ├── spring-cloud-function-webflux/
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdoc/
│ │ │ └── demo/
│ │ │ └── services/
│ │ │ └── functions/
│ │ │ ├── PersonDTO.java
│ │ │ └── SampleApplication.java
│ │ └── resources/
│ │ └── application.yml
│ └── spring-cloud-function-webmvc/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── services/
│ │ └── functions/
│ │ ├── PersonDTO.java
│ │ └── SampleApplication.java
│ └── resources/
│ └── application.yml
├── demo-spring-data-rest/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── data/
│ │ └── rest/
│ │ ├── Account.java
│ │ ├── AccountRepository.java
│ │ ├── Customer.java
│ │ ├── CustomerRepository.java
│ │ └── SpringdocApplication.java
│ └── resources/
│ └── application.properties
├── demo-spring-hateoas/
│ ├── .gitignore
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── org/
│ │ └── springdoc/
│ │ └── demo/
│ │ └── services/
│ │ └── hateoas/
│ │ ├── DatabaseLoader.java
│ │ ├── Employee.java
│ │ ├── EmployeeController.java
│ │ ├── EmployeeRepository.java
│ │ └── SpringdocApplication.java
│ └── resources/
│ └── application.properties
├── pom.xml
└── settings.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
================================================
FILE: .gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
================================================
FILE: Jenkinsfile
================================================
#!/usr/bin/env groovy
node {
stage('checkout') {
deleteDir()
checkout scm
}
stage('Clean') {
withMaven(jdk: 'java-17', maven: 'maven-3.8.4'){
sh "mvn clean -T100"
}
}
stage('Package') {
withMaven(jdk: 'java-17', maven: 'maven-3.8.4'){
sh "mvn -Pjib package jib:build -T100"
}
}
stage("Deploy") {
build 'springdoc-openapi-demos-v2-deploy'
deleteDir()
}
}
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
[](https://ci-cd.springdoc.org:8443/view/springdoc-openapi-demos/job/springdoc-openapi-demos/job/master/)
# Spring-boot with OpenAPI Demo applications.
## [Demo Spring Boot 3 Web MVC with OpenAPI 3](https://demos.springdoc.org/demo-spring-boot-3-webmvc).
## [Demo Spring Boot 3 WebFlux with OpenAPI 3](https://demos.springdoc.org/demo-spring-boot-3-webflux/swagger-ui.html).
## [Demo Spring Boot 3 Web MVC with OpenAPI 3 and Scalar](https://demos.springdoc.org/demo-spring-boot-webmvc-scalar/scalar).
## [Demo Spring Boot 3 WebFlux with OpenAPI 3 and Scalar](https://demos.springdoc.org/demo-spring-boot-webflux-scalar/scalar).
## [Demo Spring Boot 3 WebFlux with Functional endpoints OpenAPI 3](https://demos.springdoc.org/demo-spring-boot-3-webflux-functional/swagger-ui.html).
## [Demo Spring Boot 3 and Spring Cloud Function Web MVC](https://demos.springdoc.org/spring-cloud-function-webmvc).
## [Demo Spring Boot 3 and Spring Cloud Function WebFlux](https://demos.springdoc.org/spring-cloud-function-webflux/swagger-ui.html).
## [Demo Spring Boot 3 and Spring Cloud Gateway](https://demos.springdoc.org/demo-microservices/swagger-ui.html).

# **Thank you for the support**
* Thanks a lot [JetBrains](https://www.jetbrains.com/?from=springdoc-openapi) for
supporting springdoc-openapi project.

================================================
FILE: SUPPORT.md
================================================
## Where to get help
If you think you've found a bug in The Architect Theme,
please [check the existing issues](https://github.com/pages-themes/architect/issues), and
if no one has reported the
problem, [open a new issue](https://github.com/pages-themes/architect/issues/new).
If you have a general question about the theme, how to implement it, or how to customize
it for your site you have two options:
1. [Contact GitHub Support](https://github.com/contact?form%5Bsubject%5D=GitHub%20Pages%20theme%20pages-themes/architect)
, or
2. Ask your question of the Jekyll community
on [talk.jekyllrb.com](https://talk.jekyllrb.com/)
================================================
FILE: demo-book-service/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-book-service/README.md
================================================
### Relevant Articles:
- [Documenting a Spring REST API Using OpenAPI 3.0](https://www.baeldung.com/spring-rest-openapi-documentation)
================================================
FILE: demo-book-service/pom.xml
================================================
4.0.0
org.springdoc
springdoc-openapi-demos
3.1.7-SNAPSHOT
demo-book-service
org.springframework.boot
spring-boot-starter-web
org.springdoc
springdoc-openapi-starter-webmvc-ui
com.github.therapi
therapi-runtime-javadoc
0.15.0
org.springdoc
springdoc-openapi-maven-plugin
org.springframework.boot
spring-boot-maven-plugin
org.apache.maven.plugins
maven-compiler-plugin
com.github.therapi
therapi-runtime-javadoc-scribe
0.15.0
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/SpringdocApplication.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringdocApplication {
public static void main(String[] args) {
SpringApplication.run(SpringdocApplication.class, args);
}
}
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/controller/BookController.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book.controller;
import java.util.Collection;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springdoc.demo.services.book.exception.BookNotFoundException;
import org.springdoc.demo.services.book.model.Book;
import org.springdoc.demo.services.book.repository.BookRepository;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
/**
* The type Book controller.
*/
@RestController
@RequestMapping("/api/book")
public class BookController {
/**
* The Repository.
*/
private final BookRepository repository;
/**
* Instantiates a new Book controller.
*
* @param repository the repository
*/
public BookController(BookRepository repository) {
this.repository = repository;
}
/**
* Find by id book.
*
* @param id the id
* @return the book
*/
@GetMapping("/{id}")
public Book findById(@PathVariable long id) {
return repository.findById(id)
.orElseThrow(() -> new BookNotFoundException());
}
/**
* Find books collection.
*
* @return the collection
*/
@GetMapping("/")
public Collection findBooks() {
return repository.getBooks();
}
/**
* Update book book.
*
* @param id the id
* @param book the book
* @return the book
*/
@PutMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public Book updateBook(@PathVariable("id") final String id, @RequestBody final Book book) {
return book;
}
/**
* Patch book book.
*
* @param id the id
* @param book the book
* @return the book
*/
@PatchMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public Book patchBook(@PathVariable("id") final String id, @RequestBody final Book book) {
return book;
}
/**
* Post book book.
*
* @param book the book
* @return the book
*/
@PostMapping("/")
@ResponseStatus(HttpStatus.CREATED)
public Book postBook(@NotNull @Valid @RequestBody final Book book) {
return book;
}
/**
* Head book book.
*
* @return the book
*/
@RequestMapping(method = RequestMethod.HEAD, value = "/")
@ResponseStatus(HttpStatus.OK)
public Book headBook() {
return new Book();
}
/**
* Delete book long.
*
* @param id the id
* @return the long
*/
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public long deleteBook(@PathVariable final long id) {
return id;
}
}
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/exception/BookNotFoundException.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book.exception;
@SuppressWarnings("serial")
public class BookNotFoundException extends RuntimeException {
public BookNotFoundException() {
}
}
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/exception/GlobalControllerExceptionHandler.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book.exception;
import java.time.Instant;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@RestControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ConversionFailedException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ProblemDetail handleConnversion(RuntimeException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, e.getMessage());
problemDetail.setTitle("Bookmark is Not Found");
problemDetail.setProperty("errorCategory", "Generic Exception");
problemDetail.setProperty("timestamp", Instant.now());
return problemDetail;
}
@ExceptionHandler(BookNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ProblemDetail handleBookNotFound(RuntimeException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
problemDetail.setTitle("Book Not Found");
problemDetail.setProperty("errorCategory", "Generic Exception");
problemDetail.setProperty("timestamp", Instant.now());
return problemDetail;
}
}
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/model/Book.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book.model;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
/**
* The type Book.
*/
public class Book {
/**
* The Id.
*/
private long id;
/**
* The Title.
*/
@NotBlank
@Size(min = 0, max = 20)
private String title;
/**
* The Author.
*/
@NotBlank
@Size(min = 0, max = 30)
private String author;
/**
* Gets id.
*
* @return the id
*/
public long getId() {
return id;
}
/**
* Sets id.
*
* @param id the id
*/
public void setId(long id) {
this.id = id;
}
/**
* Gets title.
*
* @return the title
*/
public String getTitle() {
return title;
}
/**
* Sets title.
*
* @param title the title
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Gets author.
*
* @return the author
*/
public String getAuthor() {
return author;
}
/**
* Sets author.
*
* @param author the author
*/
public void setAuthor(String author) {
this.author = author;
}
}
================================================
FILE: demo-book-service/src/main/java/org/springdoc/demo/services/book/repository/BookRepository.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book.repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.springdoc.demo.services.book.model.Book;
import org.springframework.stereotype.Repository;
@Repository
public class BookRepository {
private Map books = new HashMap<>();
public Optional findById(long id) {
return Optional.ofNullable(books.get(id));
}
public void add(Book book) {
books.put(book.getId(), book);
}
public Collection getBooks() {
return books.values();
}
}
================================================
FILE: demo-book-service/src/main/resources/application.yml
================================================
server:
forward-headers-strategy: framework
springdoc:
version: '@springdoc.version@'
swagger-ui:
use-root-path: true
================================================
FILE: demo-book-service/src/main/resources/logback.xml
================================================
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
================================================
FILE: demo-book-service/src/test/java/org/springdoc/demo/services/book/SwaggerUnitTest.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.services.book;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@SpringBootTest
public class SwaggerUnitTest {
@Autowired
protected MockMvc mockMvc;
@Test
public void shouldDisplaySwaggerUiPage() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/swagger-ui/index.html")).andExpect(status().isOk()).andReturn();
String contentAsString = mvcResult.getResponse().getContentAsString();
Assertions.assertTrue(contentAsString.contains("Swagger UI"));
}
}
================================================
FILE: demo-microservices/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-microservices/README.md
================================================
## sample microservices architecture using spring-cloud-gateway/eureka/spring-cloud-config
### Relevant information:
* Swagger-ui : http://localhost:8060/swagger-ui.html
* Eureka: http://localhost:8761/
================================================
FILE: demo-microservices/config-service/.gitignore
================================================
/target/
/.classpath
/.project
/.settings/
================================================
FILE: demo-microservices/config-service/pom.xml
================================================
4.0.0
config-service
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
org.springframework.cloud
spring-cloud-config-server
================================================
FILE: demo-microservices/config-service/src/main/java/org/springdoc/demo/services/config/ConfigApplication.java
================================================
package org.springdoc.demo.services.config;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ConfigApplication.class).run(args);
}
}
================================================
FILE: demo-microservices/config-service/src/main/resources/application.yml
================================================
server:
port: 8088
spring:
profiles:
active: native
================================================
FILE: demo-microservices/config-service/src/main/resources/config/department-service.yml
================================================
server:
port: 8090
forward-headers-strategy: framework
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
instance:
preferIpAddress: true
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
springdoc:
cache:
disabled: true
version: '@springdoc.version@'
================================================
FILE: demo-microservices/config-service/src/main/resources/config/discovery-service.yml
================================================
server:
port: 8761
forward-headers-strategy: framework
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
registerWithEureka: false
fetchRegistry: false
================================================
FILE: demo-microservices/config-service/src/main/resources/config/employee-service.yml
================================================
server:
port: 8092
forward-headers-strategy: framework
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
instance:
preferIpAddress: true
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
springdoc:
version: '@springdoc.version@'
cache:
disabled: true
================================================
FILE: demo-microservices/config-service/src/main/resources/config/gateway-service.yml
================================================
server:
port: 8060
forward-headers-strategy: framework
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
instance:
preferIpAddress: true
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
level:
org.springframework.cloud.gateway: TRACE
org.springframework.http.server.reactive: TRACE
spring:
cloud:
gateway:
server:
webflux:
trusted-proxies: "192\\.168\\.0\\..*|10\\.88\\.0\\..*|127\\.0\\.0\\.1|144\\.24\\.171\\.248"
httpclient:
ssl:
useInsecureTrustManager: true
discovery:
locator:
enabled: true
routes:
- id: employee-service
uri: lb://employee-service
predicates:
- Path=/employee/**, /demo-microservices/employee/**
filters:
- ContextPathRewritePath=/demo-microservices/employee/(?.*), /$\{path}
- RewritePath=/employee/(?.*), /$\{path}
- id: department-service
uri: lb://department-service
predicates:
- Path=/department/**, /demo-microservices/department/**
filters:
- ContextPathRewritePath=/demo-microservices/department/(?.*), /$\{path}
- RewritePath=/department/(?.*), /$\{path}
- id: organization-service
uri: lb://organization-service
predicates:
- Path=/organization/**, /demo-microservices/organization/**
filters:
- ContextPathRewritePath=/demo-microservices/organization/(?.*), /$\{path}
- RewritePath=/organization/(?.*), /$\{path}
- id: openapi-proxy
uri: https://demos.springdoc.org
predicates:
- Path=/demo-microservices/v3/api-docs/**
filters:
- RewritePath=/demo-microservices/v3/api-docs/(?.*), /demo-microservices/$\{path}/v3/api-docs
- id: openapi
uri: http://localhost:${server.port}
predicates:
- Path=/v3/api-docs/**
filters:
- RewritePath=/v3/api-docs/(?.*), /$\{path}/v3/api-docs
springdoc:
cache:
disabled: true
version: '@springdoc.version@'
swagger-ui:
use-root-path: true
================================================
FILE: demo-microservices/config-service/src/main/resources/config/organization-service.yml
================================================
server:
port: 8091
forward-headers-strategy: framework
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
instance:
preferIpAddress: true
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
springdoc:
version: '@springdoc.version@'
cache:
disabled: true
================================================
FILE: demo-microservices/department-service/.gitignore
================================================
/target/
/.classpath
/.project
/.settings/
================================================
FILE: demo-microservices/department-service/pom.xml
================================================
4.0.0
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
department-service
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-openfeign-core
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springdoc
springdoc-openapi-starter-webmvc-api
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/DepartmentApplication.java
================================================
package org.springdoc.demo.services.department;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springdoc.demo.services.department.model.Department;
import org.springdoc.demo.services.department.repository.DepartmentRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@OpenAPIDefinition(info =
@Info(title = "Department API", version = "${springdoc.version}", description = "Documentation Department API v1.0")
)
public class DepartmentApplication {
public static void main(String[] args) {
SpringApplication.run(DepartmentApplication.class, args);
}
@Bean
DepartmentRepository repository() {
DepartmentRepository repository = new DepartmentRepository();
repository.add(new Department(1L, "Development"));
repository.add(new Department(1L, "Operations"));
repository.add(new Department(2L, "Development"));
repository.add(new Department(2L, "Operations"));
return repository;
}
}
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/client/EmployeeClient.java
================================================
package org.springdoc.demo.services.department.client;
import java.util.List;
import org.springdoc.demo.services.department.model.Employee;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "employee-service")
public interface EmployeeClient {
@GetMapping("/department/{departmentId}")
List findByDepartment(@PathVariable("departmentId") Long departmentId);
}
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/controller/DepartmentController.java
================================================
package org.springdoc.demo.services.department.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.demo.services.department.client.EmployeeClient;
import org.springdoc.demo.services.department.model.Department;
import org.springdoc.demo.services.department.repository.DepartmentRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DepartmentController {
private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentController.class);
private DepartmentRepository repository;
private EmployeeClient employeeClient;
public DepartmentController(DepartmentRepository repository, EmployeeClient employeeClient) {
this.repository = repository;
this.employeeClient = employeeClient;
}
@PostMapping("/")
public Department add(@RequestBody Department department) {
LOGGER.info("Department add: {}", department);
return repository.add(department);
}
@GetMapping("/{id}")
public Department findById(@PathVariable("id") Long id) {
LOGGER.info("Department find: id={}", id);
return repository.findById(id);
}
@GetMapping("/")
public List findAll() {
LOGGER.info("Department find");
return repository.findAll();
}
@GetMapping("/organization/{organizationId}")
public List findByOrganization(@PathVariable("organizationId") Long organizationId) {
LOGGER.info("Department find: organizationId={}", organizationId);
return repository.findByOrganization(organizationId);
}
@GetMapping("/organization/{organizationId}/with-employees")
public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId) {
LOGGER.info("Department find: organizationId={}", organizationId);
List departments = repository.findByOrganization(organizationId);
departments.forEach(d -> d.setEmployees(employeeClient.findByDepartment(d.getId())));
return departments;
}
}
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/model/Department.java
================================================
package org.springdoc.demo.services.department.model;
import java.util.ArrayList;
import java.util.List;
public class Department {
private Long id;
private Long organizationId;
private String name;
private List employees = new ArrayList<>();
public Department() {
}
public Department(Long organizationId, String name) {
super();
this.organizationId = organizationId;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getOrganizationId() {
return organizationId;
}
public void setOrganizationId(Long organizationId) {
this.organizationId = organizationId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getEmployees() {
return employees;
}
public void setEmployees(List employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Department [id=" + id + ", organizationId=" + organizationId + ", name=" + name + "]";
}
}
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/model/Employee.java
================================================
package org.springdoc.demo.services.department.model;
public class Employee {
private Long id;
private String name;
private int age;
private String position;
public Employee() {
}
public Employee(String name, int age, String position) {
this.name = name;
this.age = age;
this.position = position;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", position=" + position + "]";
}
}
================================================
FILE: demo-microservices/department-service/src/main/java/org/springdoc/demo/services/department/repository/DepartmentRepository.java
================================================
package org.springdoc.demo.services.department.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springdoc.demo.services.department.model.Department;
public class DepartmentRepository {
private List departments = new ArrayList<>();
public Department add(Department department) {
department.setId((long) (departments.size() + 1));
departments.add(department);
return department;
}
public Department findById(Long id) {
Optional department = departments.stream().filter(a -> a.getId().equals(id)).findFirst();
if (department.isPresent())
return department.get();
else
return null;
}
public List findAll() {
return departments;
}
public List findByOrganization(Long organizationId) {
return departments.stream().filter(a -> a.getOrganizationId().equals(organizationId)).collect(Collectors.toList());
}
}
================================================
FILE: demo-microservices/department-service/src/main/resources/application.yml
================================================
spring:
application:
name: department-service
config:
import: "optional:configserver:${CONFIG_SERVER:http://localhost:8088}"
================================================
FILE: demo-microservices/discovery-service/.gitignore
================================================
/target/
/.settings/
/.classpath
/.project
================================================
FILE: demo-microservices/discovery-service/pom.xml
================================================
4.0.0
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
discovery-service
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.cloud
spring-cloud-starter-config
================================================
FILE: demo-microservices/discovery-service/src/main/java/org/springdoc/demo/services/discovery/DiscoveryApplication.java
================================================
package org.springdoc.demo.services.discovery;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(DiscoveryApplication.class).run(args);
}
}
================================================
FILE: demo-microservices/discovery-service/src/main/resources/application.yml
================================================
spring:
application:
name: discovery-service
config:
import: "optional:configserver:${CONFIG_SERVER:http://localhost:8088}"
================================================
FILE: demo-microservices/employee-service/.gitignore
================================================
/target/
/.classpath
/.project
/.settings/
================================================
FILE: demo-microservices/employee-service/pom.xml
================================================
4.0.0
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
employee-service
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springdoc
springdoc-openapi-starter-webmvc-api
================================================
FILE: demo-microservices/employee-service/src/main/java/org/springdoc/demo/services/employee/EmployeeApplication.java
================================================
package org.springdoc.demo.services.employee;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springdoc.demo.services.employee.model.Employee;
import org.springdoc.demo.services.employee.repository.EmployeeRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableDiscoveryClient
@OpenAPIDefinition(info =
@Info(title = "Employee API", version = "${springdoc.version}", description = "Documentation Employee API v1.0")
)
public class EmployeeApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeApplication.class, args);
}
@Bean
EmployeeRepository repository() {
EmployeeRepository repository = new EmployeeRepository();
repository.add(new Employee(1L, 1L, "John Smith", 34, "Analyst"));
repository.add(new Employee(1L, 1L, "Darren Hamilton", 37, "Manager"));
repository.add(new Employee(1L, 1L, "Tom Scott", 26, "Developer"));
repository.add(new Employee(1L, 2L, "Anna London", 39, "Analyst"));
repository.add(new Employee(1L, 2L, "Patrick Dempsey", 27, "Developer"));
repository.add(new Employee(2L, 3L, "Kevin Price", 38, "Developer"));
repository.add(new Employee(2L, 3L, "Ian Scott", 34, "Developer"));
repository.add(new Employee(2L, 3L, "Andrew Campton", 30, "Manager"));
repository.add(new Employee(2L, 4L, "Steve Franklin", 25, "Developer"));
repository.add(new Employee(2L, 4L, "Elisabeth Smith", 30, "Developer"));
return repository;
}
}
================================================
FILE: demo-microservices/employee-service/src/main/java/org/springdoc/demo/services/employee/controller/EmployeeController.java
================================================
package org.springdoc.demo.services.employee.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.demo.services.employee.model.Employee;
import org.springdoc.demo.services.employee.repository.EmployeeRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EmployeeController {
private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeController.class);
private EmployeeRepository repository;
public EmployeeController(EmployeeRepository repository) {
this.repository = repository;
}
@PostMapping("/")
public Employee add(@RequestBody Employee employee) {
LOGGER.info("Employee add: {}", employee);
return repository.add(employee);
}
@GetMapping("/{id}")
public Employee findById(@PathVariable("id") Long id) {
LOGGER.info("Employee find: id={}", id);
return repository.findById(id);
}
@GetMapping("/")
public List findAll() {
LOGGER.info("Employee find");
return repository.findAll();
}
@GetMapping("/department/{departmentId}")
public List findByDepartment(@PathVariable("departmentId") Long departmentId) {
LOGGER.info("Employee find: departmentId={}", departmentId);
return repository.findByDepartment(departmentId);
}
@GetMapping("/organization/{organizationId}")
public List findByOrganization(@PathVariable("organizationId") Long organizationId) {
LOGGER.info("Employee find: organizationId={}", organizationId);
return repository.findByOrganization(organizationId);
}
}
================================================
FILE: demo-microservices/employee-service/src/main/java/org/springdoc/demo/services/employee/model/Employee.java
================================================
package org.springdoc.demo.services.employee.model;
public class Employee {
private Long id;
private Long organizationId;
private Long departmentId;
private String name;
private int age;
private String position;
public Employee() {
}
public Employee(Long organizationId, Long departmentId, String name, int age, String position) {
this.organizationId = organizationId;
this.departmentId = departmentId;
this.name = name;
this.age = age;
this.position = position;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getOrganizationId() {
return organizationId;
}
public void setOrganizationId(Long organizationId) {
this.organizationId = organizationId;
}
public Long getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Long departmentId) {
this.departmentId = departmentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
public String toString() {
return "Employee [id=" + id + ", organizationId=" + organizationId + ", departmentId=" + departmentId
+ ", name=" + name + ", position=" + position + "]";
}
}
================================================
FILE: demo-microservices/employee-service/src/main/java/org/springdoc/demo/services/employee/repository/EmployeeRepository.java
================================================
package org.springdoc.demo.services.employee.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springdoc.demo.services.employee.model.Employee;
public class EmployeeRepository {
private List employees = new ArrayList<>();
public Employee add(Employee employee) {
employee.setId((long) (employees.size() + 1));
employees.add(employee);
return employee;
}
public Employee findById(Long id) {
Optional employee = employees.stream().filter(a -> a.getId().equals(id)).findFirst();
if (employee.isPresent())
return employee.get();
else
return null;
}
public List findAll() {
return employees;
}
public List findByDepartment(Long departmentId) {
return employees.stream().filter(a -> a.getDepartmentId().equals(departmentId)).collect(Collectors.toList());
}
public List findByOrganization(Long organizationId) {
return employees.stream().filter(a -> a.getOrganizationId().equals(organizationId)).collect(Collectors.toList());
}
}
================================================
FILE: demo-microservices/employee-service/src/main/resources/application.yml
================================================
spring:
application:
name: employee-service
config:
import: "optional:configserver:${CONFIG_SERVER:http://localhost:8088}"
================================================
FILE: demo-microservices/gateway-service/.gitignore
================================================
/target/
/.classpath
/.project
/.settings/
================================================
FILE: demo-microservices/gateway-service/pom.xml
================================================
4.0.0
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
gateway-service
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
org.springdoc
springdoc-openapi-starter-webflux-ui
================================================
FILE: demo-microservices/gateway-service/src/main/java/org/springdoc/demo/services/gateway/ContextPathRewritePathGatewayFilterFactory.java
================================================
package org.springdoc.demo.services.gateway;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
* @author bnasslahsen
*/
@Component
public class ContextPathRewritePathGatewayFilterFactory extends RewritePathGatewayFilterFactory {
@Override
public GatewayFilter apply(Config config) {
String replacement = config.getReplacement().replace("$\\", "$");
return (exchange, chain) -> {
ServerHttpRequest req = exchange.getRequest();
addOriginalRequestUrl(exchange, req.getURI());
String path = req.getURI().getRawPath();
String newPath = path.replaceAll(config.getRegexp(), replacement);
ServerHttpRequest request = req.mutate().path(newPath).contextPath("/").build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());
return chain.filter(exchange.mutate().request(request).build());
};
}
}
================================================
FILE: demo-microservices/gateway-service/src/main/java/org/springdoc/demo/services/gateway/GatewayApplication.java
================================================
package org.springdoc.demo.services.gateway;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties.SwaggerUrl;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import static org.springdoc.core.utils.Constants.DEFAULT_API_DOCS_URL;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
@Lazy(false)
public Set apis(RouteDefinitionLocator locator, SwaggerUiConfigProperties swaggerUiConfigProperties) {
Set urls = new HashSet<>();
List definitions = locator.getRouteDefinitions().collectList().block();
definitions.stream().filter(routeDefinition -> routeDefinition.getId().matches(".*-service")).forEach(routeDefinition -> {
String name = routeDefinition.getId().replaceAll("-service", "");
SwaggerUrl swaggerUrl = new SwaggerUrl(name, DEFAULT_API_DOCS_URL+"/" + name, null);
urls.add(swaggerUrl);
});
swaggerUiConfigProperties.setUrls(urls);
return urls;
}
}
================================================
FILE: demo-microservices/gateway-service/src/main/resources/application.yml
================================================
spring:
application:
name: gateway-service
config:
import: "optional:configserver:${CONFIG_SERVER:http://localhost:8088}"
================================================
FILE: demo-microservices/organization-service/.gitignore
================================================
/target/
/.classpath
/.project
/.settings/
================================================
FILE: demo-microservices/organization-service/pom.xml
================================================
4.0.0
org.springdoc
demo-microservices
3.1.7-SNAPSHOT
organization-service
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-openfeign-core
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springdoc
springdoc-openapi-starter-webmvc-api
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/OrganizationApplication.java
================================================
package org.springdoc.demo.services.organization;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springdoc.demo.services.organization.model.Organization;
import org.springdoc.demo.services.organization.repository.OrganizationRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@OpenAPIDefinition(info =
@Info(title = "Organization API", version = "${springdoc.version}", description = "Documentation Organization API v1.0")
)
public class OrganizationApplication {
public static void main(String[] args) {
SpringApplication.run(OrganizationApplication.class, args);
}
@Bean
OrganizationRepository repository() {
OrganizationRepository repository = new OrganizationRepository();
repository.add(new Organization("Microsoft", "Redmond, Washington, USA"));
repository.add(new Organization("Oracle", "Redwood City, California, USA"));
return repository;
}
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/client/DepartmentClient.java
================================================
package org.springdoc.demo.services.organization.client;
import java.util.List;
import org.springdoc.demo.services.organization.model.Department;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "department-service")
public interface DepartmentClient {
@GetMapping("/organization/{organizationId}")
public List findByOrganization(@PathVariable("organizationId") Long organizationId);
@GetMapping("/organization/{organizationId}/with-employees")
public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId);
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/client/EmployeeClient.java
================================================
package org.springdoc.demo.services.organization.client;
import java.util.List;
import org.springdoc.demo.services.organization.model.Employee;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "employee-service")
public interface EmployeeClient {
@GetMapping("/organization/{organizationId}")
List findByOrganization(@PathVariable("organizationId") Long organizationId);
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/controller/OrganizationController.java
================================================
package org.springdoc.demo.services.organization.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.demo.services.organization.client.DepartmentClient;
import org.springdoc.demo.services.organization.client.EmployeeClient;
import org.springdoc.demo.services.organization.model.Organization;
import org.springdoc.demo.services.organization.repository.OrganizationRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrganizationController {
private static final Logger LOGGER = LoggerFactory.getLogger(OrganizationController.class);
private OrganizationRepository repository;
private DepartmentClient departmentClient;
private EmployeeClient employeeClient;
public OrganizationController(OrganizationRepository repository, DepartmentClient departmentClient, EmployeeClient employeeClient) {
this.repository = repository;
this.departmentClient = departmentClient;
this.employeeClient = employeeClient;
}
@PostMapping
public Organization add(@RequestBody Organization organization) {
LOGGER.info("Organization add: {}", organization);
return repository.add(organization);
}
@GetMapping
public List findAll() {
LOGGER.info("Organization find");
return repository.findAll();
}
@GetMapping("/{id}")
public Organization findById(@PathVariable("id") Long id) {
LOGGER.info("Organization find: id={}", id);
return repository.findById(id);
}
@GetMapping("/{id}/with-departments")
public Organization findByIdWithDepartments(@PathVariable("id") Long id) {
LOGGER.info("Organization find: id={}", id);
Organization organization = repository.findById(id);
organization.setDepartments(departmentClient.findByOrganization(organization.getId()));
return organization;
}
@GetMapping("/{id}/with-departments-and-employees")
public Organization findByIdWithDepartmentsAndEmployees(@PathVariable("id") Long id) {
LOGGER.info("Organization find: id={}", id);
Organization organization = repository.findById(id);
organization.setDepartments(departmentClient.findByOrganizationWithEmployees(organization.getId()));
return organization;
}
@GetMapping("/{id}/with-employees")
public Organization findByIdWithEmployees(@PathVariable("id") Long id) {
LOGGER.info("Organization find: id={}", id);
Organization organization = repository.findById(id);
organization.setEmployees(employeeClient.findByOrganization(organization.getId()));
return organization;
}
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/model/Department.java
================================================
package org.springdoc.demo.services.organization.model;
import java.util.ArrayList;
import java.util.List;
public class Department {
private Long id;
private String name;
private List employees = new ArrayList<>();
public Department() {
}
public Department(String name) {
super();
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getEmployees() {
return employees;
}
public void setEmployees(List employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/model/Employee.java
================================================
package org.springdoc.demo.services.organization.model;
public class Employee {
private Long id;
private String name;
private int age;
private String position;
public Employee() {
}
public Employee(String name, int age, String position) {
this.name = name;
this.age = age;
this.position = position;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", position=" + position + "]";
}
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/model/Organization.java
================================================
package org.springdoc.demo.services.organization.model;
import java.util.ArrayList;
import java.util.List;
public class Organization {
private Long id;
private String name;
private String address;
private List departments = new ArrayList<>();
private List employees = new ArrayList<>();
public Organization() {
}
public Organization(String name, String address) {
this.name = name;
this.address = address;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List getDepartments() {
return departments;
}
public void setDepartments(List departments) {
this.departments = departments;
}
public List getEmployees() {
return employees;
}
public void setEmployees(List employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Organization [id=" + id + ", name=" + name + ", address=" + address + "]";
}
}
================================================
FILE: demo-microservices/organization-service/src/main/java/org/springdoc/demo/services/organization/repository/OrganizationRepository.java
================================================
package org.springdoc.demo.services.organization.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springdoc.demo.services.organization.model.Organization;
public class OrganizationRepository {
private List organizations = new ArrayList<>();
public Organization add(Organization organization) {
organization.setId((long) (organizations.size() + 1));
organizations.add(organization);
return organization;
}
public Organization findById(Long id) {
Optional organization = organizations.stream().filter(a -> a.getId().equals(id)).findFirst();
if (organization.isPresent())
return organization.get();
else
return null;
}
public List findAll() {
return organizations;
}
}
================================================
FILE: demo-microservices/organization-service/src/main/resources/application.yml
================================================
spring:
application:
name: organization-service
config:
import: "optional:configserver:${CONFIG_SERVER:http://localhost:8088}"
================================================
FILE: demo-microservices/pom.xml
================================================
springdoc-openapi-demos
org.springdoc
3.1.7-SNAPSHOT
pom
4.0.0
demo-microservices
config-service
discovery-service
employee-service
department-service
organization-service
gateway-service
================================================
FILE: demo-oauth2/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-oauth2/README.md
================================================
## Spring Security OAuth - New Stack
### Relevant information:
1. `oauth-authorization-server` is a Keycloak Authorization Server wrapped as a Spring
Boot application
2. There is one OAuth Client registered in the Authorization Server:
1. Client Id: newClient
2. Client secret: newClientSecret
3. Redirect Uris:
- http://127.0.0.1:8081/resource-server/swagger-ui/oauth2-redirect.html
- http://127.0.0.1:8082/resource-server/swagger-ui/oauth2-redirect.html
3. There is a test user registered in the Authorization Server:
- josh@test.com / 123
4. `oauth-resource-server-webmvc` is a Spring Boot WebMVC based RESTFul API, acting as a
backend Application
swagger-ui: http://127.0.0.1:8081/resource-server/swagger-ui.html
5. `oauth-resource-server-webflux` is a Spring Boot WebFlux based RESTFul API, acting as a
backend Application
swagger-ui: http://127.0.0.1:8082/resource-server/swagger-ui.html
================================================
FILE: demo-oauth2/oauth-authorization-server/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-oauth2/oauth-authorization-server/pom.xml
================================================
4.0.0
org.springdoc
demo-oauth2
3.1.7-SNAPSHOT
oauth-authorization-server
org.springframework.security
spring-security-oauth2-authorization-server
org.springdoc
springdoc-openapi-starter-webmvc-ui
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
com.h2database
h2
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/java/org/springdoc/demo/auth/AuthorizationServerApp.java
================================================
package org.springdoc.demo.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AuthorizationServerApp {
public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApp.class, args);
}
}
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/java/org/springdoc/demo/auth/DefaultSecurityConfig.java
================================================
package org.springdoc.demo.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz ->
authz.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.anyRequest().authenticated()
)
.cors(withDefaults())
.formLogin(withDefaults());
return http.build();
}
@Bean
UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("josh@test.com")
.password("123")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/java/org/springdoc/demo/auth/Jwks.java
================================================
package org.springdoc.demo.auth;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import com.nimbusds.jose.jwk.RSAKey;
public final class Jwks {
private Jwks() {
}
public static RSAKey generateRsa() {
KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
}
}
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/java/org/springdoc/demo/auth/KeyGeneratorUtils.java
================================================
package org.springdoc.demo.auth;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
final class KeyGeneratorUtils {
private KeyGeneratorUtils() {
}
static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
static KeyPair generateEcKey() {
EllipticCurve ellipticCurve = new EllipticCurve(
new ECFieldFp(
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")),
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
ECPoint ecPoint = new ECPoint(
new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
ECParameterSpec ecParameterSpec = new ECParameterSpec(
ellipticCurve,
ecPoint,
new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"),
1);
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(ecParameterSpec);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/java/org/springdoc/demo/auth/SecurityConfig.java
================================================
package org.springdoc.demo.auth;
import java.util.List;
import java.util.UUID;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration(proxyBeanMethods = false)
public class SecurityConfig {
private static final List ALLOWED_HEADERS = List.of("Access-Control-Allow-Origin", "x-requested-with");
private static final List ALLOWED_METHODS = List.of("POST");
private static final List ALLOWED_ALL = List.of("http://127.0.0.1:8081", "http://127.0.0.1:8082", "http://144.24.171.248:8095","http://144.24.171.248:8096", "https://demos.springdoc.org");
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ALLOWED_ALL);
configuration.setAllowedMethods(ALLOWED_METHODS);
configuration.setAllowedHeaders(ALLOWED_HEADERS);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());
http
.cors(withDefaults())
.exceptionHandling(exceptions ->
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("newClient")
.clientSecret("{noop}newClientSecret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8081/resource-server/swagger-ui/oauth2-redirect.html")
.redirectUri("http://127.0.0.1:8082/resource-server/swagger-ui/oauth2-redirect.html")
.redirectUri("http://144.24.171.248:8095/resource-server/swagger-ui/oauth2-redirect.html")
.redirectUri("http://144.24.171.248:8096/resource-server/swagger-ui/oauth2-redirect.html")
.redirectUri("https://demos.springdoc.org/oauth-resource-server-webmvc/resource-server/swagger-ui/oauth2-redirect.html")
.redirectUri("https://demos.springdoc.org/oauth-resource-server-webflux/resource-server/swagger-ui/oauth2-redirect.html")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("springdoc.read")
.scope("springdoc.write")
.build();
// Save registered client in db as if in-memory
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
}
@Bean
public JWKSource jwkSource() {
RSAKey rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder(JWKSource jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
@Bean
public EmbeddedDatabase embeddedDatabase() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
.build();
}
}
================================================
FILE: demo-oauth2/oauth-authorization-server/src/main/resources/application.yml
================================================
spring:
datasource:
username: sa
url: jdbc:h2:./data/keycloak;DB_CLOSE_ON_EXIT=FALSE
hikari:
maximum-pool-size: 25
minimum-idle: 1
server:
forward-headers-strategy: native
port: 8083
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
org.springframework.security.oauth2: INFO
org.springframework.boot.autoconfigure: INFO
springdoc:
show-oauth2-endpoints: true
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/pom.xml
================================================
4.0.0
org.springdoc
demo-oauth2
3.1.7-SNAPSHOT
oauth-resource-server-webflux
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-starter-oauth2-resource-server
org.springframework.boot
spring-boot-starter-data-jpa
com.h2database
h2
org.springdoc
springdoc-openapi-starter-webflux-ui
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/ResourceServerApp.java
================================================
package org.springdoc.demo.resource;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ResourceServerApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(ResourceServerApp.class, args);
}
@Bean
public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) {
return new OpenAPI()
.components(new Components())
.info(new Info().title("Foo API").version(appVersion)
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/config/OpenApiConfig.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.resource.config;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.security.OAuthFlow;
import io.swagger.v3.oas.annotations.security.OAuthFlows;
import io.swagger.v3.oas.annotations.security.OAuthScope;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
@OpenAPIDefinition(info = @Info(title = "My App",
description = "Some long and useful description", version = "v1"))
@SecurityScheme(name = "security_auth", type = SecuritySchemeType.OAUTH2,
flows = @OAuthFlows(authorizationCode = @OAuthFlow(
authorizationUrl = "${springdoc.oAuthFlow.authorizationUrl}"
, tokenUrl = "${springdoc.oAuthFlow.tokenUrl}", scopes = {
@OAuthScope(name = "springdoc.read", description = "read scope"),
@OAuthScope(name = "springdoc.write", description = "write scope") })))
public class OpenApiConfig {}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/config/SecurityConfig.java
================================================
package org.springdoc.demo.resource.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityWebFilterChain configure(ServerHttpSecurity http) {
http
.authorizeExchange().pathMatchers("/v3/api-docs/**", "/swagger-ui/**", "/webjars/**", "/swagger-ui.html").permitAll()
.pathMatchers(HttpMethod.GET, "/user/info", "/api/foos/**")
.hasAuthority("SCOPE_springdoc.read")
.pathMatchers(HttpMethod.POST, "/api/foos")
.hasAuthority("SCOPE_springdoc.write")
.anyExchange().authenticated().and().oauth2ResourceServer().jwt();
return http.build();
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/model/Foo.java
================================================
package org.springdoc.demo.resource.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
protected Foo() {
}
public Foo(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Foo [id=" + id + ", name=" + name + "]";
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/repository/IFooRepository.java
================================================
package org.springdoc.demo.resource.repository;
import org.springdoc.demo.resource.model.Foo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface IFooRepository extends PagingAndSortingRepository, CrudRepository {
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/service/IFooService.java
================================================
package org.springdoc.demo.resource.service;
import java.util.Optional;
import org.springdoc.demo.resource.model.Foo;
public interface IFooService {
Optional findById(Long id);
Foo save(Foo foo);
Iterable findAll();
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/service/impl/FooServiceImpl.java
================================================
package org.springdoc.demo.resource.service.impl;
import java.util.Optional;
import org.springdoc.demo.resource.model.Foo;
import org.springdoc.demo.resource.repository.IFooRepository;
import org.springdoc.demo.resource.service.IFooService;
import org.springframework.stereotype.Service;
@Service
public class FooServiceImpl implements IFooService {
private IFooRepository fooRepository;
public FooServiceImpl(IFooRepository fooRepository) {
this.fooRepository = fooRepository;
}
@Override
public Optional findById(Long id) {
return fooRepository.findById(id);
}
@Override
public Foo save(Foo foo) {
return fooRepository.save(foo);
}
@Override
public Iterable findAll() {
return fooRepository.findAll();
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/web/controller/FooController.java
================================================
package org.springdoc.demo.resource.web.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springdoc.demo.resource.model.Foo;
import org.springdoc.demo.resource.service.IFooService;
import org.springdoc.demo.resource.web.dto.FooDTO;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
@RestController
@RequestMapping(value = "/api/foos")
@SecurityRequirement(name = "security_auth")
public class FooController {
private IFooService fooService;
public FooController(IFooService fooService) {
this.fooService = fooService;
}
@GetMapping(value = "/{id}")
public FooDTO findOne(@PathVariable Long id) {
Foo entity = fooService.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
return convertToDto(entity);
}
@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public void create(@RequestBody FooDTO newFoo) {
Foo entity = convertToEntity(newFoo);
this.fooService.save(entity);
}
@GetMapping
public Collection findAll() {
Iterable foos = this.fooService.findAll();
List fooDtos = new ArrayList<>();
foos.forEach(p -> fooDtos.add(convertToDto(p)));
return fooDtos;
}
@PutMapping("/{id}")
public FooDTO updateFoo(@PathVariable("id") Long id, @RequestBody FooDTO updatedFoo) {
Foo fooEntity = convertToEntity(updatedFoo);
return this.convertToDto(this.fooService.save(fooEntity));
}
protected FooDTO convertToDto(Foo entity) {
FooDTO dto = new FooDTO(entity.getId(), entity.getName());
return dto;
}
protected Foo convertToEntity(FooDTO dto) {
Foo foo = new Foo(dto.getName());
if (!StringUtils.isEmpty(dto.getId())) {
foo.setId(dto.getId());
}
return foo;
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/web/controller/UserInfoController.java
================================================
package org.springdoc.demo.resource.web.controller;
import java.util.Collections;
import java.util.Map;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserInfoController {
@GetMapping("/user/info")
@SecurityRequirement(name = "security_auth")
public Map getUserInfo(@AuthenticationPrincipal Jwt principal) {
return Collections.singletonMap("user_name", principal.getClaimAsString("sub"));
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/java/org/springdoc/demo/resource/web/dto/FooDTO.java
================================================
package org.springdoc.demo.resource.web.dto;
public class FooDTO {
private long id;
private String name;
public FooDTO() {
super();
}
public FooDTO(final long id, final String name) {
super();
this.id = id;
this.name = name;
}
//
public long getId() {
return id;
}
public void setId(final long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/resources/application.yml
================================================
server:
forward-headers-strategy: framework
port: 8082
####### resource server configuration properties
spring:
webflux:
base-path: /resource-server
jpa:
defer-datasource-initialization: true
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${OAUTH2_SERVER:http://127.0.0.1:8083}
springdoc:
version: '@springdoc.version@'
swagger-ui:
oauth:
clientId: newClient
clientSecret: newClientSecret
oAuthFlow:
authorizationUrl: ${OAUTH2_SERVER:http://127.0.0.1:8083}/oauth2/authorize
tokenUrl: ${OAUTH2_SERVER:http://127.0.0.1:8083}/oauth2/token
================================================
FILE: demo-oauth2/oauth-resource-server-webflux/src/main/resources/data.sql
================================================
INSERT INTO Foo(id, name)
VALUES (1, 'Foo 1');
INSERT INTO Foo(id, name)
VALUES (2, 'Foo 2');
INSERT INTO Foo(id, name)
VALUES (3, 'Foo 3');
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/pom.xml
================================================
4.0.0
org.springdoc
demo-oauth2
3.1.7-SNAPSHOT
oauth-resource-server-webmvc
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-oauth2-resource-server
org.springframework.boot
spring-boot-starter-data-jpa
com.h2database
h2
org.springdoc
springdoc-openapi-starter-webmvc-ui
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/ResourceServerApp.java
================================================
package org.springdoc.demo.resource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ResourceServerApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(ResourceServerApp.class, args);
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/config/OpenApiConfig.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.resource.config;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.security.OAuthFlow;
import io.swagger.v3.oas.annotations.security.OAuthFlows;
import io.swagger.v3.oas.annotations.security.OAuthScope;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
@OpenAPIDefinition(info = @Info(title = "Foo API",
description = "Foo description", version = "v1"))
@SecurityScheme(name = "security_auth", type = SecuritySchemeType.OAUTH2,
flows = @OAuthFlows(authorizationCode = @OAuthFlow(
authorizationUrl = "${springdoc.oAuthFlow.authorizationUrl}"
, tokenUrl = "${springdoc.oAuthFlow.tokenUrl}", scopes = {
@OAuthScope(name = "springdoc.read", description = "read scope"),
@OAuthScope(name = "springdoc.write", description = "write scope") })))
public class OpenApiConfig {}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/config/SecurityConfig.java
================================================
package org.springdoc.demo.resource.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.requestMatchers(HttpMethod.GET, "/user/info", "/api/foos/**")
.hasAuthority("SCOPE_springdoc.read")
.requestMatchers(HttpMethod.POST, "/api/foos")
.hasAuthority("SCOPE_springdoc.write")
.anyRequest()
.authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/model/Foo.java
================================================
package org.springdoc.demo.resource.model;
import java.util.UUID;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
private String name;
protected Foo() {
}
public Foo(String name) {
this.name = name;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Foo [id=" + id + ", name=" + name + "]";
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/repository/IFooRepository.java
================================================
package org.springdoc.demo.resource.repository;
import org.springdoc.demo.resource.model.Foo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface IFooRepository extends PagingAndSortingRepository, CrudRepository {
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/service/IFooService.java
================================================
package org.springdoc.demo.resource.service;
import java.util.Optional;
import org.springdoc.demo.resource.model.Foo;
public interface IFooService {
Optional findById(Long id);
Foo save(Foo foo);
Iterable findAll();
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/service/impl/FooServiceImpl.java
================================================
package org.springdoc.demo.resource.service.impl;
import java.util.Optional;
import org.springdoc.demo.resource.model.Foo;
import org.springdoc.demo.resource.repository.IFooRepository;
import org.springdoc.demo.resource.service.IFooService;
import org.springframework.stereotype.Service;
@Service
public class FooServiceImpl implements IFooService {
private IFooRepository fooRepository;
public FooServiceImpl(IFooRepository fooRepository) {
this.fooRepository = fooRepository;
}
@Override
public Optional findById(Long id) {
return fooRepository.findById(id);
}
@Override
public Foo save(Foo foo) {
return fooRepository.save(foo);
}
@Override
public Iterable findAll() {
return fooRepository.findAll();
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/web/controller/FooController.java
================================================
package org.springdoc.demo.resource.web.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springdoc.demo.resource.model.Foo;
import org.springdoc.demo.resource.service.IFooService;
import org.springdoc.demo.resource.web.dto.FooDTO;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
@RestController
@RequestMapping(value = "/api/foos")
@SecurityRequirement(name = "security_auth")
public class FooController {
private IFooService fooService;
public FooController(IFooService fooService) {
this.fooService = fooService;
}
@GetMapping(value = "/{id}")
public FooDTO findOne(@PathVariable Long id) {
Foo entity = fooService.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
return convertToDto(entity);
}
@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public void create(@RequestBody FooDTO newFoo) {
Foo entity = convertToEntity(newFoo);
this.fooService.save(entity);
}
@GetMapping
public Collection findAll() {
Iterable foos = this.fooService.findAll();
List fooDtos = new ArrayList<>();
foos.forEach(p -> fooDtos.add(convertToDto(p)));
return fooDtos;
}
@PutMapping("/{id}")
public FooDTO updateFoo(@PathVariable("id") Long id, @RequestBody FooDTO updatedFoo) {
Foo fooEntity = convertToEntity(updatedFoo);
return this.convertToDto(this.fooService.save(fooEntity));
}
protected FooDTO convertToDto(Foo entity) {
FooDTO dto = new FooDTO(entity.getId(), entity.getName());
return dto;
}
protected Foo convertToEntity(FooDTO dto) {
Foo foo = new Foo(dto.getName());
if (!StringUtils.isEmpty(dto.getId())) {
foo.setId(dto.getId());
}
return foo;
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/web/controller/UserInfoController.java
================================================
package org.springdoc.demo.resource.web.controller;
import java.util.Collections;
import java.util.Map;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserInfoController {
@GetMapping("/user/info")
@SecurityRequirement(name = "security_auth")
public Map getUserInfo(@AuthenticationPrincipal Jwt principal) {
return Collections.singletonMap("user_name", principal.getClaimAsString("sub"));
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/java/org/springdoc/demo/resource/web/dto/FooDTO.java
================================================
package org.springdoc.demo.resource.web.dto;
import java.util.UUID;
public class FooDTO {
private UUID id;
private String name;
public FooDTO() {
super();
}
public FooDTO(final UUID id, final String name) {
super();
this.id = id;
this.name = name;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/resources/application.yml
================================================
server:
port: 8081
forward-headers-strategy: framework
servlet:
context-path: /resource-server
####### resource server configuration properties
spring:
jpa:
defer-datasource-initialization: true
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${OAUTH2_SERVER:http://127.0.0.1:8083}
springdoc:
version: '@springdoc.version@'
swagger-ui:
oauth:
clientId: newClient
clientSecret: newClientSecret
oAuthFlow:
authorizationUrl: ${OAUTH2_SERVER:http://127.0.0.1:8083}/oauth2/authorize
tokenUrl: ${OAUTH2_SERVER:http://127.0.0.1:8083}/oauth2/token
================================================
FILE: demo-oauth2/oauth-resource-server-webmvc/src/main/resources/data.sql
================================================
INSERT INTO Foo(id, name)
VALUES ('dc58c780-a571-437e-85e2-9be232c5cd80', 'Foo 1');
INSERT INTO Foo(id, name)
VALUES ('dc58c780-a571-437e-85e2-9be232c5cd84', 'Foo 2');
INSERT INTO Foo(id, name)
VALUES ('dc58c780-a571-437e-85e2-9be232c5cd83', 'Foo 3');
================================================
FILE: demo-oauth2/pom.xml
================================================
4.0.0
springdoc-openapi-demos
org.springdoc
3.1.7-SNAPSHOT
pom
demo-oauth2
oauth-authorization-server
oauth-resource-server-webflux
oauth-resource-server-webmvc
org.apache.maven.plugins
maven-surefire-plugin
**/*LiveTest.java
================================================
FILE: demo-person-service/.gitattributes
================================================
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
================================================
FILE: demo-person-service/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-person-service/README.md
================================================
### Relevant Articles:
- [DZone Part1](https://dzone.com/articles/openapi-3-documentation-with-spring-boot)
- [DZone Part2](https://dzone.com/articles/doing-more-with-springdoc-openapi)
### Building native image with GraalVM
To create a `native image`, Run the following command
```sh
mvn -Pnative clean native:compile
```
================================================
FILE: demo-person-service/pom.xml
================================================
4.0.0
springdoc-openapi-demos
org.springdoc
3.1.7-SNAPSHOT
Demo project for Spring Boot with openapi 3 documentation
demo-person-service
org.springframework.boot
spring-boot-starter-web
org.springdoc
springdoc-openapi-starter-webmvc-ui
org.javamoney.moneta
moneta-core
1.3
org.zalando
jackson-datatype-money
1.1.1
org.springdoc
springdoc-openapi-maven-plugin
org.springframework.boot
spring-boot-maven-plugin
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/SampleApplication.java
================================================
package org.springdoc.demo.services.person;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication()
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
@Bean
public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) {
return new OpenAPI()
.components(new Components().addSecuritySchemes("basicScheme",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")))
.info(new Info().title("Person API").version(appVersion)
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/config/SampleConfig.java
================================================
package org.springdoc.demo.services.person.config;
import javax.money.MonetaryAmount;
import jakarta.annotation.PostConstruct;
import org.javamoney.moneta.Money;
import org.zalando.jackson.datatype.money.MoneyModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.springdoc.core.utils.SpringDocUtils.getConfig;
@Configuration
public class SampleConfig {
@PostConstruct
public void initConfig() {
getConfig().replaceWithClass(MonetaryAmount.class,
org.springdoc.core.converters.models.MonetaryAmount.class);
}
@Bean
public MoneyModule moneyModule() {
return new MoneyModule().withMonetaryAmount(Money::of);
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/controller/PersonController.java
================================================
package org.springdoc.demo.services.person.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import org.springdoc.demo.services.person.model.Person;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PersonController {
private Random ran = new Random();
@PostMapping("/persons")
public Person person(@Valid @RequestBody Person person) {
int nxt = ran.nextInt(10);
if (nxt >= 5) {
throw new RuntimeException("Breaking logic");
}
return person;
}
@GetMapping(path = "/persons")
public List findByLastName(@RequestParam @NotBlank @Size(max = 10) String lastName) {
List hardCoded = new ArrayList<>();
Person person = new Person();
person.setAge(20);
person.setEmail1("abc1@abc.com");
person.setEmail2("abc@abc.com");
person.setFirstName("Somefirstname");
person.setLastName(lastName);
person.setId(1);
hardCoded.add(person);
return hardCoded;
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/exceptions/ErrorMessage.java
================================================
package org.springdoc.demo.services.person.exceptions;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ErrorMessage {
private List errors;
public ErrorMessage() {
}
public ErrorMessage(List errors) {
this.errors = errors;
}
public ErrorMessage(String error) {
this(Collections.singletonList(error));
}
public ErrorMessage(String... errors) {
this(Arrays.asList(errors));
}
public List getErrors() {
return errors;
}
public void setErrors(List errors) {
this.errors = errors;
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/exceptions/GlobalControllerAdvice.java
================================================
package org.springdoc.demo.services.person.exceptions;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.demo.services.person.controller.PersonController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice(assignableTypes = PersonController.class)
public class GlobalControllerAdvice {
/**
* Note use base class if you wish to leverage its handling.
* Some code will need changing.
*/
private static final Logger logger = LoggerFactory.getLogger(GlobalControllerAdvice.class);
@ExceptionHandler(Throwable.class)
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity problem(final Throwable e) {
String message = e.getMessage();
//might actually prefer to use a geeric mesasge
message = "Problem occured";
UUID uuid = UUID.randomUUID();
String logRef = uuid.toString();
logger.error("logRef=" + logRef, message, e);
return new ResponseEntity(new Problem(logRef, message), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex
) {
List fieldErrors = ex.getBindingResult().getFieldErrors();
List globalErrors = ex.getBindingResult().getGlobalErrors();
List errors = new ArrayList<>(fieldErrors.size() + globalErrors.size());
String error;
for (FieldError fieldError : fieldErrors) {
error = fieldError.getField() + ", " + fieldError.getDefaultMessage();
errors.add(error);
}
for (ObjectError objectError : globalErrors) {
error = objectError.getObjectName() + ", " + objectError.getDefaultMessage();
errors.add(error);
}
ErrorMessage errorMessage = new ErrorMessage(errors);
//Object result=ex.getBindingResult();//instead of above can allso pass the more detailed bindingResult
return new ResponseEntity(errorMessage, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ResponseEntity handleConstraintViolatedException(ConstraintViolationException ex
) {
Set> constraintViolations = ex.getConstraintViolations();
List errors = new ArrayList<>(constraintViolations.size());
String error;
for (ConstraintViolation constraintViolation : constraintViolations) {
error = constraintViolation.getMessage();
errors.add(error);
}
ErrorMessage errorMessage = new ErrorMessage(errors);
return new ResponseEntity(errorMessage, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ResponseEntity handleMissingServletRequestParameterException(MissingServletRequestParameterException ex
) {
List errors = new ArrayList<>();
String error = ex.getParameterName() + ", " + ex.getMessage();
errors.add(error);
ErrorMessage errorMessage = new ErrorMessage(errors);
return new ResponseEntity(errorMessage, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseStatus(code = HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public ResponseEntity handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex
) {
String unsupported = "Unsupported content type: " + ex.getContentType();
String supported = "Supported content types: " + MediaType.toString(ex.getSupportedMediaTypes());
ErrorMessage errorMessage = new ErrorMessage(unsupported, supported);
return new ResponseEntity(errorMessage, HttpStatus.UNSUPPORTED_MEDIA_TYPE);
}
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
ErrorMessage errorMessage = new ErrorMessage(ex.getMessage());
return new ResponseEntity(errorMessage, HttpStatus.BAD_REQUEST);
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/exceptions/Problem.java
================================================
package org.springdoc.demo.services.person.exceptions;
public class Problem {
private String logRef;
private String message;
public Problem(String logRef, String message) {
super();
this.logRef = logRef;
this.message = message;
}
public Problem() {
super();
}
public String getLogRef() {
return logRef;
}
public void setLogRef(String logRef) {
this.logRef = logRef;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
================================================
FILE: demo-person-service/src/main/java/org/springdoc/demo/services/person/model/Person.java
================================================
package org.springdoc.demo.services.person.model;
import javax.money.MonetaryAmount;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
public class Person {
private long id;
@Size(min = 2, max = 50)
@NotBlank
private String firstName;
@Size(min = 2, max = 50)
@NotBlank
private String lastName;
@Pattern(regexp = ".+@.+\\..+", message = "Please provide a valid email address")
private String email1;
@Email
private String email2;
@Min(18)
@Max(30)
private int age;
@JsonProperty
private MonetaryAmount worth;
public MonetaryAmount getWorth() {
return worth;
}
public void setWorth(MonetaryAmount worth) {
this.worth = worth;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail1() {
return email1;
}
public void setEmail1(String email1) {
this.email1 = email1;
}
public String getEmail2() {
return email2;
}
public void setEmail2(String email2) {
this.email2 = email2;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
================================================
FILE: demo-person-service/src/main/resources/application.properties
================================================
springdoc.version=@springdoc.version@
springdoc.swagger-ui.use-root-path=true
server.forward-headers-strategy=framework
================================================
FILE: demo-spring-boot-3-webflux/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-spring-boot-3-webflux/.java-version
================================================
graalvm64-17.0.5
================================================
FILE: demo-spring-boot-3-webflux/README.md
================================================
# springdoc-openapi demo with spring-boot-2 web-flux
## Building application
### Pre-requisites
- JDK 8+
- maven 3
- docker CLI
### Option 1: Building Executable JAR
To create an `executable jar`, simply run:
```sh
mvn clean package
```
### Option 2: Building a non-native OCI Images
To create a non-native OCI docker image, simply run:
```sh
mvn clean spring-boot:build-image
```
### Option 3: Building native image with GraalVM
To create a `native image`, Run the following command
```sh
mvn -Pnative clean native:compile
```
## Running the native application
To run the demo using docker, invoke the following:
```sh
docker run --rm -p 8080:8082 springdoc-openapi-spring-boot-2-webflux:3.1.6-SNAPSHOT
```
================================================
FILE: demo-spring-boot-3-webflux/pom.xml
================================================
4.0.0
org.springdoc
springdoc-openapi-demos
3.1.7-SNAPSHOT
demo-spring-boot-3-webflux
org.springdoc
springdoc-openapi-starter-webflux-ui
org.springframework.boot
spring-boot-starter-webflux
io.projectreactor
reactor-test
test
org.springframework.boot
spring-boot-starter-data-mongodb-reactive
org.springframework.boot
spring-boot-configuration-processor
true
org.springdoc
springdoc-openapi-maven-plugin
http://localhost:8080/v3/api-docs.yaml
openapi.yaml
integration-test
generate
org.springframework.boot
spring-boot-maven-plugin
-Dspring.application.admin.enabled=true
start
stop
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/WebfluxDemoApplication.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
@SpringBootApplication
@EnableReactiveMongoRepositories
public class WebfluxDemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebfluxDemoApplication.class, args);
}
@Bean
public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) {
return new OpenAPI()
.components(new Components().addSecuritySchemes("basicScheme",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")))
.info(new Info().title("Tweet API").version(appVersion)
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
@Bean
public GroupedOpenApi storeOpenApi() {
String[] paths = { "/tweets/**" };
return GroupedOpenApi.builder().group("tweets").pathsToMatch(paths)
.build();
}
@Bean
public GroupedOpenApi userOpenApi() {
String[] paths = { "/stream/**" };
String[] packagedToMatch = { "org.springdoc.demo.app3" };
return GroupedOpenApi.builder().group("x-stream").pathsToMatch(paths).packagesToScan(packagedToMatch)
.build();
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/controller/ExceptionTranslator.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.controller;
import org.springdoc.demo.app3.exception.TweetNotFoundException;
import org.springdoc.demo.app3.payload.ErrorResponse;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ExceptionTranslator {
@SuppressWarnings("rawtypes")
@ExceptionHandler(DuplicateKeyException.class)
@ResponseStatus(HttpStatus.CONFLICT)
public ResponseEntity handleDuplicateKeyException(DuplicateKeyException ex) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ErrorResponse("A Tweet with the same text already exists"));
}
@SuppressWarnings("rawtypes")
@ExceptionHandler(TweetNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity handleTweetNotFoundException(TweetNotFoundException ex) {
return ResponseEntity.notFound().build();
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/controller/TweetController.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import org.springdoc.demo.app3.dto.TweetDTO;
import org.springdoc.demo.app3.model.Tweet;
import org.springdoc.demo.app3.repository.TweetRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by bnasslahsen
*/
@RestController
public class TweetController {
private final TweetRepository tweetRepository;
private final TweetMapper tweetMapper;
public TweetController(TweetRepository tweetRepository, TweetMapper tweetMapper) {
this.tweetRepository = tweetRepository;
this.tweetMapper = tweetMapper;
}
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "get All Tweets") })
@GetMapping("/tweets")
public Flux getAllTweets() {
Flux tweet = tweetRepository.findAll();
return tweetMapper.toDTO(tweet);
}
@PostMapping("/tweets")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "create Tweets") })
public Mono createTweets(@Valid @RequestBody TweetDTO tweetDTO) {
return tweetRepository.save(tweetMapper.toEntity(tweetDTO)).map(tweetMapper::toDTO);
}
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "get Tweet By Id"),
@ApiResponse(responseCode = "404", description = "tweet not found") })
@GetMapping("/tweets/{id}")
public Mono> getTweetById(@PathVariable(value = "id") String tweetId) {
return tweetRepository.findById(tweetId).map(savedTweet -> ResponseEntity.ok(tweetMapper.toDTO(savedTweet)))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "update Tweet"),
@ApiResponse(responseCode = "404", description = "tweet not found") })
@PutMapping("/tweets/{id}")
public Mono> updateTweet(@PathVariable(value = "id") String tweetId,
@Valid @RequestBody TweetDTO tweetDTO) {
return tweetRepository.findById(tweetId).flatMap(existingTweet -> {
existingTweet.setText(tweetMapper.toEntity(tweetDTO).getText());
return tweetRepository.save(existingTweet);
}).map(updateTweet -> new ResponseEntity<>(tweetMapper.toDTO(updateTweet), HttpStatus.OK))
.defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "delete Tweet"),
@ApiResponse(responseCode = "404", description = "tweet not found") })
@DeleteMapping("/tweets/{id}")
public Mono> deleteTweet(@PathVariable(value = "id") String tweetId) {
return tweetRepository.findById(tweetId)
.flatMap(existingTweet -> tweetRepository.delete(existingTweet)
.then(Mono.just(new ResponseEntity(HttpStatus.OK))))
.defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@Operation(description = "Tweets are Sent to the client as Server Sent Events", responses = {
@ApiResponse(responseCode = "200", description = "stream All Tweets") })
@GetMapping(value = "/stream/tweets", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux streamAllTweets() {
return tweetMapper.toDTO(tweetRepository.findAll());
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/controller/TweetMapper.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.controller;
import org.springdoc.demo.app3.dto.TweetDTO;
import org.springdoc.demo.app3.model.Tweet;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
@Component
public class TweetMapper {
Flux toDTO(Flux tweet) {
return tweet.map(this::toDTO);
}
Flux toEntity(Flux tweetDTO) {
return tweetDTO.map(this::toEntity);
}
Mono toDTO(Mono tweet) {
return tweet.map(this::toDTO);
}
Mono toEntity(Mono tweetDTO) {
return tweetDTO.map(this::toEntity);
}
TweetDTO toDTO(Tweet tweet) {
TweetDTO teTweetDTO = new TweetDTO();
BeanUtils.copyProperties(tweet,teTweetDTO);
return teTweetDTO;
}
Tweet toEntity(TweetDTO tweetDTO) {
Tweet teTweet = new Tweet();
BeanUtils.copyProperties(tweetDTO, teTweet);
return teTweet;
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/dto/TweetDTO.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.dto;
import java.util.Date;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
/**
* Created by bnasslahsen on 08/09/17.
*/
public class TweetDTO {
private String id;
@NotBlank
@Size(max = 140)
private String text;
@NotNull
private Date createdAt = new Date();
public TweetDTO() {
}
public TweetDTO(String text) {
this.text = text;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/exception/TweetNotFoundException.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.exception;
/**
* Created by bnasslahsen
*/
public class TweetNotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public TweetNotFoundException(String tweetId) {
super("Tweet not found with id " + tweetId);
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/model/Tweet.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.model;
import java.util.Date;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* Created by bnasslahsen on 08/09/17.
*/
@Document(collection = "tweets")
public class Tweet {
@Id
private String id;
@NotBlank
@Size(max = 140)
private String text;
@NotNull
private Date createdAt = new Date();
public Tweet() {
}
public Tweet(String text) {
this.text = text;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/payload/ErrorResponse.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.payload;
/**
* Created by bnasslahsen
*/
public class ErrorResponse {
private String message;
public ErrorResponse(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/java/org/springdoc/demo/app3/repository/TweetRepository.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app3.repository;
import org.springdoc.demo.app3.model.Tweet;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
/**
* Created by bnasslahsen on 08/09/17.
*/
@Repository
public interface TweetRepository extends ReactiveMongoRepository {
}
================================================
FILE: demo-spring-boot-3-webflux/src/main/resources/META-INF/native-image/reflect-config.json
================================================
[
{
"name": "org.springdoc.demo.app3.dto.TweetDTO[]"
}
]
================================================
FILE: demo-spring-boot-3-webflux/src/main/resources/application.yml
================================================
server:
port: 8082
forward-headers-strategy: framework
spring:
data:
mongodb:
uri: ${SPRING_DATA_MONGODB_URI:mongodb://localhost:27017/tweetsdb}
springdoc:
version: '@springdoc.version@'
swagger-ui:
use-root-path: true
================================================
FILE: demo-spring-boot-3-webflux-functional/.gitignore
================================================
######################
# Project Specific
######################
/target/www/**
/src/test/javascript/coverage/
######################
# Node
######################
/node/
node_tmp/
node_modules/
npm-debug.log.*
/.awcache/*
/.cache-loader/*
######################
# SASS
######################
.sass-cache/
######################
# Eclipse
######################
*.pydevproject
.project
.metadata
tmp/
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.factorypath
/src/main/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
######################
# Intellij
######################
.idea/
*.iml
*.iws
*.ipr
*.ids
*.orig
classes/
out/
######################
# Visual Studio Code
######################
.vscode/
######################
# Maven
######################
/log/
/target/
######################
# Gradle
######################
.gradle/
/build/
######################
# Package Files
######################
*.jar
*.war
*.ear
*.db
######################
# Windows
######################
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
######################
# Mac OSX
######################
.DS_Store
.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# Maven Wrapper
######################
!.mvn/wrapper/maven-wrapper.jar
######################
# ESLint
######################
.eslintcache
================================================
FILE: demo-spring-boot-3-webflux-functional/pom.xml
================================================
4.0.0
springdoc-openapi-demos
org.springdoc
3.1.7-SNAPSHOT
demo-spring-boot-3-webflux-functional
org.springdoc
springdoc-openapi-starter-webflux-ui
org.springframework.boot
spring-boot-starter-webflux
io.projectreactor
reactor-test
test
org.springframework.boot
spring-boot-starter-data-r2dbc
org.projectlombok
lombok
io.r2dbc
r2dbc-h2
runtime
org.springframework.boot
spring-boot-configuration-processor
true
org.springdoc
springdoc-openapi-maven-plugin
org.springframework.boot
spring-boot-maven-plugin
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/AppNativeConfiguration.java
================================================
package org.springdoc.demo.app4;
import java.util.Arrays;
import org.springdoc.demo.app4.AppNativeConfiguration.AppNativeRuntimeHints;
import org.springdoc.demo.app4.coffee.CoffeeService;
import org.springdoc.demo.app4.employee.EmployeeRepository;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
/**
* @author bnasslahsen
*/
@Configuration
@ImportRuntimeHints(AppNativeRuntimeHints.class)
public class AppNativeConfiguration {
static Class[] applicationClasses = { org.springdoc.demo.app4.user.User[].class,
org.springdoc.demo.app4.employee.Employee[].class,
org.springdoc.demo.app4.coffee.Coffee[].class,
org.springdoc.demo.app4.coffee.CoffeeOrder[].class,
EmployeeRepository.class,
CoffeeService.class
};
static class AppNativeRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
Arrays.stream(applicationClasses).forEach(applicationClass ->
hints.reflection().registerType(applicationClass,
(hint) -> hint.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS)));
}
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/WebfluxFunctionalDemoApplication.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app4;
import io.swagger.v3.oas.models.info.Info;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class WebfluxFunctionalDemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebfluxFunctionalDemoApplication.class, args);
}
@Bean
public GroupedOpenApi employeesOpenApi(@Value("${springdoc.version}") String appVersion) {
String[] paths = { "/employees/**" };
return GroupedOpenApi.builder().group("employees")
.addOpenApiCustomizer(openApi -> openApi.info(new Info().title("Employees API").version(appVersion)))
.pathsToMatch(paths)
.build();
}
@Bean
public GroupedOpenApi userOpenApi(@Value("${springdoc.version}") String appVersion) {
String[] paths = { "/api/user/**" };
return GroupedOpenApi.builder().group("users")
.addOpenApiCustomizer(openApi -> openApi.info(new Info().title("Users API").version(appVersion)))
.pathsToMatch(paths)
.build();
}
@Bean
public GroupedOpenApi coffeeOpenApi(@Value("${springdoc.version}") String appVersion) {
String[] paths = { "/coffees/**" };
return GroupedOpenApi.builder().group("coffees")
.addOpenApiCustomizer(openApi -> openApi.info(new Info().title("Coffees API").version(appVersion)))
.pathsToMatch(paths)
.build();
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/coffee/Coffee.java
================================================
package org.springdoc.demo.app4.coffee;
import java.util.Objects;
import org.springframework.data.annotation.Id;
public class Coffee {
@Id
private String id;
private String name;
public Coffee() {
}
public Coffee(String name) {
this.name = name;
}
public Coffee(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Coffee coffee = (Coffee) o;
return Objects.equals(id, coffee.id) &&
Objects.equals(name, coffee.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "Coffee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/coffee/CoffeeOrder.java
================================================
package org.springdoc.demo.app4.coffee;
import java.time.Instant;
import java.util.Objects;
public class CoffeeOrder {
private String coffeeId;
private Instant whenOrdered;
public CoffeeOrder() {
}
public CoffeeOrder(String coffeeId, Instant whenOrdered) {
this.coffeeId = coffeeId;
this.whenOrdered = whenOrdered;
}
public String getCoffeeId() {
return coffeeId;
}
public Instant getWhenOrdered() {
return whenOrdered;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CoffeeOrder that = (CoffeeOrder) o;
return Objects.equals(coffeeId, that.coffeeId) &&
Objects.equals(whenOrdered, that.whenOrdered);
}
@Override
public int hashCode() {
return Objects.hash(coffeeId, whenOrdered);
}
@Override
public String toString() {
return "CoffeeOrder{" +
"coffeeId='" + coffeeId + '\'' +
", whenOrdered=" + whenOrdered +
'}';
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/coffee/CoffeeRepository.java
================================================
package org.springdoc.demo.app4.coffee;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface CoffeeRepository extends ReactiveCrudRepository {
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/coffee/CoffeeService.java
================================================
package org.springdoc.demo.app4.coffee;
import java.time.Duration;
import java.time.Instant;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.stereotype.Service;
@Service
public class CoffeeService {
private final CoffeeRepository repo;
public CoffeeService(CoffeeRepository repo) {
this.repo = repo;
}
Flux getAllCoffees() {
return repo.findAll();
}
Mono getCoffeeById(@Parameter(in = ParameterIn.PATH) String id) {
return repo.findById(id);
}
Flux getOrdersForCoffeeById(@Parameter(in = ParameterIn.PATH) String coffeeId) {
return Flux.interval(Duration.ofSeconds(1))
.onBackpressureDrop()
.map(i -> new CoffeeOrder(coffeeId, Instant.now()));
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/coffee/RouteConfig.java
================================================
package org.springdoc.demo.app4.coffee;
import reactor.core.publisher.Mono;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
@Configuration
public class RouteConfig {
private final CoffeeService service;
public RouteConfig(CoffeeService service) {
this.service = service;
}
@Bean
RouterFunction routerFunction() {
return route().GET("/coffees", this::all, ops -> ops.beanClass(CoffeeService.class).beanMethod("getAllCoffees")).build()
.and(route().GET("/coffees/{id}", this::byId, ops -> ops.beanClass(CoffeeService.class).beanMethod("getCoffeeById")).build())
.and(route().GET("/coffees/{id}/orders", this::orders, ops -> ops.beanClass(CoffeeService.class).beanMethod("getOrdersForCoffeeById")).build());
}
private Mono all(ServerRequest req) {
return ServerResponse.ok()
.body(service.getAllCoffees(), Coffee.class);
}
private Mono byId(ServerRequest req) {
return ServerResponse.ok()
.body(service.getCoffeeById(req.pathVariable("id")), Coffee.class);
}
private Mono orders(ServerRequest req) {
return ServerResponse.ok()
.contentType(MediaType.TEXT_EVENT_STREAM)
.body(service.getOrdersForCoffeeById(req.pathVariable("id")), CoffeeOrder.class);
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/employee/Employee.java
================================================
package org.springdoc.demo.app4.employee;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private String id;
private String name;
// standard getters and setters
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/employee/EmployeeFunctionalConfig.java
================================================
package org.springdoc.demo.app4.employee;
import java.util.function.Consumer;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.springdoc.core.fn.builders.operation.Builder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@Configuration
public class EmployeeFunctionalConfig {
@Bean
EmployeeRepository employeeRepository() {
return new EmployeeRepository();
}
@Bean
RouterFunction getAllEmployeesRoute() {
return route()
.GET("/employees", accept(MediaType.APPLICATION_JSON),
findAllEmployeesFunction(), getOpenAPI("findAllEmployees")).build();
}
@Bean
RouterFunction getEmployeeByIdRoute() {
return route().GET("/employees/{id}", findEmployeeByIdFunction(), findEmployeeByIdOpenAPI()).build();
}
@Bean
RouterFunction updateEmployeeRoute() {
return route().POST("/employees/update", accept(MediaType.APPLICATION_XML),
updateEmployeeFunction(), getOpenAPI("updateEmployee")).build();
}
RouterFunction composedRoutes() {
return route().GET("/employees-composed", findAllEmployeesFunction(), getOpenAPI("findAllEmployees")).build()
.and(route().GET("/employees-composed/{id}", findEmployeeByIdFunction(), findEmployeeByIdOpenAPI()).build())
.and(route().POST("/employees-composed/update", updateEmployeeFunction(), getOpenAPI("updateEmployee")).build());
}
private HandlerFunction findAllEmployeesFunction() {
return req -> ok().body(
employeeRepository().findAllEmployees(), Employee.class);
}
private HandlerFunction updateEmployeeFunction() {
return req -> req.body(BodyExtractors.toMono(Employee.class))
.doOnNext(employeeRepository()::updateEmployee)
.then(ok().build());
}
private HandlerFunction findEmployeeByIdFunction() {
return req -> ok().body(
employeeRepository().findEmployeeById(req.pathVariable("id")), Employee.class);
}
private Consumer getOpenAPI(String findAllEmployees) {
return ops -> ops.beanClass(EmployeeRepository.class).beanMethod(findAllEmployees);
}
private Consumer findEmployeeByIdOpenAPI() {
return ops -> ops.tag("employee")
.operationId("findEmployeeById").summary("Find purchase order by ID").tags(new String[] { "MyEmployee" })
.parameter(parameterBuilder().in(ParameterIn.PATH).name("id").description("Employee Id"))
.response(responseBuilder().responseCode("200").description("successful operation").implementation(Employee.class))
.response(responseBuilder().responseCode("400").description("Invalid Employee ID supplied"))
.response(responseBuilder().responseCode("404").description("Employee not found"));
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/employee/EmployeeRepository.java
================================================
package org.springdoc.demo.app4.employee;
import java.util.HashMap;
import java.util.Map;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Tag(name = "Employees")
public class EmployeeRepository {
static Map employeeData;
static Map employeeAccessData;
static {
employeeData = new HashMap<>();
employeeData.put("1", new Employee("1", "Employee 1"));
employeeData.put("2", new Employee("2", "Employee 2"));
employeeData.put("3", new Employee("3", "Employee 3"));
employeeData.put("4", new Employee("4", "Employee 4"));
employeeData.put("5", new Employee("5", "Employee 5"));
employeeData.put("6", new Employee("6", "Employee 6"));
employeeData.put("7", new Employee("7", "Employee 7"));
employeeData.put("8", new Employee("8", "Employee 8"));
employeeData.put("9", new Employee("9", "Employee 9"));
employeeData.put("10", new Employee("10", "Employee 10"));
employeeAccessData = new HashMap<>();
employeeAccessData.put("1", "Employee 1 Access Key");
employeeAccessData.put("2", "Employee 2 Access Key");
employeeAccessData.put("3", "Employee 3 Access Key");
employeeAccessData.put("4", "Employee 4 Access Key");
employeeAccessData.put("5", "Employee 5 Access Key");
employeeAccessData.put("6", "Employee 6 Access Key");
employeeAccessData.put("7", "Employee 7 Access Key");
employeeAccessData.put("8", "Employee 8 Access Key");
employeeAccessData.put("9", "Employee 9 Access Key");
employeeAccessData.put("10", "Employee 10 Access Key");
}
public Mono findEmployeeById(@Parameter(in = ParameterIn.PATH) String id) {
return Mono.just(employeeData.get(id));
}
public Flux findAllEmployees() {
return Flux.fromIterable(employeeData.values());
}
public Mono updateEmployee(Employee employee) {
Employee existingEmployee = employeeData.get(employee.getId());
if (existingEmployee != null) {
existingEmployee.setName(employee.getName());
}
return Mono.just(existingEmployee);
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/user/RoutingConfiguration.java
================================================
package org.springdoc.demo.app4.user;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction monoRouterFunction(UserHandler userHandler) {
return route().GET("/api/user/index", accept(APPLICATION_JSON), userHandler::getAll, ops -> ops.beanClass(UserRepository.class).beanMethod("getAllUsers")).build()
.and(route().GET("/api/user/{id}", accept(APPLICATION_JSON), userHandler::getUser, ops -> ops.beanClass(UserRepository.class).beanMethod("getUserById")).build()
.and(route().POST("/api/user/post", accept(APPLICATION_JSON), userHandler::postUser, ops -> ops.beanClass(UserRepository.class).beanMethod("saveUser")).build())
.and(route().PUT("/api/user/put/{id}", accept(APPLICATION_JSON), userHandler::putUser, ops -> ops.beanClass(UserRepository.class).beanMethod("putUser")).build())
.and(route().DELETE("/api/user/delete/{id}", accept(APPLICATION_JSON), userHandler::deleteUser, ops -> ops.beanClass(UserRepository.class).beanMethod("deleteUser")).build()));
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/user/User.java
================================================
package org.springdoc.demo.app4.user;
public class User {
private long id;
private String firstname;
private String lastname;
private int age;
public User() {
}
public User(long id, String firstname, String lastname, int age) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
public long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
String info = String.format("id = %d, firstname = %s, lastname = %s, age = %d", id, firstname, lastname, age);
return info;
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/user/UserHandler.java
================================================
package org.springdoc.demo.app4.user;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
@Component
public class UserHandler {
private final UserRepository customerRepository;
public UserHandler(UserRepository repository) {
this.customerRepository = repository;
}
/**
* GET ALL Users
*/
public Mono getAll(ServerRequest request) {
// fetch all customers from repository
Flux customers = customerRepository.getAllUsers();
// build response
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(customers, User.class);
}
/**
* GET a User by ID
*/
public Mono getUser(ServerRequest request) {
// parse path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// build notFound response
Mono notFound = ServerResponse.notFound().build();
// get customer from repository
Mono customerMono = customerRepository.getUserById(customerId);
// build response
return customerMono
.flatMap(customer -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(customer)))
.switchIfEmpty(notFound);
}
/**
* POST a User
*/
public Mono postUser(ServerRequest request) {
Mono customer = request.bodyToMono(User.class);
return ServerResponse.ok().build(customerRepository.saveUser(customer));
}
/**
* PUT a User
*/
public Mono putUser(ServerRequest request) {
// parse id from path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// get customer data from request object
Mono customer = request.bodyToMono(User.class);
// get customer from repository
Mono responseMono = customerRepository.putUser(customerId, customer);
// build response
return responseMono
.flatMap(cust -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(cust)));
}
/**
* DELETE a User
*/
public Mono deleteUser(ServerRequest request) {
// parse id from path-variable
long customerId = Long.valueOf(request.pathVariable("id"));
// get customer from repository
Mono responseMono = customerRepository.deleteUser(customerId);
// build response
return responseMono
.flatMap(strMono -> ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(fromObject(strMono)));
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/user/UserRepository.java
================================================
package org.springdoc.demo.app4.user;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Tag(name = "Users")
public interface UserRepository {
public Mono getUserById(@Parameter(in = ParameterIn.PATH, description = "The user Id") Long id);
@Operation(description = "get all the users")
public Flux getAllUsers();
@Operation(description = "get all the users by firstname")
public Flux getAllUsers(String firstname);
public Mono saveUser(Mono user);
public Mono putUser(@Parameter(in = ParameterIn.PATH) Long id, Mono user);
public Mono deleteUser(@Parameter(in = ParameterIn.PATH) Long id);
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/java/org/springdoc/demo/app4/user/UserRepositoryImpl.java
================================================
package org.springdoc.demo.app4.user;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.annotation.PostConstruct;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositoryImpl implements UserRepository {
private Map users = new HashMap();
@PostConstruct
public void init() throws Exception {
users.put(Long.valueOf(1), new User(1, "Jack", "Smith", 20));
users.put(Long.valueOf(2), new User(2, "Peter", "Johnson", 25));
}
@Override
public Mono getUserById(Long id) {
return Mono.just(users.get(id));
}
@Override
public Flux getAllUsers() {
return Flux.fromIterable(this.users.values());
}
@Override
public Flux getAllUsers(String firstname) {
return Flux.fromIterable(this.users.values().stream().filter(user -> user.getFirstname().equals(firstname)).collect(Collectors.toList()));
}
@Override
public Mono saveUser(Mono monoUser) {
Mono userMono = monoUser.doOnNext(user -> {
// do post
users.put(user.getId(), user);
// log on console
System.out.println("########### POST:" + user);
});
return userMono.then();
}
@Override
public Mono putUser(Long id, Mono monoUser) {
Mono userMono = monoUser.doOnNext(user -> {
// reset user.Id
user.setId(id);
// do put
users.put(id, user);
// log on console
System.out.println("########### PUT:" + user);
});
return userMono;
}
@Override
public Mono deleteUser(Long id) {
// delete processing
users.remove(id);
return Mono.just("Delete Succesfully!");
}
}
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/resources/application.yml
================================================
server:
servlet:
context-path: /
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
min-response-size: 1024
http2:
enabled: true
port: 8084
forward-headers-strategy: framework
springdoc:
version: '@springdoc.version@'
swagger-ui:
use-root-path: true
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/resources/logback-spring.xml
================================================
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
true
================================================
FILE: demo-spring-boot-3-webflux-functional/src/main/resources/schema.sql
================================================
CREATE TABLE COFFEE
(
id VARCHAR(255) PRIMARY KEY,
name VARCHAR(255)
);
================================================
FILE: demo-spring-boot-3-webmvc/.gitignore
================================================
/target/
================================================
FILE: demo-spring-boot-3-webmvc/.java-version
================================================
graalvm64-17.0.5
================================================
FILE: demo-spring-boot-3-webmvc/README.md
================================================
# springdoc-openapi demo with spring-boot-2 web-mvc
## Building application
### Pre-requisites
- JDK 8+
- maven 3
- docker CLI
### Option 1: Building Executable JAR
To create an `executable jar`, simply run:
```sh
mvn clean package
```
### Option 2: Building a non-native OCI Images
To create a non-native OCI docker image, simply run:
```sh
mvn clean spring-boot:build-image
```
### Option 3: Building native image with GraalVM
To create a `native image`, Run the following command
```sh
mvn -Pnative clean native:compile
```
## Running the native application
To run the demo using docker, invoke the following:
```sh
docker run --rm -p 8080:8081 springdoc-openapi-spring-boot-2-webmvc:3.1.6-SNAPSHOT
```
================================================
FILE: demo-spring-boot-3-webmvc/pom.xml
================================================
4.0.0
org.springdoc
springdoc-openapi-demos
3.1.7-SNAPSHOT
demo-spring-boot-3-webmvc
org.springframework.boot
spring-boot-starter-web
org.springframework.data
spring-data-commons
org.springframework.boot
spring-boot-starter-actuator
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
org.springdoc
springdoc-openapi-starter-webmvc-ui
org.springframework.boot
spring-boot-configuration-processor
true
org.springdoc
springdoc-openapi-maven-plugin
org.springframework.boot
spring-boot-maven-plugin
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/Application.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import static org.springdoc.core.utils.Constants.ALL_PATTERN;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Bean
@Profile("!prod")
public GroupedOpenApi actuatorApi(OpenApiCustomizer actuatorOpenApiCustomizer,
OperationCustomizer actuatorCustomizer,
WebEndpointProperties endpointProperties,
@Value("${springdoc.version}") String appVersion) {
return GroupedOpenApi.builder()
.group("Actuator")
.pathsToMatch(endpointProperties.getBasePath() + ALL_PATTERN)
.addOpenApiCustomizer(actuatorOpenApiCustomizer)
.addOpenApiCustomizer(openApi -> openApi.info(new Info().title("Actuator API").version(appVersion)))
.addOperationCustomizer(actuatorCustomizer)
.pathsToExclude("/health/*")
.build();
}
@Bean
public GroupedOpenApi usersGroup(@Value("${springdoc.version}") String appVersion) {
return GroupedOpenApi.builder().group("users")
.addOperationCustomizer((operation, handlerMethod) -> {
operation.addSecurityItem(new SecurityRequirement().addList("basicScheme"));
return operation;
})
.addOpenApiCustomizer(openApi -> openApi.info(new Info().title("Users API").version(appVersion)))
.packagesToScan("org.springdoc.demo.app2")
.pathsToMatch("/user/**")
.build();
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/ApiUtil.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2.api;
import java.io.IOException;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.server.ResponseStatusException;
public class ApiUtil {
public static void setExampleResponse(NativeWebRequest req, String contentType, String example) {
try {
req.getNativeResponse(HttpServletResponse.class).addHeader("Content-Type", contentType);
req.getNativeResponse(HttpServletResponse.class).getOutputStream().print(example);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void checkApiKey(NativeWebRequest req) {
if (!"1".equals(System.getenv("DISABLE_API_KEY")) && !"special-key".equals(req.getHeader("api_key"))) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing API key!");
}
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/ExceptionTranslator.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2.api;
import java.util.Map;
import jakarta.validation.ConstraintViolationException;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
@RestControllerAdvice
public class ExceptionTranslator {
private final ErrorAttributes errorAttributes;
public ExceptionTranslator(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map processConstraintViolationException(WebRequest request) {
request.setAttribute("jakarta.servlet.error.status_code", HttpStatus.BAD_REQUEST.value(), RequestAttributes.SCOPE_REQUEST);
return errorAttributes.getErrorAttributes(request, ErrorAttributeOptions.defaults());
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/PetApi.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
/**
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.0.0).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.springdoc.demo.app2.api;
import java.util.List;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.Explode;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.enums.ParameterStyle;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.OAuthFlow;
import io.swagger.v3.oas.annotations.security.OAuthFlows;
import io.swagger.v3.oas.annotations.security.OAuthScope;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springdoc.core.annotations.ParameterObject;
import org.springdoc.demo.app2.model.ModelApiResponse;
import org.springdoc.demo.app2.model.Pet;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
@SecurityScheme(name = "petstore_auth", type = SecuritySchemeType.OAUTH2, flows = @OAuthFlows(implicit = @OAuthFlow(authorizationUrl = "https://petstore3.swagger.io/oauth/authorize", scopes = {
@OAuthScope(name = "write:pets", description = "modify pets in your account"),
@OAuthScope(name = "read:pets", description = "read your pets") })))
@Tag(name = "pet", description = "the pet API")
public interface PetApi {
default PetApiDelegate getDelegate() {
return new PetApiDelegate() {
};
}
@Operation(summary = "Add a new pet to the store", description = "Add a new pet to the store", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successful operation", content = { @Content(mediaType = "application/xml", schema = @Schema(implementation = Pet.class)), @Content(mediaType = "application/json", schema = @Schema(implementation = Pet.class)) }),
@ApiResponse(responseCode = "405", description = "Invalid input")
})
@PostMapping(value = "/pet", consumes = { "application/json", "application/xml", "application/x-www-form-urlencoded" })
default void addPet(
@Parameter(description = "Create a new pet in the store", required = true) @Valid @RequestBody Pet pet) {
// return getDelegate().addPet(pet);
}
@Operation(summary = "Deletes a pet", description = "", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = { @ApiResponse(responseCode = "400", description = "Invalid pet value") })
@DeleteMapping(value = "/pet/{petId}")
default ResponseEntity deletePet(
@Parameter(description = "Pet id to delete", required = true) @PathVariable("petId") Long petId,
@Parameter(description = "") @RequestHeader(value = "api_key", required = false) String apiKey) {
return getDelegate().deletePet(petId, apiKey);
}
@Operation(summary = "Finds Pets by status", description = "Multiple status values can be provided with comma separated strings", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Pet.class)))),
@ApiResponse(responseCode = "400", description = "Invalid status value") })
@GetMapping(value = "/pet/findByStatus", produces = { "application/xml", "application/json" })
default ResponseEntity> findPetsByStatus(@Parameter(explode = Explode.TRUE, name = "status", in = ParameterIn.QUERY, description = "Status values that need to be considered for filter", style = ParameterStyle.FORM, schema = @Schema(type = "string", defaultValue = "available", allowableValues = { "available", "pending", "sold" })) @Valid @RequestParam(value = "status", required = false) List status) {
return getDelegate().findPetsByStatus(status);
}
@Operation(summary = "Finds Pets by tags", description = "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Pet.class)))),
@ApiResponse(responseCode = "400", description = "Invalid tag value", content = @Content) })
@GetMapping(value = "/pet/findByTags", produces = { "application/xml", "application/json" })
default ResponseEntity> findPetsByTags(
@Parameter(description = "Tags to filter by", explode = Explode.TRUE, in = ParameterIn.QUERY, name = "tags", style = ParameterStyle.FORM) @Valid @RequestParam(value = "tags", required = false) List tags) {
return getDelegate().findPetsByTags(tags);
}
@Operation(summary = "Find pet by ID", description = "Returns a single pet", security = {
@SecurityRequirement(name = "api_key"),
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" })
}, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = Pet.class))),
@ApiResponse(responseCode = "400", description = "Invalid ID supplied", content = @Content),
@ApiResponse(responseCode = "404", description = "Pet not found", content = @Content) })
@GetMapping(value = "/pet/{petId}", produces = { "application/xml", "application/json" })
default ResponseEntity getPetById(
@Parameter(description = "ID of pet to return", required = true) @PathVariable("petId") Long petId) {
return getDelegate().getPetById(petId);
}
@Operation(summary = "Update an existing pet", description = "Update an existing pet by Id", operationId = "updatePet", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successful operation",
content =
{ @Content(mediaType = "application/xml", schema = @Schema(implementation = Pet.class)), @Content(mediaType = "application/json", schema = @Schema(implementation = Pet.class)) }
),
@ApiResponse(responseCode = "400", description = "Invalid ID supplied"),
@ApiResponse(responseCode = "404", description = "Pet not found"),
@ApiResponse(responseCode = "405", description = "Validation exception") })
@PutMapping(value = "/pet", consumes = { "application/json", "application/xml", "application/x-www-form-urlencoded" })
default ResponseEntity updatePet(
@Parameter(description = "Update an existent pet in the store", required = true) @Valid @RequestBody Pet pet) {
return getDelegate().updatePet(pet);
}
@Operation(summary = "Updates a pet in the store with form data", description = "", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = { @ApiResponse(responseCode = "405", description = "Invalid input") })
@PostMapping(value = "/pet/{petId}", consumes = { "application/x-www-form-urlencoded" })
default ResponseEntity updatePetWithForm(
@Parameter(description = "ID of pet that needs to be updated", required = true) @PathVariable("petId") Long petId,
@Parameter(description = "Name of pet that needs to be updated") @RequestParam(value = "name", required = false) String name,
@Parameter(description = "Status of pet that needs to be updated") @RequestParam(value = "status", required = false) String status) {
return getDelegate().updatePetWithForm(petId, name, status);
}
@Operation(summary = "uploads an image", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = ModelApiResponse.class))) })
@PostMapping(value = "/pet/{petId}/uploadImage", produces = { "application/json" }, consumes = {
"multipart/form-data" })
default ResponseEntity uploadFile(
@Parameter(description = "ID of pet to update", required = true) @PathVariable("petId") Long petId,
@Parameter(description = "Additional Metadata") @RequestParam(value = "additionalMetadata", required = false) String additionalMetadata,
@Parameter(content = @Content(mediaType = "multipart/form-data", schema = @Schema(type = "string", format = "binary"))) @Valid @RequestPart("file") MultipartFile file) {
return getDelegate().uploadFile(petId, additionalMetadata, file);
}
@Operation(summary = "Get all Pets paged", description = "Get all Pets paged", security = {
@SecurityRequirement(name = "petstore_auth", scopes = { "write:pets", "read:pets" }) }, tags = { "pet" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Pet.class))))
})
@GetMapping(value = "/pet", produces = { "application/xml", "application/json" })
default ResponseEntity> getAllPets(@NotNull @ParameterObject Pageable pageable) {
return getDelegate().getAllPets(pageable);
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/PetApiController.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2.api;
import java.util.Optional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("${openapi.openAPIPetstore.base-path:/}")
public class PetApiController implements PetApi {
private final PetApiDelegate delegate;
public PetApiController(@org.springframework.beans.factory.annotation.Autowired(required = false) PetApiDelegate delegate) {
this.delegate = Optional.ofNullable(delegate).orElse(new PetApiDelegate() {
});
}
@Override
public PetApiDelegate getDelegate() {
return delegate;
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/PetApiDelegate.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2.api;
import java.util.List;
import java.util.Optional;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springdoc.demo.app2.model.ModelApiResponse;
import org.springdoc.demo.app2.model.Pet;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
/**
* A delegate to be called by the {@link PetApiController}}.
* Implement this interface with a {@link org.springframework.stereotype.Service} annotated class.
*/
public interface PetApiDelegate {
default Optional getRequest() {
return Optional.empty();
}
/**
* @see PetApi#addPet
*/
default void addPet(Pet pet) {
}
/**
* @see PetApi#deletePet
*/
default ResponseEntity deletePet(Long petId,
String apiKey) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* @see PetApi#findPetsByStatus
*/
default ResponseEntity> findPetsByStatus(List status) {
extract();
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
default void extract() {
getRequest().ifPresent(request -> {
for (MediaType mediaType : MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
ApiUtil.setExampleResponse(request, "application/json", "{ \"photoUrls\" : [ \"photoUrls\", \"photoUrls\" ], \"name\" : \"doggie\", \"id\" : 0, \"category\" : { \"name\" : \"name\", \"id\" : 6 }, \"tags\" : [ { \"name\" : \"name\", \"id\" : 1 }, { \"name\" : \"name\", \"id\" : 1 } ], \"status\" : \"available\"}");
break;
}
if (mediaType.isCompatibleWith(MediaType.valueOf("application/xml"))) {
ApiUtil.setExampleResponse(request, "application/xml", " 123456789 doggie aeiou aeiou");
break;
}
}
});
}
/**
* @see PetApi#findPetsByTags
*/
default ResponseEntity> findPetsByTags(List tags) {
extract();
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* @see PetApi#getPetById
*/
default ResponseEntity getPetById(Long petId) {
extract();
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* @see PetApi#updatePet
*/
default ResponseEntity updatePet(Pet pet) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* @see PetApi#updatePetWithForm
*/
default ResponseEntity updatePetWithForm(Long petId,
String name,
String status) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* @see PetApi#uploadFile
*/
default ResponseEntity uploadFile(Long petId,
String additionalMetadata,
@Valid MultipartFile file) {
getRequest().ifPresent(request -> {
for (MediaType mediaType : MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
ApiUtil.setExampleResponse(request, "application/json", "{ \"code\" : 0, \"type\" : \"type\", \"message\" : \"message\"}");
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
default ResponseEntity> getAllPets(@NotNull Pageable pageable) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/PetApiDelegateImpl.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.springdoc.demo.app2.api;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springdoc.demo.app2.model.Category;
import org.springdoc.demo.app2.model.ModelApiResponse;
import org.springdoc.demo.app2.model.Pet;
import org.springdoc.demo.app2.model.Tag;
import org.springdoc.demo.app2.repository.PetRepository;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
@Service
public class PetApiDelegateImpl implements PetApiDelegate {
private final PetRepository petRepository;
private final NativeWebRequest request;
public PetApiDelegateImpl(PetRepository petRepository, NativeWebRequest request) {
this.petRepository = petRepository;
this.request = request;
}
private static Pet createPet(long id, Category category, String name, String[] urls, String[] tags,
Pet.StatusEnum status) {
Pet pet = new Pet().id(id).category(category).name(name).status(status);
if (null != urls) {
pet.setPhotoUrls(Arrays.asList(urls));
}
final AtomicLong i = new AtomicLong(0);
if (null != tags && tags.length > 0) {
Arrays.stream(tags).map(tag -> new Tag().name(tag).id(i.incrementAndGet())).forEach(pet::addTagsItem);
}
return pet;
}
@PostConstruct
public void initPets() {
Category dogs = new Category().id(1L).name("Dogs");
Category cats = new Category().id(2L).name("Cats");
Category rabbits = new Category().id(3L).name("Rabbits");
Category lions = new Category().id(4L).name("Lions");
petRepository.save(createPet(1, cats, "Cat 1", new String[] { "url1", "url2" }, new String[] { "tag1", "tag2" },
Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(2, cats, "Cat 2", new String[] { "url1", "url2" }, new String[] { "tag2", "tag3" },
Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(3, cats, "Cat 3", new String[] { "url1", "url2" }, new String[] { "tag3", "tag4" },
Pet.StatusEnum.PENDING));
petRepository.save(createPet(4, dogs, "Dog 1", new String[] { "url1", "url2" }, new String[] { "tag1", "tag2" },
Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(5, dogs, "Dog 2", new String[] { "url1", "url2" }, new String[] { "tag2", "tag3" },
Pet.StatusEnum.SOLD));
petRepository.save(createPet(6, dogs, "Dog 3", new String[] { "url1", "url2" }, new String[] { "tag3", "tag4" },
Pet.StatusEnum.PENDING));
petRepository.save(createPet(7, lions, "Lion 1", new String[] { "url1", "url2" },
new String[] { "tag1", "tag2" }, Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(8, lions, "Lion 2", new String[] { "url1", "url2" },
new String[] { "tag2", "tag3" }, Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(9, lions, "Lion 3", new String[] { "url1", "url2" },
new String[] { "tag3", "tag4" }, Pet.StatusEnum.AVAILABLE));
petRepository.save(createPet(10, rabbits, "Rabbit 1", new String[] { "url1", "url2" },
new String[] { "tag3", "tag4" }, Pet.StatusEnum.AVAILABLE));
}
@Override
public void addPet(Pet pet) {
petRepository.save(pet);
// return ResponseEntity.ok().build();
}
@Override
public ResponseEntity deletePet(Long petId, String apiKey) {
petRepository.deleteById(petId);
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity> findPetsByStatus(List statusList) {
List statusEnums = statusList.stream()
.map(s -> Optional.ofNullable(Pet.StatusEnum.fromValue(s))
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid status: " + s)))
.collect(Collectors.toList());
return ResponseEntity.ok(petRepository.findPetsByStatus(statusEnums));
}
@Override
public ResponseEntity> findPetsByTags(List tags) {
return ResponseEntity.ok(petRepository.findPetsByTags(tags));
}
@Override
public ResponseEntity getPetById(Long petId) {
ApiUtil.checkApiKey(request);
return petRepository.findById(petId).map(ResponseEntity::ok)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
@Override
public ResponseEntity updatePet(Pet pet) {
return null;
// return addPet(pet);
}
@Override
public ResponseEntity updatePetWithForm(Long petId, String name, String status) {
Pet pet = petRepository.findById(petId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
if (!StringUtils.isEmpty(name))
pet.name(name);
if (!StringUtils.isEmpty(name))
pet.setStatus(Pet.StatusEnum.fromValue(status));
// return addPet(pet);
return null;
}
@Override
public ResponseEntity uploadFile(Long petId, String additionalMetadata, MultipartFile file) {
try {
String uploadedFileLocation = "./" + file.getName();
System.out.println("uploading to " + uploadedFileLocation);
IOUtils.copy(file.getInputStream(), new FileOutputStream(uploadedFileLocation));
String msg = String.format("additionalMetadata: %s\nFile uploaded to %s, %d bytes", additionalMetadata,
uploadedFileLocation, (new File(uploadedFileLocation)).length());
ModelApiResponse output = new ModelApiResponse().code(200).message(msg);
return ResponseEntity.ok(output);
}
catch (Exception e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Couldn't upload file", e);
}
}
public ResponseEntity> getAllPets(@NotNull Pageable pageable) {
ApiUtil.checkApiKey(request);
return new ResponseEntity>(petRepository.findAll(pageable), HttpStatus.OK);
}
}
================================================
FILE: demo-spring-boot-3-webmvc/src/main/java/org/springdoc/demo/app2/api/StoreApi.java
================================================
/*
*
* * Copyright 2019-2020 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
/**
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.0.0).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.springdoc.demo.app2.api;
import java.util.Map;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import org.springdoc.demo.app2.model.Order;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@Tag(name = "store", description = "the store API")
public interface StoreApi {
default StoreApiDelegate getDelegate() {
return new StoreApiDelegate() {
};
}
@Operation(summary = "Delete purchase order by ID", description = "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", tags = { "store" })
@ApiResponses(value = { @ApiResponse(responseCode = "400", description = "Invalid ID supplied"),
@ApiResponse(responseCode = "404", description = "Order not found") })
@DeleteMapping(value = "/store/order/{orderId}")
default ResponseEntity deleteOrder(
@Parameter(description = "ID of the order that needs to be deleted", required = true, schema = @Schema(type = "integer", format = "int64")) @PathVariable("orderId") Long orderId) {
return getDelegate().deleteOrder(orderId);
}
@Operation(summary = "Returns pet inventories by status", description = "Returns a map of status codes to quantities", security = {
@SecurityRequirement(name = "api_key") }, tags = { "store" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(type = "object"))) })
@GetMapping(value = "/store/inventory", produces = { "application/json" })
default ResponseEntity