diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index 96a0234..0000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Require maintainer's :+1: for changes to the .github/ repo-config files
-# mainly due to https://github.com/probot/settings privilege escalation
-.github/* @pages-themes/maintainers
diff --git a/.github/config.yml b/.github/config.yml
deleted file mode 100644
index 683f93f..0000000
--- a/.github/config.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Behaviorbot config. See https://github.com/behaviorbot/ for more information.
-# Note: Please Don't edit this file directly.
-# Edit https://github.com/pages-themes/maintenance-scripts instead.
-
-# Configuration for update-docs - https://github.com/behaviorbot/update-docs
-updateDocsComment: "Thanks for the pull request! If you are making any changes to the user-facing functionality, please be sure to update the documentation in the `README` or `docs/` folder alongside your change. :heart:"
-
-# Configuration for request-info - https://github.com/behaviorbot/request-info
-requestInfoReplyComment: Thanks for this. Do you mind providing a bit more information about what problem you're trying to solve?
-requestInfoLabelToAdd: more-information-needed
-
-# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
-#newIssueWelcomeComment: >
-# Welcome!
-
-# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
-newPRWelcomeComment: Welcome! Congrats on your first pull request to The Cayman Theme. If you haven't already, please be sure to check out [the contributing guidelines](https://github.com/pages-themes/cayman/blob/master/docs/CONTRIBUTING.md).
-
-# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
-firstPRMergeComment: "Congrats on getting your first pull request to The Cayman Theme merged! Without amazing humans like you submitting pull requests, we couldn’t run this project. You rock! :tada:
If you're interested in tackling another bug or feature, take a look at [the open issues](https://github.com/pages-themes/cayman/issues), especially those [labeled `help wanted`](https://github.com/pages-themes/cayman/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)."
diff --git a/.github/no-response.yml b/.github/no-response.yml
deleted file mode 100644
index 7193eaa..0000000
--- a/.github/no-response.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-# Configuration for probot-no-response - https://github.com/probot/no-response
-
-# Number of days of inactivity before an Issue is closed for lack of response
-daysUntilClose: 14
-# Label requiring a response
-responseRequiredLabel: more-information-needed
-# Comment to post when closing an Issue for lack of response. Set to `false` to disable
-closeComment: >
- This issue has been automatically closed because there has been no response
- to our request for more information from the original author. With only the
- information that is currently in the issue, we don't have enough information
- to take action. Please reach out if you have or find the answers we need so
- that we can investigate further.
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index a1aa17e..0000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Configuration for probot-stale - https://github.com/probot/stale
-
-# Number of days of inactivity before an Issue or Pull Request becomes stale
-daysUntilStale: 60
-
-# Number of days of inactivity before a stale Issue or Pull Request is closed
-daysUntilClose: 7
-
-# Issues or Pull Requests with these labels will never be considered stale
-exemptLabels:
- - pinned
- - security
-
-# Label to use when marking as stale
-staleLabel: wontfix
-
-# Comment to post when marking as stale. Set to `false` to disable
-markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
-
-# Comment to post when closing a stale Issue or Pull Request. Set to `false` to disable
-closeComment: false
-
-# Limit to only `issues` or `pulls`
-# only: issues
diff --git a/.gitignore b/.gitignore
index ab21548..dcaa5c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,7 +36,7 @@ local.properties
.settings/
.loadpath
.factorypath
-/src/main/resources/rebel.xml
+/src/docs/resources/rebel.xml
# External tool builders
.externalToolBuilders/**
diff --git a/.rubocop.yml b/.rubocop.yml
deleted file mode 100644
index 648dfb1..0000000
--- a/.rubocop.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-AllCops:
- Exclude:
- - _site/**/*
-
-Metrics/LineLength:
- Enabled: false
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 412d52e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: java
-jdk:
- - openjdk8
-cache:
- directories:
- - $HOME/.m2
- - $HOME/.sonar/cache
-
-script:
- - mvn clean package
diff --git a/CNAME b/CNAME
deleted file mode 100644
index 30f0619..0000000
--- a/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-springdoc.org
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index 7f4f5e9..0000000
--- a/Gemfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gemspec
diff --git a/LICENSE b/LICENSE
index 670154e..261eeb9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,116 +1,201 @@
-CC0 1.0 Universal
-
-Statement of Purpose
-
-The laws of most jurisdictions throughout the world automatically confer
-exclusive Copyright and Related Rights (defined below) upon the creator and
-subsequent owner(s) (each and all, an "owner") of an original work of
-authorship and/or a database (each, a "Work").
-
-Certain owners wish to permanently relinquish those rights to a Work for the
-purpose of contributing to a commons of creative, cultural and scientific
-works ("Commons") that the public can reliably and without fear of later
-claims of infringement build upon, modify, incorporate in other works, reuse
-and redistribute as freely as possible in any form whatsoever and for any
-purposes, including without limitation commercial purposes. These owners may
-contribute to the Commons to promote the ideal of a free culture and the
-further production of creative, cultural and scientific works, or to gain
-reputation or greater distribution for their Work in part through the use and
-efforts of others.
-
-For these and/or other purposes and motivations, and without any expectation
-of additional consideration or compensation, the person associating CC0 with a
-Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
-and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
-and publicly distribute the Work under its terms, with knowledge of his or her
-Copyright and Related Rights in the Work and the meaning and intended legal
-effect of CC0 on those rights.
-
-1. Copyright and Related Rights. A Work made available under CC0 may be
-protected by copyright and related or neighboring rights ("Copyright and
-Related Rights"). Copyright and Related Rights include, but are not limited
-to, the following:
-
- i. the right to reproduce, adapt, distribute, perform, display, communicate,
- and translate a Work;
-
- ii. moral rights retained by the original author(s) and/or performer(s);
-
- iii. publicity and privacy rights pertaining to a person's image or likeness
- depicted in a Work;
-
- iv. rights protecting against unfair competition in regards to a Work,
- subject to the limitations in paragraph 4(a), below;
-
- v. rights protecting the extraction, dissemination, use and reuse of data in
- a Work;
-
- vi. database rights (such as those arising under Directive 96/9/EC of the
- European Parliament and of the Council of 11 March 1996 on the legal
- protection of databases, and under any national implementation thereof,
- including any amended or successor version of such directive); and
-
- vii. other similar, equivalent or corresponding rights throughout the world
- based on applicable law or treaty, and any national implementations thereof.
-
-2. Waiver. To the greatest extent permitted by, but not in contravention of,
-applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
-unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
-and Related Rights and associated claims and causes of action, whether now
-known or unknown (including existing as well as future claims and causes of
-action), in the Work (i) in all territories worldwide, (ii) for the maximum
-duration provided by applicable law or treaty (including future time
-extensions), (iii) in any current or future medium and for any number of
-copies, and (iv) for any purpose whatsoever, including without limitation
-commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
-the Waiver for the benefit of each member of the public at large and to the
-detriment of Affirmer's heirs and successors, fully intending that such Waiver
-shall not be subject to revocation, rescission, cancellation, termination, or
-any other legal or equitable action to disrupt the quiet enjoyment of the Work
-by the public as contemplated by Affirmer's express Statement of Purpose.
-
-3. Public License Fallback. Should any part of the Waiver for any reason be
-judged legally invalid or ineffective under applicable law, then the Waiver
-shall be preserved to the maximum extent permitted taking into account
-Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
-is so judged Affirmer hereby grants to each affected person a royalty-free,
-non transferable, non sublicensable, non exclusive, irrevocable and
-unconditional license to exercise Affirmer's Copyright and Related Rights in
-the Work (i) in all territories worldwide, (ii) for the maximum duration
-provided by applicable law or treaty (including future time extensions), (iii)
-in any current or future medium and for any number of copies, and (iv) for any
-purpose whatsoever, including without limitation commercial, advertising or
-promotional purposes (the "License"). The License shall be deemed effective as
-of the date CC0 was applied by Affirmer to the Work. Should any part of the
-License for any reason be judged legally invalid or ineffective under
-applicable law, such partial invalidity or ineffectiveness shall not
-invalidate the remainder of the License, and in such case Affirmer hereby
-affirms that he or she will not (i) exercise any of his or her remaining
-Copyright and Related Rights in the Work or (ii) assert any associated claims
-and causes of action with respect to the Work, in either case contrary to
-Affirmer's express Statement of Purpose.
-
-4. Limitations and Disclaimers.
-
- a. No trademark or patent rights held by Affirmer are waived, abandoned,
- surrendered, licensed or otherwise affected by this document.
-
- b. Affirmer offers the Work as-is and makes no representations or warranties
- of any kind concerning the Work, express, implied, statutory or otherwise,
- including without limitation warranties of title, merchantability, fitness
- for a particular purpose, non infringement, or the absence of latent or
- other defects, accuracy, or the present or absence of errors, whether or not
- discoverable, all to the greatest extent permissible under applicable law.
-
- c. Affirmer disclaims responsibility for clearing rights of other persons
- that may apply to the Work or any use thereof, including without limitation
- any person's Copyright and Related Rights in the Work. Further, Affirmer
- disclaims responsibility for obtaining any necessary consents, permissions
- or other rights required for any use of the Work.
-
- d. Affirmer understands and acknowledges that Creative Commons is not a
- party to this document and has no duty or obligation with respect to this
- CC0 or use of the Work.
-
-For more information, please see
-
+ 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.
diff --git a/README.md b/README.md
deleted file mode 100644
index fe78437..0000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# springdoc.github.io
-Library for OpenAPI 3 with spring-boot
-[](https://travis-ci.org/springdoc/springdoc.github.io)
-
-# [Full documentation](https://springdoc.org)
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index 7db9f17..0000000
--- a/_config.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-title: springdoc-openapi
-description: Library for OpenAPI 3 with spring-boot
-google_analytics: UA-143834491-1
-theme: jekyll-theme-cayman
-url: http://springdoc.org
-show_downloads: true
-markdown: kramdown
\ No newline at end of file
diff --git a/_layouts/default.html b/_layouts/default.html
deleted file mode 100644
index 31ee2b7..0000000
--- a/_layouts/default.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
- {% if site.google_analytics %}
-
-
- {% endif %}
-
-
-{% seo %}
-
-
-
-
-
-
- Skip to the content.
-
-
-
Boolean. To make spring security login-endpoint visible.
+
+
+
springdoc.pre-loading-locales
+
+
List of Strings. The list of locales to load OpenAPI on application startup (comma separated). If not specified, it will preload with the default Locale.
+
+
+
springdoc.writer-with-order-by-keys
+
false
+
Boolean. Enable a deterministic/alphabetical ordering.
+
+
+
springdoc.use-management-port
+
false
+
Boolean. To expose the swagger-ui on the actuator management port.
+
+
+
springdoc.disable-i18n
+
false
+
Boolean. To disable automatic translation using i18n.
+
+
+
springdoc.show-spring-cloud-functions
+
true
+
Boolean. To display the spring-cloud-function web endpoints.
+
+
+
springdoc.enable-groovy
+
true
+
Boolean. To enable Groovy support.
+
+
+
springdoc.enable-spring-security
+
true
+
Boolean. To enable spring-security support.
+
+
+
springdoc.enable-kotlin
+
true
+
Boolean. To enable Kotlin support.
+
+
+
springdoc.enable-hateoas
+
true
+
Boolean. To enable spring-hateoas support.
+
+
+
springdoc.enable-data-rest
+
true
+
Boolean. To enable spring-data-rest support.
+
+
+
springdoc.api-docs.version
+
openapi_3_1
+
String. To choose OpenAPI 3.0 or OpenAPI 3.1 (using the value OPENAPI_3_1).
+
+
+
springdoc.default-flat-param-object
+
false
+
Boolean. To default flatten parameter.
+
+
+
springdoc.default-support-form-data
+
false
+
Boolean. To default set parameters to form data when specifying api to accept form data.
+
+
+
springdoc.nullable-request-parameter-enabled
+
true
+
Boolean. To default Enable Support for nullable request parameters in Kotlin.
+
+
+
springdoc.show-oauth2-endpoints
+
false
+
Boolean. To make spring security oauth2-endpoint visible.
+
+
+
springdoc.api-docs.resolve-extensions-properties
+
false
+
Boolean. To enable support of spring property resolver for @ExtensionProperty.
+
+
+
springdoc.enable-default-api-docs
+
true
+
Boolean. To enable default OpenAPI endpoint /v3/api-docs.
+
+
+
springdoc.trim-kotlin-indent
+
false
+
Boolean. Adjust indentation when parsing the @Operation annotation in Kotlin.
+
+
+
springdoc.allowed-locales
+
+
List of Strings. The list of allowed locales for OpenAPI (comma separated, for example US,fr-CA).
+
+
+
springdoc.enable-extra-schemas
+
true
+
Boolean. To enable default support for extra Schemas, from java.time package like LocalTime, Duration, but also other Java classes like java.util.Locale or java.nio.charset.Charset
+
+
+
springdoc.explicit-object-schema
+
false
+
Boolean. Set explicit-object-schema to true to always include type: object in the schema, or to false to omit type: object.
+
+
+
springdoc.use-arbitrary-schemas
+
false
+
Boolean. When set to true, schemas without a defined type will be deserialized as an ArbitrarySchema (with no type), instead of an ObjectSchema with type: object.
+
+
\ No newline at end of file
diff --git a/docs/faq.html b/docs/faq.html
new file mode 100644
index 0000000..ae663fc
--- /dev/null
+++ b/docs/faq.html
@@ -0,0 +1,2135 @@
+
+
+
+
+
+
+
+F.A.Q
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
F.A.Q
+
+
+
How can I define multiple OpenAPI definitions in one Spring Boot project?
+
+
You can define your own groups of API based on the combination of: API paths and packages to scan. Each group should have a unique groupName.
+The OpenAPI description of this group, will be available by default on:
Can springdoc-openapi generate API only for @RestController?
+
+
+
+
@RestController is equivalent to @Controller + @RequestMapping on the type level.
+
+
+
For some legacy apps, we are constrained to still support both.
+
+
+
If you need to hide the @Controller on the type level, in this case, you can use: @Hidden on controller level.
+
+
+
Please note this annotation can be also used to hide some methods from the generated documentation.
+
+
+
+
+
+
Are the following validation annotations supported : @NotEmpty@NotBlank@PositiveOrZero@NegativeOrZero?
+
+
+
+
Yes
+
+
+
+
+
+
How can I map Pageable (spring-data-commons) object to correct URL-Parameter in Swagger UI?
+
+
The support for Pageable of spring-data-commons is available out-of-the box since springdoc-openapi v1.6.0.
+For this, you have to combine @ParameterObject annotation with the Pageable type.
+
+
+
Before springdoc-openapi v1.6.0:
+
+
+
+
+
You can use as well @ParameterObject instead of @PageableAsQueryParam for HTTP GET methods.
Another solution, is to configure Pageable manually:
+
+
+
+
you will have to declare the explicit mapping of Pageable fields as Query Params and add the @Parameter(hidden = true) Pageable pageable on your pageable parameter.
+
+
+
You should also, declare the annotation @PageableAsQueryParam provided by springdoc-openapi on the method level, or declare your own if need to define your custom description, defaultValue, …
+
+
+
+
+
+
+
+
If you want to disable the support of spring Pageable Type, you can use:
How can I deploy springdoc-openapi-starter-webmvc-ui behind a reverse proxy?
+
+
+
+
If your application is running behind a proxy, a load-balancer or in the cloud, the request information (like the host, port, scheme…) might change along the way. Your application may be running on 10.10.10.10:8080, but HTTP clients should only see example.org.
+
+
+
RFC7239 "Forwarded Headers" defines the Forwarded HTTP header; proxies can use this header to provide information about the original request. You can configure your application to read those headers and automatically use that information when creating links and sending them to clients in HTTP 302 responses, JSON documents or HTML pages. There are also non-standard headers, like X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, and X-Forwarded-Prefix.
+
+
+
If the proxy adds the commonly used X-Forwarded-For and X-Forwarded-Proto headers, setting server.forward-headers-strategy to NATIVE is enough to support those. With this option, the Web servers themselves natively support this feature; you can check their specific documentation to learn about specific behavior.
+
+
+
You need to make sure the following header is set in your reverse proxy configuration: X-Forwarded-Prefix
+
+
+
For example, using Apache 2, configuration:
+
+
+
+
+
+
RequestHeader set X-Forwarded-Prefix "/custom-path"
+
+
+
+
+
+
Then, in your Spring Boot application make sure your application handles this header: X-Forwarded-For. There are two ways to achieve this:
+
+
+
+
+
+
server.use-forward-headers=true
+
+
+
+
+
+
If this is not enough, Spring Framework provides a ForwardedHeaderFilter. You can register it as a Servlet Filter in your application by setting server.forward-headers-strategy is set to FRAMEWORK.
+
+
+
Since Spring Boot 2.2, this is the new property to handle reverse proxy headers:
+
+
+
+
+
+
server.forward-headers-strategy=framework
+
+
+
+
+
+
And you can add the following bean to your application:
+
+
+
+
+
+
@Bean
+ForwardedHeaderFilter forwardedHeaderFilter() {
+ return new ForwardedHeaderFilter();
+}
+
+
+
+
+
+
+
If you need to manually adjust the URL displayed in the Swagger UI, implement the ServerBaseUrlCustomizer interface. This might be necessary to remove the port number, for example.
+
+
+
+
+
+
@Bean
+public class CustomServerBaseUrlCustomizer implements ServerBaseUrlCustomizer {
+ @Override
+ public String customize(String serverBaseUrl) {
+ try {
+ URL url = new URL(serverBaseUrl);
+ if (url.getHost().contains(".com")) {
+ serverBaseUrl = new URL(url.getProtocol(),url.getHost(),url.getFile()).toString();
+ }
+ } catch (MalformedURLException ex) {
+ // nothing we can do
+ }
+
+ return serverBaseUrl;
+ }
+}
+
+
+
+
+
+
Is @JsonView annotations in Spring MVC APIs supported?
+
+
+
+
Yes
+
+
+
+
+
+
Adding springdoc-openapi-starter-webmvc-ui dependency breaks my public/index.html welcome page
+
+
+
+
If you already have static content on your root, and you don’t want it to be overridden by springdoc-openapi-starter-webmvc-ui configuration, you can just define a custom configuration of the swagger-ui, in order not to override the configuration of your files from in your context-root:
How are endpoints with multiple consuming media types supported?
+
+
+
+
An overloaded method on the same class, with the same HTTP Method and path, will have as a result, only one OpenAPI Operation generated.
+
+
+
In addition, it’s recommended to have the @Operation in the level of one of the overloaded methods. Otherwise it might be overridden if it’s declared many times within the same overloaded method.
+
+
+
+
+
+
How can I get yaml and json (OpenAPI) in compile time?
+
+
+
+
You can use springdoc-openapi-maven-plugin for this functionality:
@Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .components(new Components()
+ .addSecuritySchemes("bearer-key",
+ new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
+}
+
+
+
+
+
+
Differentiation to Springfox project
+
+
+
+
OAS 3 was released in July 2017, and there was no release of springfox to support OAS 3.
+springfox covers for the moment only swagger 2 integration with Spring Boot. The latest release date is June 2018. So, in terms of maintenance there is a big lack of support lately.
+
+
+
We decided to move forward and share the library that we already used on our internal projects, with the community.
+
+
+
The biggest difference with springfox, is that we integrate new features not covered by springfox:
+
+
+
The integration between Spring Boot and OpenAPI 3 standard.
+
+
+
We rely on on swagger-annotations and swagger-ui only official libraries.
+
+
+
We support new features on Spring 5, like spring-webflux with annotated and functional style.
+
+
+
We do our best to answer all the questions and address all issues or enhancement requests
+
+
+
+
+
+
How do I migrate to OpenAPI 3 with springdoc-openapi
+
+
+
+
There is no relation between springdoc-openapi and springfox.If you want to migrate to OpenAPI 3:
+
+
+
Remove all the dependencies and the related code to springfox
If you don’t want to serve the UI from your root path or there is a conflict with an existing configuration, you can just change the following property:
You may have global parameters with Standard OpenAPI description.
+
+
+
If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi , you can use OpenAPI Bean.
+
+
+
You can define common parameters under parameters in the global components section and reference them elsewhere via $ref. You can also define global header parameters.
+
+
+
For this, you can override to OpenAPI Bean, and set the global headers or parameters definition on the components level.
+
+
+
+
+
+
@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"))
+ .addParameters("myHeader1", new Parameter().in("header").schema(new StringSchema()).name("myHeader1")).addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema())))
+ .info(new Info()
+ .title("Petstore API")
+ .version(appVersion)
+ .description("This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.")
+ .termsOfService("http://swagger.io/terms/")
+ .license(new License().name("Apache 2.0").url("http://springdoc.org")));
+}
+
+
+
+
+
+
Are Callbacks supported?
+
+
+
+
Yes
+
+
+
+
+
+
How can I define SecurityScheme ?
+
+
+
+
You can use: @SecurityScheme annotation.
+
+
+
Or you can define it programmatically, by overriding OpenAPI Bean:
+
+
+
+
+
+
@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("SpringShop API").version(appVersion)
+ .license(new License().name("Apache 2.0").url("http://springdoc.org")));
+ }
+
+
+
+
+
+
How can I hide an operation or a controller from documentation ?
+
+
+
+
You can use @io.swagger.v3.oas.annotations.Hidden annotation at @RestController, @RestControllerAdvice and method level
+
+
+
The @Hidden annotation on exception handler methods, is considered when building generic (error) responses from @ControllerAdvice exception handlers.
+
+
+
Or use: @Operation(hidden = true)
+
+
+
+
+
+
How to configure global security schemes?
+
+
+
+
For global SecurityScheme, you can add it inside your own OpenAPI definition:
What is the URL of the swagger-ui, when I set a different context-path?
+
+
+
+
If you use different context-path:
+
+
+
+
+
+
server.servlet.context-path= /foo
+
+
+
+
+
+
The swagger-ui will be available on the following URL:
+
+
+
+
http://server:port/foo/swagger-ui.html
+
+
+
+
+
+
+
+
+
Can I customize OpenAPI object programmatically?
+
+
+
+
You can Define your own OpenAPI Bean: If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi , you can use OpenAPI Bean.
If you need the definitions to appear within a specific group, and respect the conditions specified on the GroupedOpenApi, you can add OpenApiCustomizer to your GroupedOpenApi definition.
Can I use @Parameter inside @Operation annotation?
+
+
+
+
Yes, it’s supported
+
+
+
+
+
+
Why my parameter is marked as required?
+
+
+
+
Any @GetMapping parameters is marked as required, even if @RequestParam is missing.
+
+
+
You can add @Parameter(required=false) annotation if you need different behaviour.
+
+
+
Query parameters with defaultValue specified are marked as required.
+
+
+
+
+
+
How are overloaded methods with the same endpoints, but with different parameters
+
+
+
+
springdoc-openapi renders these methods as a single endpoint. It detects the overloaded endpoints, and generates parameters.schema.oneOf.
+
+
+
+
+
+
What is a proper way to set up Swagger UI to use provided spec.yml?
+
+
+
+
With this property, all the springdoc-openapi auto-configuration beans are disabled:
+
+
+
+
+
+
springdoc.api-docs.enabled=false
+
+
+
+
+
+
Then enable the minimal Beans configuration, by adding this Bean:
+
+
+
+
+
+
@Bean
+SpringDocConfiguration springDocConfiguration(){
+ return new SpringDocConfiguration();
+}
+
+@Bean
+SpringDocConfigProperties springDocConfigProperties() {
+ return new SpringDocConfigProperties();
+}
+
+@Bean
+ObjectMapperProvider objectMapperProvider(SpringDocConfigProperties springDocConfigProperties){
+ return new ObjectMapperProvider(springDocConfigProperties);
+}
+
+
+
+
+
+
+
Then configure, the path of your custom UI yaml file.
+
+
+
+
+
+
springdoc.swagger-ui.url=/api-docs.yaml
+
+
+
+
+
Is there a way to send authorization header through the @Parameter tag?
+
+
+
+
The OpenAPI 3 specification does not allow explicitly adding Authorization header.
+Note: Header parameters named Accept, Content-Type and Authorization are not allowed. To describe these headers
You can use springdoc annotation @ParameterObject.
+
+
+
Request parameter annotated with @ParameterObject will help adding each field of the parameter as a separate request parameter.
+
+
+
This is compatible with Spring MVC request parameters mapping to POJO object.
+
+
+
This annotation does not support nested parameter objects.
+
+
+
POJO object must contain getters for fields with mandatory prefix get. Otherwise, the swagger documentation will not show the fields of the annotated entity.
+
+
+
+
+
+
How can I use the last springdoc-openapi SNAPSHOT ?
+
+
+
+
For testing purposes only, you can test temporarily using the last springdoc-openapi SNAPSHOT
+
+
+
To achieve that, configure your pom.xml file with the following <repositories> section:
Another solution, without using springdoc-openapi MonetaryAmount, would be:
+
+
+
+
+
+
SpringDocUtils.getConfig().replaceWithSchema(MonetaryAmount.class, new ObjectSchema()
+ .addProperties("amount", new NumberSchema()).example(99.96)
+ .addProperties("currency", new StringSchema().example("USD")));
+
+
+
+
+
+
How can i aggregate external endpoints (exposing OPENAPI 3 spec) inside one single application?
+
+
The properties springdoc.swagger-ui.urls.*, are suitable to configure external (/v3/api-docs url).
+For example if you want to agreagte all the endpoints of other services, inside one single application.
+IMPORTANT: Don’t forget that CORS needs to be enabled as well.
+
+
+
+
How can use custom json/yml file instead of generated one ?
+
+
If your file open-api.json, contains the OpenAPI documentation in OpenAPI 3 format.
+Then simply declare: The file name can be anything you want, from the moment your declaration is consistent yaml or json OpenAPI Spec.
+
+
+
+
springdoc.swagger-ui.url=/open-api.json
+
+
+
+
Then the file open-api.json, should be located in: src/main/resources/static
+No additional configuration is needed.
+
+
+
+
How can i enable CSRF support?
+
+
If you are using standard headers.( For example using spring-security headers)
+If the CSRF Token is required, swagger-ui automatically sends the new XSRF-TOKEN during each HTTP REQUEST.
+
+
+
If your XSRF-TOKEN isn’t standards-based, you can use a requestInterceptor to manually capture and attach the latest xsrf token to requests programmatically via spring resource transformer:
Is @PageableDefault supported, to enhance the OpenAPI 3 docuementation?
+
+
Yes, you can use it in conjunction with @ParameterObject annotation.
+Also, the spring-boot spring.data.web. and spring.data.rest.default. properties are supported since v1.4.5
+
+
+
+
How can i make spring security login-endpoint visible ?
+
+
You can use the following property:
+
+
+
+
springdoc.show-login-endpoint=true
+
+
+
+
+
How can i show schema definitions even the schema is not referenced?
The whole idea of springdoc-openapi is to get your documentation the closest to the code, with minimal code changes.
+If the code contains @Deprecated, sprindoc-openapi will consider its schema as Deprecated as well.
+If you want to declare a field on swagger as non deprecated, even with the java code, the field contains @Depreacted,
+You can use the following property that is available since release v1.4.3:
How can i display a method that returns ModelAndView?
+
+
You can use the following property:
+
+
+
+
springdoc.model-and-view-allowed=true
+
+
+
+
+
How can i have pretty-printed output of the OpenApi specification?
+
+
You can use the following property:
+
+
+
+
springdoc.writer-with-default-pretty-printer=true
+
+
+
+
+
How can i define different schemas for the same class?
+
+
Complex objects are always resolved as a reference to a schema defined in components.
+For example let’s consider a Instance class with an workAddress and homeAddress attribute of type Address:
You can customize swagger documentation static resources located in META-INF/resources/webjars/swagger-ui/{swagger.version}/. The list of resources includes:
+
+
+
+
+
index.html
+
+
+
swagger-ui-bundle.js
+
+
+
swagger-ui.css
+
+
+
swagger-ui-standalone-preset.js
+
+
+
swagger-ui.css.map
+
+
+
swagger-ui-bundle.js.map
+
+
+
swagger-ui-standalone-preset.js.map
+
+
+
favicon-32x32.png
+
+
+
+
+
To do this, you need to extend the implementation of SwaggerIndexPageTransformer
+
+
+
+
public class SwaggerCodeBlockTransformer
+ extends SwaggerIndexPageTransformer {
+ // < constructor >
+ @Override
+ public Resource transform(HttpServletRequest request,
+ Resource resource,
+ ResourceTransformerChain transformer)
+ throws IOException {
+ if (resource.toString().contains("swagger-ui.css")) {
+ final InputStream is = resource.getInputStream();
+ final InputStreamReader isr = new InputStreamReader(is);
+ try (BufferedReader br = new BufferedReader(isr)) {
+ final String css = br.lines().collect(Collectors.joining());
+ final byte[] transformedContent = css.replace("old", "new").getBytes();
+ return new TransformedResource(resource, transformedContent);
+ } // AutoCloseable br > isr > is
+ }
+ return super.transform(request, resource, transformer);
+ }
+
+}
+
+
+
+
+
Next, add transformer @Bean to your @Configuration
+
+
+
+
@Configuration
+public class OpenApiConfig {
+ @Bean
+ public SwaggerIndexTransformer swaggerIndexTransformer(
+ SwaggerUiConfigProperties a,
+ SwaggerUiOAuthProperties b,
+ SwaggerUiConfigParameters c,
+ SwaggerWelcomeCommon d) {
+ return new SwaggerCodeBlockTransformer(a, b, c, d);
+ }
+}
+
+
+
+
+
Illustrative example
+
+
+
+
+
+
+
+
+
Is GraalVM supported ?
+
+
The native support available added in spring-boot 3.
+If you have some time, do not hesitate to test it before the next release.
+
+
+
For the OpenAPI REST endpoints, you just need to build your application with the spring native profile.
+
+
+
If you give @OpenAPIDefinition or @SecurityScheme to a class that has no implementation, that class will disappear when you natively compile.
+To avoid this, give the class a @Configuration.
+
+
+
+
@Configuration
+@OpenAPIDefinition(info = @Info(title = "My App", description = "description"))
+public class OpenAPIConfig {
+}
+
+
+
+
+
How to Integrate Open API 3 with Spring project (not Spring Boot)?
+
+
When your application is using spring without (spring-boot), you need to add beans and auto-configuration that are natively provided in spring-boot.
+
+
+
For example, lets assume you want load the swagger-ui in spring-mvc application:
+
+
+
+
+
You mainly, need to add the springdoc-openapi module
If you don’t have the spring-boot and spring-boot-autoconfigure dependencies, you need to add them. And pay attention to the compatibility matrix, between you spring.version and spring-boot.version. For example, in this case (spring.version=5.1.12.RELEASE):
Depending on your module, you can find them on the file: org.springframework.boot.autoconfigure.AutoConfiguration.imports of each springdoc-openapi module.
+
+
+
For groups usage make sure your GroupedOpenApi Beans are scanned.
+
+
+
If additionally, you are using custom context path: /my-servlet-path. Make sure you declare the following property:
+
+
+
+
+
+
spring.mvc.servlet.path=/my-servlet-path
+
+
+
+
+
What is the compatibility matrix of springdoc-openapi with spring-boot ?
+
+
springdoc-openapi 2.x is compatible with spring-boot 3.
+
+
+
In general, you should only pick the last stable version as per today 2.8.9.
+
+
+
More precisely, this the exhaustive list of spring-boot versions against which springdoc-openapi has been built:
+
+
+
+
+
+
+
+
+
Spring Boot Versions
+
Springdoc OpenAPI Versions
+
+
+
3.4.x
+
2.7.x - 2.8.x
+
+
+
3.3.x
+
2.6.x
+
+
+
3.2.x
+
2.3.x - 2.5.x
+
+
+
3.1.x
+
2.2.x
+
+
+
3.0.x
+
2.0.x - 2.1.x
+
+
+
2.7.x, 1.5.x
+
1.6.0+
+
+
+
2.6.x, 1.5.x
+
1.6.0+
+
+
+
2.5.x, 1.5.x
+
1.5.9+
+
+
+
2.4.x, 1.5.x
+
1.5.0+
+
+
+
2.3.x, 1.5.x
+
1.4.0+
+
+
+
2.2.x, 1.5.x
+
1.2.1+
+
+
+
2.0.x, 1.5.x
+
1.0.0+
+
+
+
+
+
+
Why am i getting an error: Swagger UI unable to render definition, when overriding the default spring registered HttpMessageConverter?
+
+
When overriding the default spring-boot registered HttpMessageConverter, you should have ByteArrayHttpMessageConverter registered as well to have proper springdoc-openapi support.
+Order is very important, when registering HttpMessageConverters.
+
+
+
+
+
+
+
Some parameters are not generated in the resulting OpenAPI spec.
+
+
The issue is caused by the changes introduced by Spring-Boot 3.2.0
+in particular for the Parameter Name Discovery.
+This can be fixed by adding the -parameters arg to the Maven Compiler Plugin.
+
+
\ No newline at end of file
diff --git a/docs/favicon.ico b/docs/favicon.ico
new file mode 100644
index 0000000..45468e6
Binary files /dev/null and b/docs/favicon.ico differ
diff --git a/docs/features.html b/docs/features.html
new file mode 100644
index 0000000..dfa5983
--- /dev/null
+++ b/docs/features.html
@@ -0,0 +1,362 @@
+
+
+
+
+
+
+
+Springdoc-openapi Features
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Springdoc-openapi Features
+
+
+
Adding API Information and Security documentation
+
+
The library uses spring-boot application auto-configured packages to scan for the following annotations in spring beans: OpenAPIDefinition and Info.
+These annotations declare, API Information: Title, version, licence, security, servers, tags, security and externalDocs.
+For better performance of documentation generation, declare @OpenAPIDefinition and @SecurityScheme annotations within a spring managed bean.
+
+
+
+
Error Handling for REST using @ControllerAdvice
+
+
To generate documentation automatically, make sure all the methods declare the HTTP Code responses using the annotation: @ResponseStatus
+
+
+
+
Disabling the springdoc-openapi endpoints
+
+
In order to disable the springdoc-openapi endpoint (/v3/api-docs by default) use the following property:
+
+
+
+
# Disabling the /v3/api-docs endpoint
+springdoc.api-docs.enabled=false
+
+
+
+
+
Disabling the swagger-ui
+
+
In order to disable the swagger-ui, use the following property:
+
+
+
+
# Disabling the swagger-ui
+springdoc.swagger-ui.enabled=false
+
+
+
+
+
Swagger-ui configuration
+
+
The library supports the swagger-ui official properties:
You need to declare swagger-ui properties as spring-boot properties.
+All these properties should be declared with the following prefix: springdoc.swagger-ui
+
+
+
+
Selecting the Rest Controllers to include in the documentation
+
+
Additionally, to @Hidden annotation from swagger-annotations, its possible to restrict the generated OpenAPI description using package or path configuration.
+
+
+
For the list of packages to include, use the following property:
+
+
+
+
# Packages to include
+springdoc.packagesToScan=com.package1, com.package2
+
+
+
+
For the list of paths to include, use the following property:
+
+
+
+
# Paths to include
+springdoc.pathsToMatch=/v1, /api/balance/**
+
+
+
+
+
Spring-webflux/WebMvc.fn with Functional Endpoints
+
+
Since version v1.5.0, a functional DSL has been introduced, thanks to this enhancement in the spring-framework: #25938
+
+
+
It’s an alternative functional API to the @RouterOperations annotations.
+
+
+
This is a sample DSL, to generate OpenAPI description to the webflux/WebMvc.fn REST endpoints:
+
+
+
+
@Bean
+RouterFunction<?> routes() {
+ return route().GET("/foo", HANDLER_FUNCTION, ops -> ops
+ .operationId("hello")
+ .parameter(parameterBuilder().name("key1").description("My key1 description"))
+ .parameter(parameterBuilder().name("key2").description("My key2 description"))
+ .response(responseBuilder().responseCode("200").description("This is normal response description"))
+ .response(responseBuilder().responseCode("404").description("This is another response description"))
+ ).build();
+}
+
Since version v1.3.8, the support of functional endpoints has been added.
+Two main annotations have been added for this purpose: @RouterOperations and @RouterOperation.
+
+
+
Only REST APIs with the @RouterOperations and @RouterOperation can be displayed on the swagger-ui.
+
+
+
+
+
@RouterOperation: It can be used alone, if the Router bean contains one single route related to the REST API..
+When using @RouterOperation, its not mandatory to fill the path
+
+
+
@RouterOperation, can reference directly a spring Bean (beanClass property) and the underlying method (beanMethod property): Springdoc-openapi, will then inspect this method and the swagger annotations on this method level.
@RouterOperation, contains the @Operation annotation.
+The @Operation annotation can also be placed on the bean method level if the property beanMethod is declared.
+
+
+
+
+
+
+
+
+
+
+Don’t forget to set operationId which is mandatory.
+
@RouterOperations: This annotation should be used if the Router bean contains multiple routes.
+When using RouterOperations, its mandatory to fill the path property.
+
+
+
A @RouterOperations, contains many @RouterOperation.
All the documentations filled using @RouterOperation, might be completed by the router function data.
+For that, @RouterOperation fields must help identify uniquely the concerned route.
+springdoc-openpi scans for a unique route related to a @RouterOperation annotation, using on the following criteria:
+
+
+
+
+
by path
+
+
+
by path and RequestMethod
+
+
+
by path and produces
+
+
+
by path and consumes
+
+
+
by path and RequestMethod and produces
+
+
+
by path and RequestMethod and consumes
+
+
+
by path and produces and consumes
+
+
+
by path and RequestMethod and produces and consumes
+
+
+
+
+
Some code samples are available on GITHUB of demos:
+
+
\ No newline at end of file
diff --git a/docs/fonts/FontAwesome.otf b/docs/fonts/FontAwesome.otf
new file mode 100755
index 0000000..401ec0f
Binary files /dev/null and b/docs/fonts/FontAwesome.otf differ
diff --git a/docs/fonts/fontawesome-webfont.eot b/docs/fonts/fontawesome-webfont.eot
new file mode 100755
index 0000000..e9f60ca
Binary files /dev/null and b/docs/fonts/fontawesome-webfont.eot differ
diff --git a/docs/fonts/fontawesome-webfont.svg b/docs/fonts/fontawesome-webfont.svg
new file mode 100755
index 0000000..855c845
--- /dev/null
+++ b/docs/fonts/fontawesome-webfont.svg
@@ -0,0 +1,2671 @@
+
+
+
diff --git a/docs/fonts/fontawesome-webfont.ttf b/docs/fonts/fontawesome-webfont.ttf
new file mode 100755
index 0000000..35acda2
Binary files /dev/null and b/docs/fonts/fontawesome-webfont.ttf differ
diff --git a/docs/fonts/fontawesome-webfont.woff b/docs/fonts/fontawesome-webfont.woff
new file mode 100755
index 0000000..400014a
Binary files /dev/null and b/docs/fonts/fontawesome-webfont.woff differ
diff --git a/docs/fonts/fontawesome-webfont.woff2 b/docs/fonts/fontawesome-webfont.woff2
new file mode 100755
index 0000000..4d13fc6
Binary files /dev/null and b/docs/fonts/fontawesome-webfont.woff2 differ
diff --git a/docs/getting-started.html b/docs/getting-started.html
new file mode 100644
index 0000000..448bf29
--- /dev/null
+++ b/docs/getting-started.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+Getting Started
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Getting Started
+
+
+
For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed)
This will automatically deploy swagger-ui to a spring-boot application:
+
+
+
+
+
Documentation will be available in HTML format, using the official swagger-ui jars
+
+
+
The Swagger UI page will then be available at http://server:port/context-path/swagger-ui.html and the OpenAPI description will be available at the following url for json format: http://server:port/context-path/v3/api-docs
+
+
+
+
server: The server name or IP
+
+
+
port: The server port
+
+
+
context-path: The context path of the application
+
+
+
+
+
+
Documentation will be available in yaml format as well, on the following path : /v3/api-docs.yaml
+
+
+
+
+
+
+
+
+
+
+For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file: .
+
+springdoc-openapi v1.8.0 is the latest Open Source release supporting Spring Boot 2.x and 1.x.
+An extended support for springdoc-openapi v1 project is now available for organizations that need support beyond 2023.
+For more details, feel free to reach out: sales@springdoc.org
+
+
+
+
+
+
springdoc-openapi is on Open Collective. If you ❤️ this project consider becoming a sponsor.
springdoc-openapi java library helps to automate the generation of API documentation using spring boot projects.
+springdoc-openapi works by examining an application at runtime to infer API semantics based on spring configurations, class structure and various annotations.
+
+
+
Automatically generates documentation in JSON/YAML and HTML format APIs.
+This documentation can be completed by comments using swagger-api annotations.
+
+
+
This library supports:
+
+
+
+
+
OpenAPI 3
+
+
+
Spring-boot v3 (Java 17 & Jakarta EE 9)
+
+
+
JSR-303, specifically for @NotNull, @Min, @Max, and @Size.
+
+
+
Swagger-ui
+
+
+
OAuth 2
+
+
+
GraalVM native images
+
+
+
+
+
The following video introduces the Library:
+
+
+
+
+
+
+
+
This is a community-based project, not maintained by the Spring Framework Contributors (Pivotal).
+
+
+
+
+
2. Getting Started
+
+
+
For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed)
This will automatically deploy swagger-ui to a spring-boot application:
+
+
+
+
+
Documentation will be available in HTML format, using the official swagger-ui jars
+
+
+
The Swagger UI page will then be available at http://server:port/context-path/swagger-ui.html and the OpenAPI description will be available at the following url for json format: http://server:port/context-path/v3/api-docs
+
+
+
+
server: The server name or IP
+
+
+
port: The server port
+
+
+
context-path: The context path of the application
+
+
+
+
+
+
Documentation will be available in yaml format as well, on the following path : /v3/api-docs.yaml
+
+
+
+
+
+
+
+
+
+
+For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file: .
+
The support for Spring Hateoas is available using the dependency springdoc-openapi-hateoas.
+
+
+
The projects that use spring-boot-starter-hateoas should use:
+
+
+
+
+
springdoc-openapi-starter-webmvc-api if they need only the access to the OpenAPI endpoints
+
+
+
OR springdoc-openapi-starter-webmvc-ui, if they need also the access to the swagger-ui
+
+
+
+
+
+
3.5. Spring Data Rest support
+
+
springdoc-openapi project supports spring-boot-starter-data-rest types like: @RepositoryRestResource and QuerydslPredicate annotations.
+
+
+
The projects that use spring-boot-starter-data-rest should use:
+
+
+
+
+
springdoc-openapi-starter-webmvc-api if they need only the access to the OpenAPI endpoints
+
+
+
OR springdoc-openapi-starter-webmvc-ui, if they need also the access to the swagger-ui
+
+
+
+
+
+
3.6. Spring Security support
+
+
springdoc-openapi helps ignoring @AuthenticationPrincipal type in case it is used on REST Controllers.
+
+
+
springdoc-openapi supports also exposing Oauth2 endpoints of spring-security-oauth2-authorization-server.
+
+
+
The projects that use spring-boot-starter-security or spring-security-oauth2-authorization-server should use:
+
+
+
+
+
springdoc-openapi-starter-webmvc-api if they depend on spring-boot-starter-web and they only need the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webmvc-ui, if they depend on spring-boot-starter-web and they also need the access to the swagger-ui.
+
+
+
OR springdoc-openapi-starter-webflux-api if they depend on spring-boot-starter-webflux and they only the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webflux-ui, if they depend on spring-boot-starter-webflux and they also need the access to the swagger-ui.
+
+
+
+
+
+
3.7. Actuator support
+
+
+
+
In order to display spring-boot-actuator endpoints, simply add the following property:
+
+
+
+
+
+
springdoc.show-actuator=true
+
+
+
+
Starting from the release 1.5.1, it will be possible to expose the swagger-ui and the openapi endpoints on actuator port.
+
+
+
+
+
+
+
+
+The actuator management port has to be different from the application port.
+
+
+
+
+
+
To expose the swagger-ui, on the management port, you should set
+
+
+
+
springdoc.use-management-port=true
+# This property enables the openapi and swagger-ui endpoints to be exposed beneath the actuator base path.
+management.endpoints.web.exposure.include=openapi, swagger-ui
+
+
+
+
Once enabled, you should also be able to see the springdoc-openapi endpoints under: (host and port depends on your settings)
+- http://serverName:managementPort/actuator
For the example, you should also be able to see the springdoc-openapi endpoints:
+
+
+
+
+
http://serverName:9090/actuator
+
+
+
http://serverName:9090/actuator/swagger-ui
+
+
+
http://serverName:9090/actuator/openapi
+
+
+
+
+
All the path springdoc-openapi properties are not applicable when springdoc.use-management-port=true.
+
+
+
+
+
+
+
+
+If you want to reach the application endpoints, from the swagger-ui deployed beneath the actuator base path, using a different port from your application, CORS for your endpoints on your application level should be enabled.
+
+
+
+
+
+
Additionally, it is also possible to combine this property, with the existing property to display the actuator endpoints in the swagger-ui.
+
+
+
+
springdoc.show-actuator=true
+
+
+
+
Once enabled:
+- A dedicated group for the actuator endpoints will be by default added.
+- If no group is defined for the application, a default one will be added.
+
+
+
The swagger-ui will be then accessible through the actuator port:
If the management port is different from the application port and springdoc.use-management-port is not defined but springdoc.show-actuator is set to true:
+
+
+
+
+
The swagger-ui will be then accessible through the application port. For example: http://serverName:applicationPort/swagger-ui.html
+
+
+
A dedicated group for the actuator endpoints will be by default added.
+
+
+
If no group is defined for the application, a default one will be added.
+
+
+
+
+
+
+
+
+
+
+If you want to reach the actuator endpoints for this case (different port from your application), CORS for your actuator endpoints should be enabled.
+
+
+
+
+
+
Note: The naming of these new endpoints beneath the actuator base path cannot be customized for now.
+
+
+
+
3.8. Spring Cloud Function Web support
+
+
spring-cloud-function-web exposes Java Function as REST endpoint automatically.
+* Since version v1.6.3, the support of functional endpoints has been added.
+
+
+
+
+
These starters will display the OpenAPI description of the spring-cloud-function-web endpoints.
+
+
+
+
If you are using spring-web, simply add the springdoc-openapi-starter-webmvc-ui dependency.
+
+
+
If you are using spring-webflux, simply add the springdoc-openapi-starter-webflux-ui dependency.
+
+
+
+
+
+
+
+
The customisation of the output can be achieved programmatically through OpenApiCustomizer or with the annotations: @RouterOperations and @RouterOperation.
+For annotation usage, you have:
+* @RouterOperation: It can be used alone, if the customisation is related to a single REST API.
+When using @RouterOperation, it’s not mandatory to fill the path
+
+
+
+
+
@RouterOperation, contains the @Operation annotation.
+The @Operation annotation can also be placed on the bean method level if the property beanMethod is declared.
+
+
+
+
+
+
+
+
+
+
+Don’t forget to set operationId which is mandatory.
+
@RouterOperations: This annotation should be used to describe the multiple REST APIs exposed by spring-cloud-function-web.
+When using RouterOperations, it’s mandatory to fill the method property.
+
+
+
A @RouterOperations, contains many @RouterOperation.
springdoc-openapi-starter-webmvc-api if they depend on spring-boot-starter-web and they only need the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webmvc-ui, if they depend on spring-boot-starter-web and they also need the access to the swagger-ui.
+
+
+
OR springdoc-openapi-starter-webflux-api if they depend on spring-boot-starter-webflux and they only the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webflux-ui, if they depend on spring-boot-starter-webflux and they also need the access to the swagger-ui.
+
+
+
+
+
+
3.11. Javadoc support
+
+
springdoc-openapi can introspect Javadoc annotations and comments:
+
+
+
+
+
The javadoc comment of a method: is resolved as the @Operation description
+
+
+
@return : is resolved as the @Operation response description
+
+
+
The javadoc comment of an attribute: is resolved as '@Schema' description for this field.
+
+
+
+
+
The projects that needs Javadoc support should use:
+
+
+
+
+
springdoc-openapi-starter-webmvc-api if they depend on spring-boot-starter-web and they only need the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webmvc-ui, if they depend on spring-boot-starter-web and they also need the access to the swagger-ui.
+
+
+
OR springdoc-openapi-starter-webflux-api if they depend on spring-boot-starter-webflux and they only the access to the OpenAPI endpoints.
+
+
+
OR springdoc-openapi-starter-webflux-ui, if they depend on spring-boot-starter-webflux and they also need the access to the swagger-ui.
+
+
+
+
+
+
+
+
+
+
+In addition, your project should add therapi-runtime-javadoc to read Javadoc comments at runtime.
+Ensure that you add it as well as its annotation processor to your project’s dependencies. Otherwise, the Javadoc support will fail silently.
+
+If both a swagger-annotation description and a javadoc comment are present. The value of the swagger-annotation description will be used.
+
+
+
+
+
+
+
3.12. Springdoc-openapi BOM
+
+
Starting from version v2.8.7, springdoc-openapi provides a BOM (Bill of Materials) to manage the dependencies of the project.
+You can declare it in your project as follows:
4.1. Adding API Information and Security documentation
+
+
The library uses spring-boot application auto-configured packages to scan for the following annotations in spring beans: OpenAPIDefinition and Info.
+These annotations declare, API Information: Title, version, licence, security, servers, tags, security and externalDocs.
+For better performance of documentation generation, declare @OpenAPIDefinition and @SecurityScheme annotations within a spring managed bean.
+
+
+
+
4.2. Error Handling for REST using @ControllerAdvice
+
+
To generate documentation automatically, make sure all the methods declare the HTTP Code responses using the annotation: @ResponseStatus
+
+
+
+
4.3. Disabling the springdoc-openapi endpoints
+
+
In order to disable the springdoc-openapi endpoint (/v3/api-docs by default) use the following property:
+
+
+
+
# Disabling the /v3/api-docs endpoint
+springdoc.api-docs.enabled=false
+
+
+
+
+
4.4. Disabling the swagger-ui
+
+
In order to disable the swagger-ui, use the following property:
+
+
+
+
# Disabling the swagger-ui
+springdoc.swagger-ui.enabled=false
+
+
+
+
+
4.5. Swagger-ui configuration
+
+
The library supports the swagger-ui official properties:
You need to declare swagger-ui properties as spring-boot properties.
+All these properties should be declared with the following prefix: springdoc.swagger-ui
+
+
+
+
4.6. Selecting the Rest Controllers to include in the documentation
+
+
Additionally, to @Hidden annotation from swagger-annotations, its possible to restrict the generated OpenAPI description using package or path configuration.
+
+
+
For the list of packages to include, use the following property:
+
+
+
+
# Packages to include
+springdoc.packagesToScan=com.package1, com.package2
+
+
+
+
For the list of paths to include, use the following property:
+
+
+
+
# Paths to include
+springdoc.pathsToMatch=/v1, /api/balance/**
+
+
+
+
+
4.7. Spring-webflux/WebMvc.fn with Functional Endpoints
+
+
Since version v1.5.0, a functional DSL has been introduced, thanks to this enhancement in the spring-framework: #25938
+
+
+
It’s an alternative functional API to the @RouterOperations annotations.
+
+
+
This is a sample DSL, to generate OpenAPI description to the webflux/WebMvc.fn REST endpoints:
+
+
+
+
@Bean
+RouterFunction<?> routes() {
+ return route().GET("/foo", HANDLER_FUNCTION, ops -> ops
+ .operationId("hello")
+ .parameter(parameterBuilder().name("key1").description("My key1 description"))
+ .parameter(parameterBuilder().name("key2").description("My key2 description"))
+ .response(responseBuilder().responseCode("200").description("This is normal response description"))
+ .response(responseBuilder().responseCode("404").description("This is another response description"))
+ ).build();
+}
+
Since version v1.3.8, the support of functional endpoints has been added.
+Two main annotations have been added for this purpose: @RouterOperations and @RouterOperation.
+
+
+
Only REST APIs with the @RouterOperations and @RouterOperation can be displayed on the swagger-ui.
+
+
+
+
+
@RouterOperation: It can be used alone, if the Router bean contains one single route related to the REST API..
+When using @RouterOperation, its not mandatory to fill the path
+
+
+
@RouterOperation, can reference directly a spring Bean (beanClass property) and the underlying method (beanMethod property): Springdoc-openapi, will then inspect this method and the swagger annotations on this method level.
@RouterOperation, contains the @Operation annotation.
+The @Operation annotation can also be placed on the bean method level if the property beanMethod is declared.
+
+
+
+
+
+
+
+
+
+
+Don’t forget to set operationId which is mandatory.
+
@RouterOperations: This annotation should be used if the Router bean contains multiple routes.
+When using RouterOperations, its mandatory to fill the path property.
+
+
+
A @RouterOperations, contains many @RouterOperation.
All the documentations filled using @RouterOperation, might be completed by the router function data.
+For that, @RouterOperation fields must help identify uniquely the concerned route.
+springdoc-openpi scans for a unique route related to a @RouterOperation annotation, using on the following criteria:
+
+
+
+
+
by path
+
+
+
by path and RequestMethod
+
+
+
by path and produces
+
+
+
by path and consumes
+
+
+
by path and RequestMethod and produces
+
+
+
by path and RequestMethod and consumes
+
+
+
by path and produces and consumes
+
+
+
by path and RequestMethod and produces and consumes
+
+
+
+
+
Some code samples are available on GITHUB of demos:
Boolean. To make spring security login-endpoint visible.
+
+
+
springdoc.pre-loading-locales
+
+
List of Strings. The list of locales to load OpenAPI on application startup (comma separated). If not specified, it will preload with the default Locale.
+
+
+
springdoc.writer-with-order-by-keys
+
false
+
Boolean. Enable a deterministic/alphabetical ordering.
+
+
+
springdoc.use-management-port
+
false
+
Boolean. To expose the swagger-ui on the actuator management port.
+
+
+
springdoc.disable-i18n
+
false
+
Boolean. To disable automatic translation using i18n.
+
+
+
springdoc.show-spring-cloud-functions
+
true
+
Boolean. To display the spring-cloud-function web endpoints.
+
+
+
springdoc.enable-groovy
+
true
+
Boolean. To enable Groovy support.
+
+
+
springdoc.enable-spring-security
+
true
+
Boolean. To enable spring-security support.
+
+
+
springdoc.enable-kotlin
+
true
+
Boolean. To enable Kotlin support.
+
+
+
springdoc.enable-hateoas
+
true
+
Boolean. To enable spring-hateoas support.
+
+
+
springdoc.enable-data-rest
+
true
+
Boolean. To enable spring-data-rest support.
+
+
+
springdoc.api-docs.version
+
openapi_3_1
+
String. To choose OpenAPI 3.0 or OpenAPI 3.1 (using the value OPENAPI_3_1).
+
+
+
springdoc.default-flat-param-object
+
false
+
Boolean. To default flatten parameter.
+
+
+
springdoc.default-support-form-data
+
false
+
Boolean. To default set parameters to form data when specifying api to accept form data.
+
+
+
springdoc.nullable-request-parameter-enabled
+
true
+
Boolean. To default Enable Support for nullable request parameters in Kotlin.
+
+
+
springdoc.show-oauth2-endpoints
+
false
+
Boolean. To make spring security oauth2-endpoint visible.
+
+
+
springdoc.api-docs.resolve-extensions-properties
+
false
+
Boolean. To enable support of spring property resolver for @ExtensionProperty.
+
+
+
springdoc.enable-default-api-docs
+
true
+
Boolean. To enable default OpenAPI endpoint /v3/api-docs.
+
+
+
springdoc.trim-kotlin-indent
+
false
+
Boolean. Adjust indentation when parsing the @Operation annotation in Kotlin.
+
+
+
springdoc.allowed-locales
+
+
List of Strings. The list of allowed locales for OpenAPI (comma separated, for example US,fr-CA).
+
+
+
springdoc.enable-extra-schemas
+
true
+
Boolean. To enable default support for extra Schemas, from java.time package like LocalTime, Duration, but also other Java classes like java.util.Locale or java.nio.charset.Charset
+
+
+
springdoc.explicit-object-schema
+
false
+
Boolean. Set explicit-object-schema to true to always include type: object in the schema, or to false to omit type: object.
+
+
+
springdoc.use-arbitrary-schemas
+
false
+
Boolean. When set to true, schemas without a defined type will be deserialized as an ArbitrarySchema (with no type), instead of an ObjectSchema with type: object.
+
+
+
+
+
+
5.2. swagger-ui properties
+
+
+
+
The support of the swagger-ui properties is available on springdoc-openapi. See Official documentation.
+
+
+
You can use the same swagger-ui properties in the documentation as Spring Boot properties.
+
+
+
+
+
+
+
+
+
+
+All these properties should be declared with the following prefix: springdoc.swagger-ui
+
+
+
+
+
+
+
+
+
+
+
+
+
Parameter name
+
Default Value
+
Description
+
+
+
+
+
springdoc.swagger-ui.path
+
/swagger-ui.html
+
String, For custom path of the swagger-ui HTML documentation.
+
+
+
springdoc.swagger-ui.enabled
+
true
+
Boolean. To disable the swagger-ui endpoint (/swagger-ui.html by default).
+
+
+
springdoc.swagger-ui.configUrl
+
/v3/api-docs/swagger-config
+
String. URL to fetch external configuration document from.
+
+
+
springdoc.swagger-ui.layout
+
BaseLayout
+
String. The name of a component available via the plugin system to use as the top-level layout for Swagger UI.
+
+
+
springdoc.swagger-ui.validatorUrl
+
+
By default, Swagger UI does not validate specs. You can use this parameter to set a validator URL, for example for against swagger.io’s online validator.
+
+
+
springdoc.swagger-ui.tryItOutEnabled
+
false
+
Boolean. Controls whether the "Try it out" section should be enabled by default.
+
+
+
springdoc.swagger-ui.filter
+
false
+
Boolean OR String. If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be Boolean to enable or disable, or a string, in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
+
+
+
springdoc.swagger-ui.operationsSorter
+
+
Function=(a ⇒ a). Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
+
+
+
springdoc.swagger-ui.tagsSorter
+
+
Function=(a ⇒ a). Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function see Array.prototype.sort() to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger UI.
+
+
+
springdoc.swagger-ui.oauth2RedirectUrl
+
/swagger-ui/oauth2-redirect.html
+
String. OAuth redirect URL.
+
+
+
springdoc.swagger-ui.displayOperationId
+
false
+
Boolean. Controls the display of operationId in operations list. The default is false.
+
+
+
springdoc.swagger-ui.displayRequestDuration
+
false
+
Boolean. Controls the display of the request duration (in milliseconds) for "Try it out" requests.
Number. The default expansion depth for models (set to -1 completely hide the models).
+
+
+
springdoc.swagger-ui.defaultModelExpandDepth
+
1
+
Number. The default expansion depth for the model on the model-example section.
+
+
+
springdoc.swagger-ui.defaultModelRendering
+
+
String=["example"*, "model"]. Controls how the model is shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.)
+
+
+
springdoc.swagger-ui.docExpansion
+
+
String=["list"*, "full", "none"]. Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing).
+
+
+
springdoc.swagger-ui.maxDisplayedTags
+
+
Number. If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
+
+
+
springdoc.swagger-ui.showExtensions
+
false
+
Boolean. Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema.
+
+
+
springdoc.swagger-ui.url
+
+
String.To configure, the path of a custom OpenAPI file . Will be ignored if urls is used.
+
+
+
springdoc.swagger-ui.showCommonExtensions
+
false
+
Boolean. Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields and values for Parameters.
+
+
+
springdoc.swagger-ui.supportedSubmitMethods
+
+
Array=[get, put, post, delete, options, head, patch, trace]. List of HTTP methods that have the "Try it out" feature enabled. An empty array disables "Try it out" for all operations. This does not filter the operations from the display.
+
+
+
springdoc.swagger-ui.queryConfigEnabled
+
false
+
Boolean. Disabled since v1.6.0. This parameter enables (legacy) overriding configuration parameters via URL search params. See security advisory before enabling this feature.
String. Additional query parameters added to authorizationUrl and tokenUrl.
+
+
+
springdoc.swagger-ui.disable-swagger-default-url
+
false
+
Boolean. To disable the swagger-ui default petstore url. (Available since v1.4.1).
+
+
+
springdoc.swagger-ui.urls[0].url
+
+
URL. The url of the swagger group, used by Topbar plugin. URLs must be unique among all items in this array, since they’re used as identifiers.
+
+
+
springdoc.swagger-ui.urls[0].name
+
+
String. The name of the swagger group, used by Topbar plugin. Names must be unique among all items in this array, since they’re used as identifiers.
+
+
+
springdoc.swagger-ui.urlsPrimaryName
+
+
String. The name of the swagger group which will be displayed when Swagger UI loads.
+
+
+
springdoc.swagger-ui.oauth.clientId
+
+
String. Default clientId. MUST be a string.
+
+
+
springdoc.swagger-ui.oauth.clientSecret
+
+
String. Default clientSecret. Never use this parameter in your production environment. It exposes crucial security information. This feature is intended for dev/test environments only.
+
+
+
springdoc.swagger-ui.oauth.realm
+
+
String. realm query parameter (for OAuth 1) added to authorizationUrl and tokenUrl.
+
+
+
springdoc.swagger-ui.oauth.appName
+
+
String. OAuth application name, displayed in authorization popup.
+
+
+
springdoc.swagger-ui.oauth.scopeSeparator
+
+
String. OAuth scope separator for passing scopes, encoded before calling, default value is a space (encoded value %20).
+
+
+
springdoc.swagger-ui.csrf.enabled
+
false
+
Boolean. To enable CSRF support
+
+
+
springdoc.swagger-ui.csrf.use-local-storage
+
false
+
Boolean. To get the CSRF token from the Local Storage.
+
+
+
springdoc.swagger-ui.csrf.use-session-storage
+
false
+
Boolean. To get the CSRF token from the Session Storage.
+
+
+
springdoc.swagger-ui.csrf.cookie-name
+
XSRF-TOKEN
+
String. Optional CSRF, to set the CSRF cookie name.
+
+
+
springdoc.swagger-ui.csrf.header-name
+
X-XSRF-TOKEN
+
String. Optional CSRF, to set the CSRF header name.
+
+
+
springdoc.swagger-ui.syntaxHighlight.activated
+
true
+
Boolean. Whether syntax highlighting should be activated or not.
+
+
+
springdoc.swagger-ui.syntaxHighlight.theme
+
agate
+
String. String=["agate"*, "arta", "monokai", "nord", "obsidian", "tomorrow-night"]. Highlight.js syntax coloring theme to use. (Only these 6 styles are available.)
Boolean. Only activated for the accessCode flow. During the authorization_code request to the tokenUrl, pass the Client Password using the HTTP Basic Authentication scheme (Authorization header with Basic base64encode(client_id + client_secret)).
Boolean.Only applies to authorizatonCode flows. Proof Key for Code Exchange brings enhanced security for OAuth public clients.
+
+
+
springdoc.swagger-ui.persistAuthorization
+
false
+
Boolean. If set to true, it persists authorization data and it would not be lost on browser close/refresh
+
+
+
springdoc.swagger-ui.use-root-path
+
false
+
Boolean. If set to true, the swagger-ui will be accessible from the application root path directly.
+
+
+
+
+
+
+
+
+
+
+
6. Springdoc-openapi Plugins
+
+
+
6.1. Maven plugin
+
+
The aim of springdoc-openapi-maven-plugin is to generate json and yaml OpenAPI description during build time.
+The plugin works during integration-tests phase, and generate the OpenAPI description.
+The plugin works in conjunction with spring-boot-maven plugin.
+
+
+
You can test it during the integration tests phase using the maven command:
+
+
+
+
mvn verify
+
+
+
+
In order to use this functionality, you need to add the plugin declaration on the plugins section of your pom.xml:
All the modules have been renamed.
+springdoc-openapi-starter-common integrates many spring modules support in order to hide the maximum of complexity.
+It allows the support out of the box for Actuator / Spring Cloud Function / Spring Data Rest/ Spring Native/ Spring Hateoas / Spring Securtiy / Kotlin/ Javadoc.
+
+
+
The following table describes the main modules changes:
+
+
+
+
+
+
+
+
+
+
springdoc-openapi-v1
+
springdoc-openapi-v2
+
Description
+
+
+
+
+
springdoc-openapi-common
+
springdoc-openapi-starter-common
+
Includes foundation springdoc-openapi features
+
+
+
springdoc-openapi-data-rest
+
springdoc-openapi-starter-common
+
For Spring Data Rest support
+
+
+
springdoc-openapi-groovy
+
springdoc-openapi-starter-common
+
For Groovy support
+
+
+
springdoc-openapi-hateoas
+
springdoc-openapi-starter-common
+
For Spring Hateoas support
+
+
+
springdoc-openapi-javadoc
+
springdoc-openapi-starter-common
+
For Javadoc support
+
+
+
springdoc-openapi-kotlin
+
springdoc-openapi-starter-common
+
For Kotlin support
+
+
+
springdoc-openapi-security
+
springdoc-openapi-starter-common
+
For Spring Security support
+
+
+
springdoc-openapi-webmvc-core
+
springdoc-openapi-starter-webmvc-api
+
For Spring WebMvc support
+
+
+
springdoc-openapi-webflux-core
+
springdoc-openapi-starter-webflux-api
+
For Spring WebFlux support
+
+
+
springdoc-openapi-ui
+
springdoc-openapi-starter-webmvc-ui
+
For using the Swagger-UI in a Spring WebMvc context
+
+
+
springdoc-openapi-webflux-ui
+
springdoc-openapi-starter-webflux-ui
+
For using the Swagger-UI in a Spring WebFlux context
Replace swagger 2 annotations with swagger 3 annotations (it is already included with springdoc-openapi-starter-webmvc-ui dependency).
+Package for swagger 3 annotations is io.swagger.v3.oas.annotations.
+
+
+
+
@Api → @Tag
+
+
+
@ApiIgnore → @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
If issues are not created by the end of the month, the remaining ones are lost.
+
+
+
+
+
+
+
+
12. Special Thanks
+
+
+
+
+
Thank you to The Spring Team for sharing all relevant resources around Spring projects.
+
+
+
Thanks a lot JetBrains for supporting springdoc-openapi project.
+
+
+
+
+
+
+
+
+
+
+
+
13. F.A.Q
+
+
+
13.1. How can I define multiple OpenAPI definitions in one Spring Boot project?
+
+
You can define your own groups of API based on the combination of: API paths and packages to scan. Each group should have a unique groupName.
+The OpenAPI description of this group, will be available by default on:
13.20. Can springdoc-openapi generate API only for @RestController?
+
+
+
+
@RestController is equivalent to @Controller + @RequestMapping on the type level.
+
+
+
For some legacy apps, we are constrained to still support both.
+
+
+
If you need to hide the @Controller on the type level, in this case, you can use: @Hidden on controller level.
+
+
+
Please note this annotation can be also used to hide some methods from the generated documentation.
+
+
+
+
+
+
13.21. Are the following validation annotations supported : @NotEmpty@NotBlank@PositiveOrZero@NegativeOrZero?
+
+
+
+
Yes
+
+
+
+
+
+
13.22. How can I map Pageable (spring-data-commons) object to correct URL-Parameter in Swagger UI?
+
+
The support for Pageable of spring-data-commons is available out-of-the box since springdoc-openapi v1.6.0.
+For this, you have to combine @ParameterObject annotation with the Pageable type.
+
+
+
Before springdoc-openapi v1.6.0:
+
+
+
+
+
You can use as well @ParameterObject instead of @PageableAsQueryParam for HTTP GET methods.
Another solution, is to configure Pageable manually:
+
+
+
+
you will have to declare the explicit mapping of Pageable fields as Query Params and add the @Parameter(hidden = true) Pageable pageable on your pageable parameter.
+
+
+
You should also, declare the annotation @PageableAsQueryParam provided by springdoc-openapi on the method level, or declare your own if need to define your custom description, defaultValue, …
+
+
+
+
+
+
+
+
If you want to disable the support of spring Pageable Type, you can use:
13.24. How can I deploy springdoc-openapi-starter-webmvc-ui behind a reverse proxy?
+
+
+
+
If your application is running behind a proxy, a load-balancer or in the cloud, the request information (like the host, port, scheme…) might change along the way. Your application may be running on 10.10.10.10:8080, but HTTP clients should only see example.org.
+
+
+
RFC7239 "Forwarded Headers" defines the Forwarded HTTP header; proxies can use this header to provide information about the original request. You can configure your application to read those headers and automatically use that information when creating links and sending them to clients in HTTP 302 responses, JSON documents or HTML pages. There are also non-standard headers, like X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, and X-Forwarded-Prefix.
+
+
+
If the proxy adds the commonly used X-Forwarded-For and X-Forwarded-Proto headers, setting server.forward-headers-strategy to NATIVE is enough to support those. With this option, the Web servers themselves natively support this feature; you can check their specific documentation to learn about specific behavior.
+
+
+
You need to make sure the following header is set in your reverse proxy configuration: X-Forwarded-Prefix
+
+
+
For example, using Apache 2, configuration:
+
+
+
+
+
+
RequestHeader set X-Forwarded-Prefix "/custom-path"
+
+
+
+
+
+
Then, in your Spring Boot application make sure your application handles this header: X-Forwarded-For. There are two ways to achieve this:
+
+
+
+
+
+
server.use-forward-headers=true
+
+
+
+
+
+
If this is not enough, Spring Framework provides a ForwardedHeaderFilter. You can register it as a Servlet Filter in your application by setting server.forward-headers-strategy is set to FRAMEWORK.
+
+
+
Since Spring Boot 2.2, this is the new property to handle reverse proxy headers:
+
+
+
+
+
+
server.forward-headers-strategy=framework
+
+
+
+
+
+
And you can add the following bean to your application:
+
+
+
+
+
+
@Bean
+ForwardedHeaderFilter forwardedHeaderFilter() {
+ return new ForwardedHeaderFilter();
+}
+
+
+
+
+
+
+
If you need to manually adjust the URL displayed in the Swagger UI, implement the ServerBaseUrlCustomizer interface. This might be necessary to remove the port number, for example.
+
+
+
+
+
+
@Bean
+public class CustomServerBaseUrlCustomizer implements ServerBaseUrlCustomizer {
+ @Override
+ public String customize(String serverBaseUrl) {
+ try {
+ URL url = new URL(serverBaseUrl);
+ if (url.getHost().contains(".com")) {
+ serverBaseUrl = new URL(url.getProtocol(),url.getHost(),url.getFile()).toString();
+ }
+ } catch (MalformedURLException ex) {
+ // nothing we can do
+ }
+
+ return serverBaseUrl;
+ }
+}
+
+
+
+
+
+
13.25. Is @JsonView annotations in Spring MVC APIs supported?
+
+
+
+
Yes
+
+
+
+
+
+
13.26. Adding springdoc-openapi-starter-webmvc-ui dependency breaks my public/index.html welcome page
+
+
+
+
If you already have static content on your root, and you don’t want it to be overridden by springdoc-openapi-starter-webmvc-ui configuration, you can just define a custom configuration of the swagger-ui, in order not to override the configuration of your files from in your context-root:
13.30. How are endpoints with multiple consuming media types supported?
+
+
+
+
An overloaded method on the same class, with the same HTTP Method and path, will have as a result, only one OpenAPI Operation generated.
+
+
+
In addition, it’s recommended to have the @Operation in the level of one of the overloaded methods. Otherwise it might be overridden if it’s declared many times within the same overloaded method.
+
+
+
+
+
+
13.31. How can I get yaml and json (OpenAPI) in compile time?
+
+
+
+
You can use springdoc-openapi-maven-plugin for this functionality:
@Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .components(new Components()
+ .addSecuritySchemes("bearer-key",
+ new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
+}
+
+
+
+
+
+
13.35. Differentiation to Springfox project
+
+
+
+
OAS 3 was released in July 2017, and there was no release of springfox to support OAS 3.
+springfox covers for the moment only swagger 2 integration with Spring Boot. The latest release date is June 2018. So, in terms of maintenance there is a big lack of support lately.
+
+
+
We decided to move forward and share the library that we already used on our internal projects, with the community.
+
+
+
The biggest difference with springfox, is that we integrate new features not covered by springfox:
+
+
+
The integration between Spring Boot and OpenAPI 3 standard.
+
+
+
We rely on on swagger-annotations and swagger-ui only official libraries.
+
+
+
We support new features on Spring 5, like spring-webflux with annotated and functional style.
+
+
+
We do our best to answer all the questions and address all issues or enhancement requests
+
+
+
+
+
+
13.36. How do I migrate to OpenAPI 3 with springdoc-openapi
+
+
+
+
There is no relation between springdoc-openapi and springfox.If you want to migrate to OpenAPI 3:
+
+
+
Remove all the dependencies and the related code to springfox
If you don’t want to serve the UI from your root path or there is a conflict with an existing configuration, you can just change the following property:
You may have global parameters with Standard OpenAPI description.
+
+
+
If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi , you can use OpenAPI Bean.
+
+
+
You can define common parameters under parameters in the global components section and reference them elsewhere via $ref. You can also define global header parameters.
+
+
+
For this, you can override to OpenAPI Bean, and set the global headers or parameters definition on the components level.
+
+
+
+
+
+
@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"))
+ .addParameters("myHeader1", new Parameter().in("header").schema(new StringSchema()).name("myHeader1")).addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema())))
+ .info(new Info()
+ .title("Petstore API")
+ .version(appVersion)
+ .description("This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.")
+ .termsOfService("http://swagger.io/terms/")
+ .license(new License().name("Apache 2.0").url("http://springdoc.org")));
+}
+
+
+
+
+
+
13.38. Are Callbacks supported?
+
+
+
+
Yes
+
+
+
+
+
+
13.39. How can I define SecurityScheme ?
+
+
+
+
You can use: @SecurityScheme annotation.
+
+
+
Or you can define it programmatically, by overriding OpenAPI Bean:
+
+
+
+
+
+
@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("SpringShop API").version(appVersion)
+ .license(new License().name("Apache 2.0").url("http://springdoc.org")));
+ }
+
+
+
+
+
+
13.40. How can I hide an operation or a controller from documentation ?
+
+
+
+
You can use @io.swagger.v3.oas.annotations.Hidden annotation at @RestController, @RestControllerAdvice and method level
+
+
+
The @Hidden annotation on exception handler methods, is considered when building generic (error) responses from @ControllerAdvice exception handlers.
+
+
+
Or use: @Operation(hidden = true)
+
+
+
+
+
+
13.41. How to configure global security schemes?
+
+
+
+
For global SecurityScheme, you can add it inside your own OpenAPI definition:
13.48. What is the URL of the swagger-ui, when I set a different context-path?
+
+
+
+
If you use different context-path:
+
+
+
+
+
+
server.servlet.context-path= /foo
+
+
+
+
+
+
The swagger-ui will be available on the following URL:
+
+
+
+
http://server:port/foo/swagger-ui.html
+
+
+
+
+
+
+
+
+
13.49. Can I customize OpenAPI object programmatically?
+
+
+
+
You can Define your own OpenAPI Bean: If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi , you can use OpenAPI Bean.
If you need the definitions to appear within a specific group, and respect the conditions specified on the GroupedOpenApi, you can add OpenApiCustomizer to your GroupedOpenApi definition.
13.54. Can I use @Parameter inside @Operation annotation?
+
+
+
+
Yes, it’s supported
+
+
+
+
+
+
13.55. Why my parameter is marked as required?
+
+
+
+
Any @GetMapping parameters is marked as required, even if @RequestParam is missing.
+
+
+
You can add @Parameter(required=false) annotation if you need different behaviour.
+
+
+
Query parameters with defaultValue specified are marked as required.
+
+
+
+
+
+
13.56. How are overloaded methods with the same endpoints, but with different parameters
+
+
+
+
springdoc-openapi renders these methods as a single endpoint. It detects the overloaded endpoints, and generates parameters.schema.oneOf.
+
+
+
+
+
+
13.57. What is a proper way to set up Swagger UI to use provided spec.yml?
+
+
+
+
With this property, all the springdoc-openapi auto-configuration beans are disabled:
+
+
+
+
+
+
springdoc.api-docs.enabled=false
+
+
+
+
+
+
Then enable the minimal Beans configuration, by adding this Bean:
+
+
+
+
+
+
@Bean
+SpringDocConfiguration springDocConfiguration(){
+ return new SpringDocConfiguration();
+}
+
+@Bean
+SpringDocConfigProperties springDocConfigProperties() {
+ return new SpringDocConfigProperties();
+}
+
+@Bean
+ObjectMapperProvider objectMapperProvider(SpringDocConfigProperties springDocConfigProperties){
+ return new ObjectMapperProvider(springDocConfigProperties);
+}
+
+
+
+
+
+
+
Then configure, the path of your custom UI yaml file.
+
+
+
+
+
+
springdoc.swagger-ui.url=/api-docs.yaml
+
+
+
+
+
13.58. Is there a way to send authorization header through the @Parameter tag?
+
+
+
+
The OpenAPI 3 specification does not allow explicitly adding Authorization header.
+Note: Header parameters named Accept, Content-Type and Authorization are not allowed. To describe these headers
13.61. How can I extract fields from parameter object ?
+
+
+
+
You can use springdoc annotation @ParameterObject.
+
+
+
Request parameter annotated with @ParameterObject will help adding each field of the parameter as a separate request parameter.
+
+
+
This is compatible with Spring MVC request parameters mapping to POJO object.
+
+
+
This annotation does not support nested parameter objects.
+
+
+
POJO object must contain getters for fields with mandatory prefix get. Otherwise, the swagger documentation will not show the fields of the annotated entity.
+
+
+
+
+
+
13.62. How can I use the last springdoc-openapi SNAPSHOT ?
+
+
+
+
For testing purposes only, you can test temporarily using the last springdoc-openapi SNAPSHOT
+
+
+
To achieve that, configure your pom.xml file with the following <repositories> section:
Another solution, without using springdoc-openapi MonetaryAmount, would be:
+
+
+
+
+
+
SpringDocUtils.getConfig().replaceWithSchema(MonetaryAmount.class, new ObjectSchema()
+ .addProperties("amount", new NumberSchema()).example(99.96)
+ .addProperties("currency", new StringSchema().example("USD")));
+
+
+
+
+
+
13.64. How can i aggregate external endpoints (exposing OPENAPI 3 spec) inside one single application?
+
+
The properties springdoc.swagger-ui.urls.*, are suitable to configure external (/v3/api-docs url).
+For example if you want to agreagte all the endpoints of other services, inside one single application.
+IMPORTANT: Don’t forget that CORS needs to be enabled as well.
+
+
+
+
13.65. How can use custom json/yml file instead of generated one ?
+
+
If your file open-api.json, contains the OpenAPI documentation in OpenAPI 3 format.
+Then simply declare: The file name can be anything you want, from the moment your declaration is consistent yaml or json OpenAPI Spec.
+
+
+
+
springdoc.swagger-ui.url=/open-api.json
+
+
+
+
Then the file open-api.json, should be located in: src/main/resources/static
+No additional configuration is needed.
+
+
+
+
13.66. How can i enable CSRF support?
+
+
If you are using standard headers.( For example using spring-security headers)
+If the CSRF Token is required, swagger-ui automatically sends the new XSRF-TOKEN during each HTTP REQUEST.
+
+
+
If your XSRF-TOKEN isn’t standards-based, you can use a requestInterceptor to manually capture and attach the latest xsrf token to requests programmatically via spring resource transformer:
13.68. Is @PageableDefault supported, to enhance the OpenAPI 3 docuementation?
+
+
Yes, you can use it in conjunction with @ParameterObject annotation.
+Also, the spring-boot spring.data.web. and spring.data.rest.default. properties are supported since v1.4.5
+
+
+
+
13.69. How can i make spring security login-endpoint visible ?
+
+
You can use the following property:
+
+
+
+
springdoc.show-login-endpoint=true
+
+
+
+
+
13.70. How can i show schema definitions even the schema is not referenced?
The whole idea of springdoc-openapi is to get your documentation the closest to the code, with minimal code changes.
+If the code contains @Deprecated, sprindoc-openapi will consider its schema as Deprecated as well.
+If you want to declare a field on swagger as non deprecated, even with the java code, the field contains @Depreacted,
+You can use the following property that is available since release v1.4.3:
13.72. How can i display a method that returns ModelAndView?
+
+
You can use the following property:
+
+
+
+
springdoc.model-and-view-allowed=true
+
+
+
+
+
13.73. How can i have pretty-printed output of the OpenApi specification?
+
+
You can use the following property:
+
+
+
+
springdoc.writer-with-default-pretty-printer=true
+
+
+
+
+
13.74. How can i define different schemas for the same class?
+
+
Complex objects are always resolved as a reference to a schema defined in components.
+For example let’s consider a Instance class with an workAddress and homeAddress attribute of type Address:
You can customize swagger documentation static resources located in META-INF/resources/webjars/swagger-ui/{swagger.version}/. The list of resources includes:
+
+
+
+
+
index.html
+
+
+
swagger-ui-bundle.js
+
+
+
swagger-ui.css
+
+
+
swagger-ui-standalone-preset.js
+
+
+
swagger-ui.css.map
+
+
+
swagger-ui-bundle.js.map
+
+
+
swagger-ui-standalone-preset.js.map
+
+
+
favicon-32x32.png
+
+
+
+
+
To do this, you need to extend the implementation of SwaggerIndexPageTransformer
+
+
+
+
public class SwaggerCodeBlockTransformer
+ extends SwaggerIndexPageTransformer {
+ // < constructor >
+ @Override
+ public Resource transform(HttpServletRequest request,
+ Resource resource,
+ ResourceTransformerChain transformer)
+ throws IOException {
+ if (resource.toString().contains("swagger-ui.css")) {
+ final InputStream is = resource.getInputStream();
+ final InputStreamReader isr = new InputStreamReader(is);
+ try (BufferedReader br = new BufferedReader(isr)) {
+ final String css = br.lines().collect(Collectors.joining());
+ final byte[] transformedContent = css.replace("old", "new").getBytes();
+ return new TransformedResource(resource, transformedContent);
+ } // AutoCloseable br > isr > is
+ }
+ return super.transform(request, resource, transformer);
+ }
+
+}
+
+
+
+
+
Next, add transformer @Bean to your @Configuration
+
+
+
+
@Configuration
+public class OpenApiConfig {
+ @Bean
+ public SwaggerIndexTransformer swaggerIndexTransformer(
+ SwaggerUiConfigProperties a,
+ SwaggerUiOAuthProperties b,
+ SwaggerUiConfigParameters c,
+ SwaggerWelcomeCommon d) {
+ return new SwaggerCodeBlockTransformer(a, b, c, d);
+ }
+}
+
+
+
+
+
Illustrative example
+
+
+
+
+
+
+
+
+
13.77. Is GraalVM supported ?
+
+
The native support available added in spring-boot 3.
+If you have some time, do not hesitate to test it before the next release.
+
+
+
For the OpenAPI REST endpoints, you just need to build your application with the spring native profile.
+
+
+
If you give @OpenAPIDefinition or @SecurityScheme to a class that has no implementation, that class will disappear when you natively compile.
+To avoid this, give the class a @Configuration.
+
+
+
+
@Configuration
+@OpenAPIDefinition(info = @Info(title = "My App", description = "description"))
+public class OpenAPIConfig {
+}
+
+
+
+
+
13.78. How to Integrate Open API 3 with Spring project (not Spring Boot)?
+
+
When your application is using spring without (spring-boot), you need to add beans and auto-configuration that are natively provided in spring-boot.
+
+
+
For example, lets assume you want load the swagger-ui in spring-mvc application:
+
+
+
+
+
You mainly, need to add the springdoc-openapi module
If you don’t have the spring-boot and spring-boot-autoconfigure dependencies, you need to add them. And pay attention to the compatibility matrix, between you spring.version and spring-boot.version. For example, in this case (spring.version=5.1.12.RELEASE):
Depending on your module, you can find them on the file: org.springframework.boot.autoconfigure.AutoConfiguration.imports of each springdoc-openapi module.
+
+
+
For groups usage make sure your GroupedOpenApi Beans are scanned.
+
+
+
If additionally, you are using custom context path: /my-servlet-path. Make sure you declare the following property:
+
+
+
+
+
+
spring.mvc.servlet.path=/my-servlet-path
+
+
+
+
+
13.79. What is the compatibility matrix of springdoc-openapi with spring-boot ?
+
+
springdoc-openapi 2.x is compatible with spring-boot 3.
+
+
+
In general, you should only pick the last stable version as per today 2.8.9.
+
+
+
More precisely, this the exhaustive list of spring-boot versions against which springdoc-openapi has been built:
+
+
+
+
+
+
+
+
+
Spring Boot Versions
+
Springdoc OpenAPI Versions
+
+
+
3.4.x
+
2.7.x - 2.8.x
+
+
+
3.3.x
+
2.6.x
+
+
+
3.2.x
+
2.3.x - 2.5.x
+
+
+
3.1.x
+
2.2.x
+
+
+
3.0.x
+
2.0.x - 2.1.x
+
+
+
2.7.x, 1.5.x
+
1.6.0+
+
+
+
2.6.x, 1.5.x
+
1.6.0+
+
+
+
2.5.x, 1.5.x
+
1.5.9+
+
+
+
2.4.x, 1.5.x
+
1.5.0+
+
+
+
2.3.x, 1.5.x
+
1.4.0+
+
+
+
2.2.x, 1.5.x
+
1.2.1+
+
+
+
2.0.x, 1.5.x
+
1.0.0+
+
+
+
+
+
+
13.80. Why am i getting an error: Swagger UI unable to render definition, when overriding the default spring registered HttpMessageConverter?
+
+
When overriding the default spring-boot registered HttpMessageConverter, you should have ByteArrayHttpMessageConverter registered as well to have proper springdoc-openapi support.
+Order is very important, when registering HttpMessageConverters.
+
+
+
+
+
+
+
13.81. Some parameters are not generated in the resulting OpenAPI spec.
+
+
The issue is caused by the changes introduced by Spring-Boot 3.2.0
+in particular for the Parameter Name Discovery.
+This can be fixed by adding the -parameters arg to the Maven Compiler Plugin.
+
+
\ No newline at end of file
diff --git a/docs/intro.html b/docs/intro.html
new file mode 100644
index 0000000..9181077
--- /dev/null
+++ b/docs/intro.html
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+Introduction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Introduction
+
+
+
springdoc-openapi java library helps to automate the generation of API documentation using spring boot projects.
+springdoc-openapi works by examining an application at runtime to infer API semantics based on spring configurations, class structure and various annotations.
+
+
+
Automatically generates documentation in JSON/YAML and HTML format APIs.
+This documentation can be completed by comments using swagger-api annotations.
+
+
+
This library supports:
+
+
+
+
+
OpenAPI 3
+
+
+
Spring-boot v3 (Java 17 & Jakarta EE 9)
+
+
+
JSR-303, specifically for @NotNull, @Min, @Max, and @Size.
+
+
+
Swagger-ui
+
+
+
OAuth 2
+
+
+
GraalVM native images
+
+
+
+
+
The following video introduces the Library:
+
+
+
+
+
+
+
+
This is a community-based project, not maintained by the Spring Framework Contributors (Pivotal).
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/js/setup.js b/docs/js/setup.js
new file mode 100755
index 0000000..ae5b1b7
--- /dev/null
+++ b/docs/js/setup.js
@@ -0,0 +1,3 @@
+!function(){"use strict";document.getElementsByTagName("html")[0].classList.add("js")}();
+!function(){var t=function(t,n,e){if("function"!=typeof t)throw new TypeError("Expected a function");return setTimeout((function(){t.apply(void 0,e)}),n)};var n=function(t){return t};var e=function(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)},r=Math.max;var o=function(t,n,o){return n=r(void 0===n?t.length-1:n,0),function(){for(var c=arguments,u=-1,i=r(c.length-n,0),a=Array(i);++u0){if(++n>=800)return arguments[0]}else n=0;return t.apply(void 0,arguments)}},D=C(R);var G=/\s/;var U=function(t){for(var n=t.length;n--&&G.test(t.charAt(n)););return n},z=/^\s+/;var B=function(t){return t?t.slice(0,U(t)+1).replace(z,""):t};var H=function(t){return null!=t&&"object"==typeof t};var J=function(t){return"symbol"==typeof t||H(t)&&"[object Symbol]"==g(t)},K=/^[-+]0x[0-9a-f]+$/i,Q=/^0b[01]+$/i,V=/^0o[0-7]+$/i,W=parseInt;var X=function(t){if("number"==typeof t)return t;if(J(t))return NaN;if(m(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=m(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=B(t);var e=Q.test(t);return e||V.test(t)?W(t.slice(2),e?2:8):K.test(t)?NaN:+t},Y=function(t,e){return D(o(t,e,n),t+"")}((function(n,e,r){return t(n,X(e)||0,r)}));!function(){"use strict";const t=window.localStorage,n=document.documentElement,e=window.matchMedia("(prefers-color-scheme: dark)");function r(){const n=null!==t?t.getItem("theme"):null;return n?"dark"===n:e.matches}function o(){this.checked?(Y((function(){n.classList.add("dark-theme")}),100),c("dark")):(Y((function(){n.classList.remove("dark-theme")}),100),c("light"))}function c(n){t&&t.setItem("theme",n)}r()&&n.classList.add("dark-theme"),window.addEventListener("load",(function(){const t=document.querySelector("#switch-theme-checkbox");t.checked=r(),t.addEventListener("change",o.bind(t))}))}()}();
+//# sourceMappingURL=setup.js.map
diff --git a/docs/js/setup.js.map b/docs/js/setup.js.map
new file mode 100755
index 0000000..2971105
--- /dev/null
+++ b/docs/js/setup.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["setup/src/main/js/setup/layout.js","setup/node_modules/browser-pack-flat/_prelude","setup/node_modules/lodash/_baseDelay.js","setup/switchtheme.js","setup/node_modules/lodash/identity.js","setup/node_modules/lodash/_apply.js","setup/node_modules/lodash/_overRest.js","setup/node_modules/lodash/constant.js","setup/node_modules/lodash/_freeGlobal.js","setup/node_modules/lodash/_root.js","setup/node_modules/lodash/_Symbol.js","setup/node_modules/lodash/_getRawTag.js","setup/node_modules/lodash/_objectToString.js","setup/node_modules/lodash/_baseGetTag.js","setup/node_modules/lodash/isObject.js","setup/node_modules/lodash/isFunction.js","setup/node_modules/lodash/_isMasked.js","setup/node_modules/lodash/_coreJsData.js","setup/node_modules/lodash/_toSource.js","setup/node_modules/lodash/_baseIsNative.js","setup/node_modules/lodash/_getValue.js","setup/node_modules/lodash/_getNative.js","setup/node_modules/lodash/_defineProperty.js","setup/node_modules/lodash/_baseSetToString.js","setup/node_modules/lodash/_shortOut.js","setup/node_modules/lodash/_setToString.js","setup/node_modules/lodash/_baseRest.js","setup/node_modules/lodash/_trimmedEndIndex.js","setup/node_modules/lodash/_baseTrim.js","setup/node_modules/lodash/isObjectLike.js","setup/node_modules/lodash/isSymbol.js","setup/node_modules/lodash/toNumber.js","setup/node_modules/lodash/delay.js","setup/src/main/js/setup/switchtheme.js","setup/node_modules/browser-pack-flat/_postlude"],"names":["document","getElementsByTagName","classList","add","_$baseDelay_3","func","wait","args","TypeError","setTimeout","apply","undefined","_$identity_25","value","_$apply_2","thisArg","length","call","nativeMax","Math","max","_$overRest_17","start","transform","arguments","index","array","Array","otherArgs","this","_$constant_23","_$freeGlobal_11","global","freeGlobal","Object","self","window","freeSelf","_$root_18","Function","_$Symbol_1","Symbol","objectProto","prototype","hasOwnProperty","nativeObjectToString","toString","symToStringTag","toStringTag","_$getRawTag_13","isOwn","tag","unmasked","e","result","__nativeObjectToString_16","_$objectToString_16","__symToStringTag_4","_$baseGetTag_4","_$isObject_27","type","uid","_$isFunction_26","_$coreJsData_9","maskSrcKey","exec","keys","IE_PROTO","_$isMasked_15","funcToString","_$toSource_21","reIsHostCtor","__funcProto_5","__objectProto_5","__funcToString_5","__hasOwnProperty_5","reIsNative","RegExp","replace","_$baseIsNative_5","test","_$getValue_14","object","key","_$getNative_12","_$defineProperty_10","_$baseSetToString_7","string","configurable","enumerable","writable","nativeNow","Date","now","_$shortOut_20","count","lastCalled","stamp","remaining","_$setToString_19","reWhitespace","_$trimmedEndIndex_22","charAt","reTrimStart","_$baseTrim_8","slice","_$isObjectLike_28","_$isSymbol_29","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","parseInt","_$toNumber_30","other","valueOf","isBinary","_$delay_24","_$baseRest_6","localStorage","htmlElement","documentElement","prefersDarkColorScheme","matchMedia","isInitialThemeDark","theme","getItem","matches","onThemeChange","checked","saveTheme","remove","setItem","addEventListener","toggleCheckboxElement","querySelector","bind"],"mappings":"CAgBA,WACE,aACAA,SAASC,qBAAqB,QAAQ,GAAGC,UAAUC,IAAI,KACxD,CAHD;CChBA,WCoBA,IAAAC,EAPA,SAAmBC,EAAMC,EAAMC,GAC7B,GAAmB,mBAARF,EACT,MAAM,IAAIG,UAdQ,uBAgBpB,OAAOC,YAAW,WAAaJ,EAAKK,WAAMC,EAAWJ,EAAM,GAAID,ECEjE,ECCA,IAAAM,EAJA,SAAkBC,GAChB,OAAOA,CDwBT,EErBA,IAAAC,EAVA,SAAeT,EAAMU,EAASR,GAC5B,OAAQA,EAAKS,QACX,KAAK,EAAG,OAAOX,EAAKY,KAAKF,GACzB,KAAK,EAAG,OAAOV,EAAKY,KAAKF,EAASR,EAAK,IACvC,KAAK,EAAG,OAAOF,EAAKY,KAAKF,EAASR,EAAK,GAAIA,EAAK,IAChD,KAAK,EAAG,OAAOF,EAAKY,KAAKF,EAASR,EAAK,GAAIA,EAAK,GAAIA,EAAK,IAE3D,OAAOF,EAAKK,MAAMK,EAASR,EF8C7B,EG5DIW,EAAYC,KAAKC,IAgCrB,IAAAC,EArBA,SAAkBhB,EAAMiB,EAAOC,GAE7B,OADAD,EAAQJ,OAAoBP,IAAVW,EAAuBjB,EAAKW,OAAS,EAAKM,EAAO,GAC5D,WAML,IALA,IAAIf,EAAOiB,UACPC,GAAS,EACTT,EAASE,EAAUX,EAAKS,OAASM,EAAO,GACxCI,EAAQC,MAAMX,KAETS,EAAQT,GACfU,EAAMD,GAASlB,EAAKe,EAAQG,GAE9BA,GAAS,EAET,IADA,IAAIG,EAAYD,MAAML,EAAQ,KACrBG,EAAQH,GACfM,EAAUH,GAASlB,EAAKkB,GAG1B,OADAG,EAAUN,GAASC,EAAUG,GACtBZ,EAAMT,EAAMwB,KAAMD,EHoE3B,CACF,EI3EA,IAAAE,EANA,SAAkBjB,GAChB,OAAO,WACL,OAAOA,CJyGT,CACF,EAIIkB,EAAkB,CAAC,GACvB,SAAWC,IAAQ,WKnInB,IAAAC,EAAA,iBAAAD,GAAAA,GAAAA,EAAAE,SAAAA,QAAAF,EAEAD,EAAAE,CLuIC,GAAEhB,KAAKY,KAAM,GAAEZ,KAAKY,KAAuB,oBAAXG,OAAyBA,OAAyB,oBAATG,KAAuBA,KAAyB,oBAAXC,OAAyBA,OAAS,CAAC,GMvIlJ,IAAIC,EAA0B,iBAARF,MAAoBA,MAAQA,KAAKD,SAAWA,QAAUC,KAK5EG,EAFWP,GAAcM,GAAYE,SAAS,cAATA,GCDrCC,EAFaF,EAAKG,OCAdC,EAAcR,OAAOS,UAGrBC,EAAiBF,EAAYE,eAO7BC,EAAuBH,EAAYI,SAGnCC,EAAiBP,EAASA,EAAOQ,iBAAcrC,EA6BnD,IAAAsC,EApBA,SAAmBpC,GACjB,IAAIqC,EAAQN,EAAe3B,KAAKJ,EAAOkC,GACnCI,EAAMtC,EAAMkC,GAEhB,IACElC,EAAMkC,QAAkBpC,EACxB,IAAIyC,GAAW,CACL,CAAV,MAAOC,GAAG,CAEZ,IAAIC,EAAST,EAAqB5B,KAAKJ,GAQvC,OAPIuC,IACEF,EACFrC,EAAMkC,GAAkBI,SAEjBtC,EAAMkC,IAGVO,CR8JT,EShMIC,EAPcrB,OAAOS,UAOcG,SAavC,IAAAU,EAJA,SAAwB3C,GACtB,OAAO0C,EAAqBtC,KAAKJ,ET6MnC,EUtNI4C,EAAiBjB,EAASA,EAAOQ,iBAAcrC,EAkBnD,IAAA+C,EATA,SAAoB7C,GAClB,OAAa,MAATA,OACeF,IAAVE,EAdQ,qBADL,gBAiBJ4C,GAAkBA,KAAkBvB,OAAOrB,GAC/CoC,EAAUpC,GACV2C,EAAe3C,EVkOrB,EW5NA,IAAA8C,EALA,SAAkB9C,GAChB,IAAI+C,SAAc/C,EAClB,OAAgB,MAATA,IAA0B,UAAR+C,GAA4B,YAARA,EX+P/C,EYtPA,IChCMC,EDgCNC,EAVA,SAAoBjD,GAClB,IAAK8C,EAAS9C,GACZ,OAAO,EAIT,IAAIsC,EAAMO,EAAW7C,GACrB,MA5BY,qBA4BLsC,GA3BI,8BA2BcA,GA7BZ,0BA6B6BA,GA1B7B,kBA0BgDA,CZ8R/D,Ec1TAY,EAFiBzB,EAAK,sBDAlB0B,GACEH,EAAM,SAASI,KAAKF,GAAcA,EAAWG,MAAQH,EAAWG,KAAKC,UAAY,KACvE,iBAAmBN,EAAO,GAc1C,IAAAO,EAJA,SAAkB/D,GAChB,QAAS2D,GAAeA,KAAc3D,Cb2UxC,EevVIgE,EAHY9B,SAASI,UAGIG,SAqB7B,IAAAwB,EAZA,SAAkBjE,GAChB,GAAY,MAARA,EAAc,CAChB,IACE,OAAOgE,EAAapD,KAAKZ,EACf,CAAV,MAAOgD,GAAG,CACZ,IACE,OAAQhD,EAAO,EACL,CAAV,MAAOgD,GAAG,CfgWd,Ce9VA,MAAO,EfgWT,EgB1WIkB,EAAe,8BAGfC,EAAYjC,SAASI,UACrB8B,EAAcvC,OAAOS,UAGrB+B,EAAeF,EAAU1B,SAGzB6B,EAAiBF,EAAY7B,eAG7BgC,EAAaC,OAAO,IACtBH,EAAazD,KAAK0D,GAAgBG,QAjBjB,sBAiBuC,QACvDA,QAAQ,yDAA0D,SAAW,KAmBhF,IAAAC,EARA,SAAsBlE,GACpB,SAAK8C,EAAS9C,IAAUuD,EAASvD,MAGnBiD,EAAWjD,GAAS+D,EAAaL,GAChCS,KAAKV,EAASzD,GhBwX/B,EiBvZA,IAAAoE,EAJA,SAAkBC,EAAQC,GACxB,OAAiB,MAAVD,OAAiBvE,EAAYuE,EAAOC,EjBwa7C,EkBjaA,IAAAC,EALA,SAAmBF,EAAQC,GACzB,IAAItE,EAAQoE,EAASC,EAAQC,GAC7B,OAAOJ,EAAalE,GAASA,OAAQF,ClBqbvC,EmBxbA0E,EARsB,WACpB,IACE,IAAIhF,EAAO+E,EAAUlD,OAAQ,kBAE7B,OADA7B,EAAK,CAAA,EAAI,GAAI,CAAA,GACNA,CACG,CAAV,MAAOgD,GAAG,CnBucd,CmB5ckB,GCmBlBiC,EATuBD,EAA4B,SAAShF,EAAMkF,GAChE,OAAOF,EAAehF,EAAM,WAAY,CACtCmF,cAAgB,EAChBC,YAAc,EACd5E,MAASiB,EAASyD,GAClBG,UAAY,GpBkdhB,EoBvdwC9E,ECPpC+E,EAAYC,KAAKC,IA+BrB,IAAAC,EApBA,SAAkBzF,GAChB,IAAI0F,EAAQ,EACRC,EAAa,EAEjB,OAAO,WACL,IAAIC,EAAQN,IACRO,EApBO,IAoBiBD,EAAQD,GAGpC,GADAA,EAAaC,EACTC,EAAY,GACd,KAAMH,GAzBI,IA0BR,OAAOvE,UAAU,QAGnBuE,EAAQ,EAEV,OAAO1F,EAAKK,WAAMC,EAAWa,UrBwe/B,CACF,EsB5fA2E,EAFkBL,EAASR,GCK3B,ICfIc,EAAe,KAiBnB,IAAAC,EAPA,SAAyBd,GAGvB,IAFA,IAAI9D,EAAQ8D,EAAOvE,OAEZS,KAAW2E,EAAapB,KAAKO,EAAOe,OAAO7E,MAClD,OAAOA,CxB4iBT,EyBxjBI8E,EAAc,OAelB,IAAAC,EANA,SAAkBjB,GAChB,OAAOA,EACHA,EAAOkB,MAAM,EAAGJ,EAAgBd,GAAU,GAAGT,QAAQyB,EAAa,IAClEhB,CzBgkBN,E0BnjBA,IAAAmB,EAJA,SAAsB7F,GACpB,OAAgB,MAATA,GAAiC,iBAATA,C1BolBjC,E2BjlBA,IAAA8F,EALA,SAAkB9F,GAChB,MAAuB,iBAATA,GACX6F,EAAa7F,IArBF,mBAqBY6C,EAAW7C,E3BinBvC,E4BloBI+F,EAAa,qBAGbC,EAAa,aAGbC,EAAY,cAGZC,EAAeC,SA8CnB,IAAAC,EArBA,SAAkBpG,GAChB,GAAoB,iBAATA,EACT,OAAOA,EAET,GAAI8F,EAAS9F,GACX,OA1CM,IA4CR,GAAI8C,EAAS9C,GAAQ,CACnB,IAAIqG,EAAgC,mBAAjBrG,EAAMsG,QAAwBtG,EAAMsG,UAAYtG,EACnEA,EAAQ8C,EAASuD,GAAUA,EAAQ,GAAMA,C5B6oB3C,C4B3oBA,GAAoB,iBAATrG,EACT,OAAiB,IAAVA,EAAcA,GAASA,EAEhCA,EAAQ2F,EAAS3F,GACjB,IAAIuG,EAAWP,EAAW7B,KAAKnE,GAC/B,OAAQuG,GAAYN,EAAU9B,KAAKnE,GAC/BkG,EAAalG,EAAM4F,MAAM,GAAIW,EAAW,EAAI,GAC3CR,EAAW5B,KAAKnE,GAvDb,KAuD6BA,C5B6oBvC,E6B9qBAwG,ENfA,SAAkBhH,EAAMiB,GACtB,OAAO6E,EAAY9E,EAAShB,EAAMiB,EAAOV,GAAWP,EAAO,GvB0hB7D,C6BhhBYiH,EAAS,SAASjH,EAAMC,EAAMC,GACxC,OAAOH,EAAUC,EAAM4G,EAAS3G,IAAS,EAAGC,E7B4sB9C,K8BptBA,WACE,aAIA,MAAMgH,EAAenF,OAAOmF,aACtBC,EAAcxH,SAASyH,gBACvBC,EAAyBtF,OAAOuF,WACpC,gCAuBF,SAASC,IACP,MAAMC,EAyBkB,OAAjBN,EAAwBA,EAAaO,QAAQ,SAAW,KAxB/D,OAAOD,EAAkB,SAAVA,EAAmBH,EAAuBK,O9B0uB3D,C8BvuBA,SAASC,IACHnG,KAAKoG,SACPZ,GAAM,WACJG,EAAYtH,UAAUC,IAAI,a9B0uB5B,G8BzuBG,KACH+H,EAAU,UAEVb,GAAM,WACJG,EAAYtH,UAAUiI,OAAO,a9B0uB/B,G8BzuBG,KACHD,EAAU,S9B2uBd,C8BvuBA,SAASA,EAAUL,GACbN,GACFA,EAAaa,QAAQ,QAASP,E9B2uBlC,C8BhxBMD,KACFJ,EAAYtH,UAAUC,IAAI,cAJ9BiC,OAAOiG,iBAAiB,QAQxB,WACE,MAAMC,EAAwBtI,SAASuI,cACrC,0BAEFD,EAAsBL,QAAUL,IAChCU,EAAsBD,iBACpB,SACAL,EAAcQ,KAAKF,G9B2uBvB,G8B3sBD,CA3DD,ECfA,CjCDA","file":"setup.js","sourcesContent":["/*\n * Copyright 2021 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n(function () {\n \"use strict\";\n document.getElementsByTagName(\"html\")[0].classList.add(\"js\");\n})();\n","(function(){\n","/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * The base implementation of `_.delay` and `_.defer` which accepts `args`\n * to provide to `func`.\n *\n * @private\n * @param {Function} func The function to delay.\n * @param {number} wait The number of milliseconds to delay invocation.\n * @param {Array} args The arguments to provide to `func`.\n * @returns {number|Object} Returns the timer id or timeout object.\n */\nfunction baseDelay(func, wait, args) {\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n return setTimeout(function() { func.apply(undefined, args); }, wait);\n}\n\nmodule.exports = baseDelay;\n","/*\n * Copyright 2021 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n(function () {\n \"use strict\";\n\n const delay = require(\"lodash/delay\");\n\n const localStorage = window.localStorage;\n const htmlElement = document.documentElement;\n const prefersDarkColorScheme = window.matchMedia(\n \"(prefers-color-scheme: dark)\"\n );\n\n swithInitialTheme();\n window.addEventListener(\"load\", onWindowLoad);\n\n function swithInitialTheme() {\n if (isInitialThemeDark()) {\n htmlElement.classList.add(\"dark-theme\");\n }\n }\n\n function onWindowLoad() {\n const toggleCheckboxElement = document.querySelector(\n \"#switch-theme-checkbox\"\n );\n toggleCheckboxElement.checked = isInitialThemeDark();\n toggleCheckboxElement.addEventListener(\n \"change\",\n onThemeChange.bind(toggleCheckboxElement)\n );\n }\n\n function isInitialThemeDark() {\n const theme = loadTheme();\n return theme ? theme === \"dark\" : prefersDarkColorScheme.matches;\n }\n\n function onThemeChange() {\n if (this.checked) {\n delay(function () {\n htmlElement.classList.add(\"dark-theme\");\n }, 100);\n saveTheme(\"dark\");\n } else {\n delay(function () {\n htmlElement.classList.remove(\"dark-theme\");\n }, 100);\n saveTheme(\"light\");\n }\n }\n\n function saveTheme(theme) {\n if (localStorage) {\n localStorage.setItem(\"theme\", theme);\n }\n }\n\n function loadTheme() {\n return localStorage !== null ? localStorage.getItem(\"theme\") : null;\n }\n})();\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nmodule.exports = identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nmodule.exports = apply;\n","var apply = require('./_apply');\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of `baseRest` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = transform(array);\n return apply(func, this, otherArgs);\n };\n}\n\nmodule.exports = overRest;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nmodule.exports = constant;\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nmodule.exports = freeGlobal;\n","var freeGlobal = require('./_freeGlobal');\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nmodule.exports = root;\n","var root = require('./_root');\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nmodule.exports = Symbol;\n","var Symbol = require('./_Symbol');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nmodule.exports = getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nmodule.exports = objectToString;\n","var Symbol = require('./_Symbol'),\n getRawTag = require('./_getRawTag'),\n objectToString = require('./_objectToString');\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nmodule.exports = baseGetTag;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nmodule.exports = isObject;\n","var baseGetTag = require('./_baseGetTag'),\n isObject = require('./isObject');\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nmodule.exports = isFunction;\n","var coreJsData = require('./_coreJsData');\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nmodule.exports = isMasked;\n","var root = require('./_root');\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nmodule.exports = coreJsData;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nmodule.exports = toSource;\n","var isFunction = require('./isFunction'),\n isMasked = require('./_isMasked'),\n isObject = require('./isObject'),\n toSource = require('./_toSource');\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nmodule.exports = baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nmodule.exports = getValue;\n","var baseIsNative = require('./_baseIsNative'),\n getValue = require('./_getValue');\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nmodule.exports = getNative;\n","var getNative = require('./_getNative');\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nmodule.exports = defineProperty;\n","var constant = require('./constant'),\n defineProperty = require('./_defineProperty'),\n identity = require('./identity');\n\n/**\n * The base implementation of `setToString` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n return defineProperty(func, 'toString', {\n 'configurable': true,\n 'enumerable': false,\n 'value': constant(string),\n 'writable': true\n });\n};\n\nmodule.exports = baseSetToString;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nmodule.exports = shortOut;\n","var baseSetToString = require('./_baseSetToString'),\n shortOut = require('./_shortOut');\n\n/**\n * Sets the `toString` method of `func` to return `string`.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar setToString = shortOut(baseSetToString);\n\nmodule.exports = setToString;\n","var identity = require('./identity'),\n overRest = require('./_overRest'),\n setToString = require('./_setToString');\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n return setToString(overRest(func, start, identity), func + '');\n}\n\nmodule.exports = baseRest;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nmodule.exports = trimmedEndIndex;\n","var trimmedEndIndex = require('./_trimmedEndIndex');\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nmodule.exports = baseTrim;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nmodule.exports = isObjectLike;\n","var baseGetTag = require('./_baseGetTag'),\n isObjectLike = require('./isObjectLike');\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nmodule.exports = isSymbol;\n","var baseTrim = require('./_baseTrim'),\n isObject = require('./isObject'),\n isSymbol = require('./isSymbol');\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = toNumber;\n","var baseDelay = require('./_baseDelay'),\n baseRest = require('./_baseRest'),\n toNumber = require('./toNumber');\n\n/**\n * Invokes `func` after `wait` milliseconds. Any additional arguments are\n * provided to `func` when it's invoked.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to delay.\n * @param {number} wait The number of milliseconds to delay invocation.\n * @param {...*} [args] The arguments to invoke `func` with.\n * @returns {number} Returns the timer id.\n * @example\n *\n * _.delay(function(text) {\n * console.log(text);\n * }, 1000, 'later');\n * // => Logs 'later' after one second.\n */\nvar delay = baseRest(function(func, wait, args) {\n return baseDelay(func, toNumber(wait) || 0, args);\n});\n\nmodule.exports = delay;\n","/*\n * Copyright 2021 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n(function () {\n \"use strict\";\n\n const delay = require(\"lodash/delay\");\n\n const localStorage = window.localStorage;\n const htmlElement = document.documentElement;\n const prefersDarkColorScheme = window.matchMedia(\n \"(prefers-color-scheme: dark)\"\n );\n\n swithInitialTheme();\n window.addEventListener(\"load\", onWindowLoad);\n\n function swithInitialTheme() {\n if (isInitialThemeDark()) {\n htmlElement.classList.add(\"dark-theme\");\n }\n }\n\n function onWindowLoad() {\n const toggleCheckboxElement = document.querySelector(\n \"#switch-theme-checkbox\"\n );\n toggleCheckboxElement.checked = isInitialThemeDark();\n toggleCheckboxElement.addEventListener(\n \"change\",\n onThemeChange.bind(toggleCheckboxElement)\n );\n }\n\n function isInitialThemeDark() {\n const theme = loadTheme();\n return theme ? theme === \"dark\" : prefersDarkColorScheme.matches;\n }\n\n function onThemeChange() {\n if (this.checked) {\n delay(function () {\n htmlElement.classList.add(\"dark-theme\");\n }, 100);\n saveTheme(\"dark\");\n } else {\n delay(function () {\n htmlElement.classList.remove(\"dark-theme\");\n }, 100);\n saveTheme(\"light\");\n }\n }\n\n function saveTheme(theme) {\n if (localStorage) {\n localStorage.setItem(\"theme\", theme);\n }\n }\n\n function loadTheme() {\n return localStorage !== null ? localStorage.getItem(\"theme\") : null;\n }\n})();\n","\n}());"]}
\ No newline at end of file
diff --git a/docs/js/site.js b/docs/js/site.js
new file mode 100755
index 0000000..24a40b4
--- /dev/null
+++ b/docs/js/site.js
@@ -0,0 +1,7 @@
+!function(){"use strict";function n(){const n=document.getElementById("anchor-rewrite"),o=window.location.hash.substr(1);n&&o&&function(n,o){const e=[n];for(console.debug(n);o[n];){if(n=o[n],e.includes(n))return void console.error("Skipping circular anchor update");e.push(n)}window.location.hash=n}(o,JSON.parse(n.innerHTML))}window.addEventListener("load",n),window.addEventListener("hashchange",n)}();
+!function(){"use strict";!function(){let t=document.getElementById("author"),n=t;for(;t;)t.classList.contains("author")&&(n=t),t=t.nextElementSibling;n&&n.classList.add("last-author")}()}();
+!function(){var t=function(t,n,e){if("function"!=typeof t)throw new TypeError("Expected a function");return setTimeout((function(){t.apply(void 0,e)}),n)};var n=function(t){return t};var e=function(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)},r=Math.max;var o=function(t,n,o){return n=r(void 0===n?t.length-1:n,0),function(){for(var c=arguments,i=-1,u=r(c.length-n,0),a=Array(u);++i0){if(++n>=800)return arguments[0]}else n=0;return t.apply(void 0,arguments)}},G=D(I);var M=/\s/;var U=function(t){for(var n=t.length;n--&&M.test(t.charAt(n)););return n},z=/^\s+/;var B=function(t){return t?t.slice(0,U(t)+1).replace(z,""):t};var H=function(t){return null!=t&&"object"==typeof t};var J=function(t){return"symbol"==typeof t||H(t)&&"[object Symbol]"==g(t)},K=/^[-+]0x[0-9a-f]+$/i,Q=/^0b[01]+$/i,V=/^0o[0-7]+$/i,W=parseInt;var X=function(t){if("number"==typeof t)return t;if(J(t))return NaN;if(m(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=m(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=B(t);var e=Q.test(t);return e||V.test(t)?W(t.slice(2),e?2:8):K.test(t)?NaN:+t},Y=function(t,e){return G(o(t,e,n),t+"")}((function(n,e,r){return t(n,X(e)||0,r)}));!function(){"use strict";function t(t){const e=t.querySelector("code").cloneNode(!0);for(const t of e.querySelectorAll(".hide-when-unfolded"))t.parentNode.removeChild(t);const r=e.innerText;r&&window.navigator.clipboard.writeText(r+"\n").then(n.bind(this))}function n(){this.classList.add("clicked")}function e(){this.classList.remove("clicked")}function r(t){const n=t.querySelector("code"),e=!n.classList.contains("unfolded");n.classList.remove(e?"folding":"unfolding"),n.classList.add(e?"unfolding":"folding"),Y((function(){n.classList.remove(e?"unfolding":"folding"),n.classList.toggle("unfolded")}),1100),o(this,!e)}function o(t,n){const e=n?"Expand folded text":"Collapse foldable text";t.classList.remove(n?"fold-button":"unfold-button"),t.classList.add(n?"unfold-button":"fold-button"),t.querySelector("span.label").innerText=e,t.title=e}!function(){for(const t of document.querySelectorAll(".doc pre.highlight")){const e=document.createElement("div");e.className="codetools",n(t,e)&&t.appendChild(e)}function n(n,i){let u=0;return function(t){return!!t.querySelector("span.hide-when-folded")}(n)&&(!function(t,n){const e=c();o(e,!0),e.addEventListener("click",r.bind(e,t)),n.appendChild(e)}(n,i),u++),window.navigator.clipboard&&(!function(n,r){const o=c("Copy to clipboard","copy-button");o.addEventListener("click",t.bind(o,n)),o.addEventListener("mouseleave",e.bind(o)),o.addEventListener("blur",e.bind(o));const i=document.createElement("span");o.appendChild(i),i.className="copied",r.appendChild(o)}(n,i),u++),u>0}function c(t,n){const e=document.createElement("button");e.className=n,e.title=t,e.type="button";const r=document.createElement("span");return r.appendChild(document.createTextNode(t)),r.className="label",e.appendChild(r),e}}()}()}();
+!function(){function e(n){return n instanceof Map?n.clear=n.delete=n.set=function(){throw new Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=function(){throw new Error("set is read-only")}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((function(t){var a=n[t];"object"!=typeof a||Object.isFrozen(a)||e(a)})),n}var n=e,t=e;n.default=t;class a{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function i(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function s(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}const r=e=>!!e.kind;class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=i(e)}openNode(e){if(!r(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){r(e)&&(this.buffer+="")}value(){return this.buffer}span(e){this.buffer+=``}}class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new o(this,this.options).value()}finalize(){return!0}}function g(e){return e?"string"==typeof e?e:e.source:null}const d=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;const u="[a-zA-Z]\\w*",b="[a-zA-Z_]\\w*",m="\\b\\d+(\\.\\d+)?",h="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",p="\\b(0b[01]+)",f={begin:"\\\\[\\s\\S]",relevance:0},_={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[f]},E={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[f]},v={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},N=function(e,n,t={}){const a=s({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(v),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},y=N("//","$"),w=N("/\\*","\\*/"),x=N("#","$"),M={className:"number",begin:m,relevance:0},O={className:"number",begin:h,relevance:0},k={className:"number",begin:p,relevance:0},R={className:"number",begin:m+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},S={begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[f,{begin:/\[/,end:/\]/,relevance:0,contains:[f]}]}]},A={className:"title",begin:u,relevance:0},T={className:"title",begin:b,relevance:0},C={begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0};var D=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:u,UNDERSCORE_IDENT_RE:b,NUMBER_RE:m,C_NUMBER_RE:h,BINARY_NUMBER_RE:p,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map((e=>g(e))).join("")}(n,/.*\b/,e.binary,/\b.*/)),s({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:f,APOS_STRING_MODE:_,QUOTE_STRING_MODE:E,PHRASAL_WORDS_MODE:v,COMMENT:N,C_LINE_COMMENT_MODE:y,C_BLOCK_COMMENT_MODE:w,HASH_COMMENT_MODE:x,NUMBER_MODE:M,C_NUMBER_MODE:O,BINARY_NUMBER_MODE:k,CSS_NUMBER_MODE:R,REGEXP_MODE:S,TITLE_MODE:A,UNDERSCORE_TITLE_MODE:T,METHOD_GUARD:C,END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}});function L(e,n){"."===e.input[e.index-1]&&n.ignoreMatch()}function B(e,n){n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=L,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,void 0===e.relevance&&(e.relevance=0))}function $(e,n){Array.isArray(e.illegal)&&(e.illegal=function(...e){return"("+e.map((e=>g(e))).join("|")+")"}(...e.illegal))}function I(e,n){if(e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function j(e,n){void 0===e.relevance&&(e.relevance=1)}const z=["of","and","for","in","not","or","if","then","parent","list","value"];function P(e,n,t="keyword"){const a={};return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((function(t){Object.assign(a,P(e[t],n,t))})),a;function i(e,t){n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((function(n){const t=n.split("|");a[t[0]]=[e,U(t[0],t[1])]}))}}function U(e,n){return n?Number(n):function(e){return z.includes(e.toLowerCase())}(e)?0:1}function K(e,{plugins:n}){function t(n,t){return new RegExp(g(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class a{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return new RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map((e=>e[1]));this.matcherRe=t(function(e,n="|"){let t=0;return e.map((e=>{t+=1;const n=t;let a=g(e),i="";for(;a.length>0;){const e=d.exec(a);if(!e){i+=a;break}i+=a.substring(0,e.index),a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+String(Number(e[1])+n):(i+=e[0],"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new a;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))),n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;let t=n.exec(e);if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&this.considerAll()),t}}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=s(e.classNameAliases||{}),function n(a,r){const o=a;if(a.isCompiled)return o;[I].forEach((e=>e(a,r))),e.compilerExtensions.forEach((e=>e(a,r))),a.__beforeBegin=null,[B,$,j].forEach((e=>e(a,r))),a.isCompiled=!0;let l=null;if("object"==typeof a.keywords&&(l=a.keywords.$pattern,delete a.keywords.$pattern),a.keywords&&(a.keywords=P(a.keywords,e.case_insensitive)),a.lexemes&&l)throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l=l||a.lexemes||/\w+/,o.keywordPatternRe=t(l,!0),r&&(a.begin||(a.begin=/\B|\b/),o.beginRe=t(a.begin),a.endSameAsBegin&&(a.end=a.begin),a.end||a.endsWithParent||(a.end=/\B|\b/),a.end&&(o.endRe=t(a.end)),o.terminatorEnd=g(a.end)||"",a.endsWithParent&&r.terminatorEnd&&(o.terminatorEnd+=(a.end?"|":"")+r.terminatorEnd)),a.illegal&&(o.illegalRe=t(a.illegal)),a.contains||(a.contains=[]),a.contains=[].concat(...a.contains.map((function(e){return function(e){e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((function(n){return s(e,{variants:null},n)})));if(e.cachedVariants)return e.cachedVariants;if(H(e))return s(e,{starts:e.starts?s(e.starts):null});if(Object.isFrozen(e))return s(e);return e}("self"===e?a:e)}))),a.contains.forEach((function(e){n(e,o)})),a.starts&&n(a.starts,r),o.matcher=function(e){const n=new i;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin"}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(o),o}(e)}function H(e){return!!e&&(e.endsWithParent||H(e.starts))}function Z(e){const n={props:["language","code","autodetect"],data:function(){return{detectedLanguage:"",unknownLanguage:!1}},computed:{className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){if(!this.autoDetect&&!e.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`),this.unknownLanguage=!0,i(this.code);let n={};return this.autoDetect?(n=e.highlightAuto(this.code),this.detectedLanguage=n.language):(n=e.highlight(this.language,this.code,this.ignoreIllegals),this.detectedLanguage=this.language),n.value},autoDetect(){return!this.language||(e=this.autodetect,Boolean(e||""===e));var e},ignoreIllegals:()=>!0},render(e){return e("pre",{},[e("code",{class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{Component:n,VuePlugin:{install(e){e.component("highlightjs",n)}}}}const G={"after:highlightElement":({el:e,result:n,text:t})=>{const a=F(e);if(!a.length)return;const s=document.createElement("div");s.innerHTML=n.value,n.value=function(e,n,t){let a=0,s="";const r=[];function o(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function c(e){s+=""+q(e)+">"}function g(e){("start"===e.event?l:c)(e.node)}for(;e.length||n.length;){let n=o();if(s+=i(t.substring(a,n[0].offset)),a=n[0].offset,n===e){r.reverse().forEach(c);do{g(n.splice(0,1)[0]),n=o()}while(n===e&&n.length&&n[0].offset===a);r.reverse().forEach(l)}else"start"===n[0].event?r.push(n[0].node):r.pop(),g(n.splice(0,1)[0])}return s+i(t.substr(a))}(a,F(s),t)}};function q(e){return e.nodeName.toLowerCase()}function F(e){const n=[];return function e(t,a){for(let i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=e(i,a),q(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}const W={},Q=e=>{console.error(e)},X=(e,...n)=>{console.log(`WARN: ${e}`,...n)},V=(e,n)=>{W[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),W[`${e}/${n}`]=!0)},J=i,Y=s,ee=Symbol("nomatch");var ne=function(e){const t=Object.create(null),i=Object.create(null),s=[];let r=!0;const o=/(^(<[^>]+>|\t|)+|\n)/gm,l="Could not find the language '{}', did you forget to load/include a language module?",g={disableAutodetect:!0,name:"Plain text",contains:[]};let d={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:c};function u(e){return d.noHighlightRe.test(e)}function b(e,n,t,a){let i="",s="";"object"==typeof n?(i=e,t=n.ignoreIllegals,s=n.language,a=void 0):(V("10.7.0","highlight(lang, code, ...args) has been deprecated."),V("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),s=e,i=n);const r={code:i,language:s};O("before:highlight",r);const o=r.result?r.result:m(r.language,r.code,t,a);return o.code=r.code,O("after:highlight",o),o}function m(e,n,i,o){function c(e,n){const t=N.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function g(){null!=M.subLanguage?function(){if(""===R)return;let e=null;if("string"==typeof M.subLanguage){if(!t[M.subLanguage])return void k.addText(R);e=m(M.subLanguage,R,!0,O[M.subLanguage]),O[M.subLanguage]=e.top}else e=h(R,M.subLanguage.length?M.subLanguage:null);M.relevance>0&&(S+=e.relevance),k.addSublanguage(e.emitter,e.language)}():function(){if(!M.keywords)return void k.addText(R);let e=0;M.keywordPatternRe.lastIndex=0;let n=M.keywordPatternRe.exec(R),t="";for(;n;){t+=R.substring(e,n.index);const a=c(M,n);if(a){const[e,i]=a;if(k.addText(t),t="",S+=i,e.startsWith("_"))t+=n[0];else{const t=N.classNameAliases[e]||e;k.addKeyword(n[0],t)}}else t+=n[0];e=M.keywordPatternRe.lastIndex,n=M.keywordPatternRe.exec(R)}t+=R.substr(e),k.addText(t)}(),R=""}function u(e){return e.className&&k.openNode(N.classNameAliases[e.className]||e.className),M=Object.create(e,{parent:{value:M}}),M}function b(e,n,t){let i=function(e,n){const t=e&&e.exec(n);return t&&0===t.index}(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e);e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){for(;e.endsParent&&e.parent;)e=e.parent;return e}}if(e.endsWithParent)return b(e.parent,n,t)}function p(e){return 0===M.matcher.regexIndex?(R+=e[0],1):(C=!0,0)}function f(e){const n=e[0],t=e.rule,i=new a(t),s=[t.__beforeBegin,t["on:begin"]];for(const t of s)if(t&&(t(e,i),i.isMatchIgnored))return p(n);return t&&t.endSameAsBegin&&(t.endRe=new RegExp(n.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),t.skip?R+=n:(t.excludeBegin&&(R+=n),g(),t.returnBegin||t.excludeBegin||(R=n)),u(t),t.returnBegin?0:n.length}function _(e){const t=e[0],a=n.substr(e.index),i=b(M,e,a);if(!i)return ee;const s=M;s.skip?R+=t:(s.returnEnd||s.excludeEnd||(R+=t),g(),s.excludeEnd&&(R=t));do{M.className&&k.closeNode(),M.skip||M.subLanguage||(S+=M.relevance),M=M.parent}while(M!==i.parent);return i.starts&&(i.endSameAsBegin&&(i.starts.endRe=i.endRe),u(i.starts)),s.returnEnd?0:t.length}let E={};function v(t,a){const s=a&&a[0];if(R+=t,null==s)return g(),0;if("begin"===E.type&&"end"===a.type&&E.index===a.index&&""===s){if(R+=n.slice(a.index,a.index+1),!r){const n=new Error("0 width match regex");throw n.languageName=e,n.badRule=E.rule,n}return 1}if(E=a,"begin"===a.type)return f(a);if("illegal"===a.type&&!i){const e=new Error('Illegal lexeme "'+s+'" for mode "'+(M.className||"")+'"');throw e.mode=M,e}if("end"===a.type){const e=_(a);if(e!==ee)return e}if("illegal"===a.type&&""===s)return 1;if(T>1e5&&T>3*a.index){throw new Error("potential infinite loop, way more iterations than matches")}return R+=s,s.length}const N=w(e);if(!N)throw Q(l.replace("{}",e)),new Error('Unknown language: "'+e+'"');const y=K(N,{plugins:s});let x="",M=o||y;const O={},k=new d.__emitter(d);!function(){const e=[];for(let n=M;n!==N;n=n.parent)n.className&&e.unshift(n.className);e.forEach((e=>k.openNode(e)))}();let R="",S=0,A=0,T=0,C=!1;try{for(M.matcher.considerAll();;){T++,C?C=!1:M.matcher.considerAll(),M.matcher.lastIndex=A;const e=M.matcher.exec(n);if(!e)break;const t=v(n.substring(A,e.index),e);A=e.index+t}return v(n.substr(A)),k.closeAllNodes(),k.finalize(),x=k.toHTML(),{relevance:Math.floor(S),value:x,language:e,illegal:!1,emitter:k,top:M}}catch(t){if(t.message&&t.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:t.message,context:n.slice(A-100,A+100),mode:t.mode},sofar:x,relevance:0,value:J(n),emitter:k};if(r)return{illegal:!1,relevance:0,value:J(n),emitter:k,language:e,top:M,errorRaised:t};throw t}}function h(e,n){n=n||d.languages||Object.keys(t);const a=function(e){const n={relevance:0,emitter:new d.__emitter(d),value:J(e),illegal:!1,top:g};return n.emitter.addText(e),n}(e),i=n.filter(w).filter(M).map((n=>m(n,e,!1)));i.unshift(a);const s=i.sort(((e,n)=>{if(e.relevance!==n.relevance)return n.relevance-e.relevance;if(e.language&&n.language){if(w(e.language).supersetOf===n.language)return 1;if(w(n.language).supersetOf===e.language)return-1}return 0})),[r,o]=s,l=r;return l.second_best=o,l}const p={"before:highlightElement":({el:e})=>{d.useBR&&(e.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n"))},"after:highlightElement":({result:e})=>{d.useBR&&(e.value=e.value.replace(/\n/g," "))}},f=/^(<[^>]+>|\t)+/gm,_={"after:highlightElement":({result:e})=>{d.tabReplace&&(e.value=e.value.replace(f,(e=>e.replace(/\t/g,d.tabReplace))))}};function E(e){let n=null;const t=function(e){let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n);if(t){const n=w(t[1]);return n||(X(l.replace("{}",t[1])),X("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}return n.split(/\s+/).find((e=>u(e)||w(e)))}(e);if(u(t))return;O("before:highlightElement",{el:e,language:t}),n=e;const a=n.textContent,s=t?b(a,{language:t,ignoreIllegals:!0}):h(a);O("after:highlightElement",{el:e,result:s,text:a}),e.innerHTML=s.value,function(e,n,t){const a=n?i[n]:t;e.classList.add("hljs"),a&&e.classList.add(a)}(e,t,s.language),e.result={language:s.language,re:s.relevance,relavance:s.relevance},s.second_best&&(e.second_best={language:s.second_best.language,re:s.second_best.relevance,relavance:s.second_best.relevance})}const v=()=>{if(v.called)return;v.called=!0,V("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead.");document.querySelectorAll("pre code").forEach(E)};let N=!1;function y(){if("loading"===document.readyState)return void(N=!0);document.querySelectorAll("pre code").forEach(E)}function w(e){return e=(e||"").toLowerCase(),t[e]||t[i[e]]}function x(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{i[e.toLowerCase()]=n}))}function M(e){const n=w(e);return n&&!n.disableAutodetect}function O(e,n){const t=e;s.forEach((function(e){e[t]&&e[t](n)}))}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(function(){N&&y()}),!1),Object.assign(e,{highlight:b,highlightAuto:h,highlightAll:y,fixMarkup:function(e){return V("10.2.0","fixMarkup will be removed entirely in v11.0"),V("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),n=e,d.tabReplace||d.useBR?n.replace(o,(e=>"\n"===e?d.useBR?" ":e:d.tabReplace?e.replace(/\t/g,d.tabReplace):e)):n;var n},highlightElement:E,highlightBlock:function(e){return V("10.7.0","highlightBlock will be removed entirely in v12.0"),V("10.7.0","Please use highlightElement now."),E(e)},configure:function(e){e.useBR&&(V("10.3.0","'useBR' will be removed entirely in v11.0"),V("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),d=Y(d,e)},initHighlighting:v,initHighlightingOnLoad:function(){V("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),N=!0},registerLanguage:function(n,a){let i=null;try{i=a(e)}catch(e){if(Q("Language definition for '{}' could not be registered.".replace("{}",n)),!r)throw e;Q(e),i=g}i.name||(i.name=n),t[n]=i,i.rawDefinition=a.bind(null,e),i.aliases&&x(i.aliases,{languageName:n})},unregisterLanguage:function(e){delete t[e];for(const n of Object.keys(i))i[n]===e&&delete i[n]},listLanguages:function(){return Object.keys(t)},getLanguage:w,registerAliases:x,requireLanguage:function(e){V("10.4.0","requireLanguage will be removed entirely in v11."),V("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844");const n=w(e);if(n)return n;throw new Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:M,inherit:Y,addPlugin:function(e){!function(e){e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{e["before:highlightBlock"](Object.assign({block:n.el},n))}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{e["after:highlightBlock"](Object.assign({block:n.el},n))})}(e),s.push(e)},vuePlugin:Z(e).VuePlugin}),e.debugMode=function(){r=!1},e.safeMode=function(){r=!0},e.versionString="10.7.3";for(const e in D)"object"==typeof D[e]&&n(D[e]);return Object.assign(e,D),e.addPlugin(p),e.addPlugin(G),e.addPlugin(_),e}({});function te(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var ae=function(e){const n=[{className:"strong",begin:/\*{2}([^\n]+?)\*{2}/},{className:"strong",begin:te(/\*\*/,/((\*(?!\*)|\\[^\n]|[^*\n\\])+\n)+/,/(\*(?!\*)|\\[^\n]|[^*\n\\])*/,/\*\*/),relevance:0},{className:"strong",begin:/\B\*(\S|\S[^\n]*?\S)\*(?!\w)/},{className:"strong",begin:/\*[^\s]([^\n]+\n)+([^\n]+)\*/}],t=[{className:"emphasis",begin:/_{2}([^\n]+?)_{2}/},{className:"emphasis",begin:te(/__/,/((_(?!_)|\\[^\n]|[^_\n\\])+\n)+/,/(_(?!_)|\\[^\n]|[^_\n\\])*/,/__/),relevance:0},{className:"emphasis",begin:/\b_(\S|\S[^\n]*?\S)_(?!\w)/},{className:"emphasis",begin:/_[^\s]([^\n]+\n)+([^\n]+)_/},{className:"emphasis",begin:"\\B'(?!['\\s])",end:"(\\n{2}|')",contains:[{begin:"\\\\'\\w",relevance:0}],relevance:0}];return{name:"AsciiDoc",aliases:["adoc"],contains:[e.COMMENT("^/{4,}\\n","\\n/{4,}$",{relevance:10}),e.COMMENT("^//","$",{relevance:0}),{className:"title",begin:"^\\.\\w.*$"},{begin:"^[=\\*]{4,}\\n",end:"\\n^[=\\*]{4,}$",relevance:10},{className:"section",relevance:10,variants:[{begin:"^(={1,6})[ \t].+?([ \t]\\1)?$"},{begin:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$"}]},{className:"meta",begin:"^:.+?:",end:"\\s",excludeEnd:!0,relevance:10},{className:"meta",begin:"^\\[.+?\\]$",relevance:0},{className:"quote",begin:"^_{4,}\\n",end:"\\n_{4,}$",relevance:10},{className:"code",begin:"^[\\-\\.]{4,}\\n",end:"\\n[\\-\\.]{4,}$",relevance:10},{begin:"^\\+{4,}\\n",end:"\\n\\+{4,}$",contains:[{begin:"<",end:">",subLanguage:"xml",relevance:0}],relevance:10},{className:"bullet",begin:"^(\\*+|-+|\\.+|[^\\n]+?::)\\s+"},{className:"symbol",begin:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",relevance:10},{begin:/\\[*_`]/},{begin:/\\\\\*{2}[^\n]*?\*{2}/},{begin:/\\\\_{2}[^\n]*_{2}/},{begin:/\\\\`{2}[^\n]*`{2}/},{begin:/[:;}][*_`](?![*_`])/},...n,...t,{className:"string",variants:[{begin:"``.+?''"},{begin:"`.+?'"}]},{className:"code",begin:/`{2}/,end:/(\n{2}|`{2})/},{className:"code",begin:"(`.+?`|\\+.+?\\+)",relevance:0},{className:"code",begin:"^[ \\t]",end:"$",relevance:0},{begin:"^'{3,}[ \\t]*$",relevance:10},{begin:"(link:)?(http|https|ftp|file|irc|image:?):\\S+?\\[[^[]*?\\]",returnBegin:!0,contains:[{begin:"(link|image:?):",relevance:0},{className:"link",begin:"\\w",end:"[^\\[]+",relevance:0},{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0,relevance:0}],relevance:10}]}};function ie(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var se=function(e){const n={},t={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[n]}]};Object.assign(n,{className:"variable",variants:[{begin:ie(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,n,a]};a.contains.push(s);const r={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,n]},o=e.SHEBANG({binary:`(${["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"].join("|")})`,relevance:10}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"},contains:[o,e.SHEBANG(),l,r,e.HASH_COMMENT_MODE,i,s,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},n]}};const re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],oe=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],le=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],ce=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ge=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse();function de(e){return function(...e){return e.map((e=>function(e){return e?"string"==typeof e?e:e.source:null}(e))).join("")}("(?=",e,")")}var ue=function(e){const n=(e=>({IMPORTANT:{className:"meta",begin:"!important"},HEXCOLOR:{className:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"},ATTRIBUTE_SELECTOR_MODE:{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]}}))(e),t=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[e.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/},e.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+le.join("|")+")"},{begin:"::("+ce.join("|")+")"}]},{className:"attribute",begin:"\\b("+ge.join("|")+")\\b"},{begin:":",end:"[;}]",contains:[n.HEXCOLOR,n.IMPORTANT,e.CSS_NUMBER_MODE,...t,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},{className:"built_in",begin:/[\w-]+(?=\()/}]},{begin:de(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only",attribute:oe.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...t,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}};var be=function(e){return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,variants:[{begin:/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/},{begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^--- +\d+,\d+ +----$/}]},{className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/^index/,end:/$/},{begin:/={3,}/,end:/$/},{begin:/^-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{begin:/^\*{15}$/},{begin:/^diff --git/,end:/$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}};var me=function(e){return{name:"Dockerfile",aliases:["docker"],case_insensitive:!0,keywords:"from maintainer expose env arg user onbuild stopsignal",contains:[e.HASH_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{beginKeywords:"run cmd entrypoint volume add copy workdir label healthcheck shell",starts:{end:/[^\\]$/,subLanguage:"bash"}}],illegal:""}};var he=function(e){const n=e.COMMENT(/^\s*@?rem\b/,/$/,{relevance:10});return{name:"Batch file (DOS)",aliases:["bat","cmd"],case_insensitive:!0,illegal:/\/\*/,keywords:{keyword:"if else goto for in do call exit not exist errorlevel defined equ neq lss leq gtr geq",built_in:"prn nul lpt3 lpt2 lpt1 con com4 com3 com2 com1 aux shift cd dir echo setlocal endlocal set pause copy append assoc at attrib break cacls cd chcp chdir chkdsk chkntfs cls cmd color comp compact convert date dir diskcomp diskcopy doskey erase fs find findstr format ftype graftabl help keyb label md mkdir mode more move path pause print popd pushd promt rd recover rem rename replace restore rmdir shift sort start subst time title tree type ver verify vol ping net ipconfig taskkill xcopy ren del"},contains:[{className:"variable",begin:/%%[^ ]|%[^ ]+?%|![^ ]+?!/},{className:"function",begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)",end:"goto:eof",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),n]},{className:"number",begin:"\\b\\d+",relevance:0},n]}};var pe=function(e){return{name:"Gradle",case_insensitive:!0,keywords:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,e.REGEXP_MODE]}};function fe(e){return function(...e){return e.map((e=>function(e){return e?"string"==typeof e?e:e.source:null}(e))).join("")}("(?=",e,")")}function _e(e,n={}){return n.variants=e,n}var Ee=function(e){const n="[A-Za-z0-9_$]+",t=_e([e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]})]),a={className:"regexp",begin:/~?\/[^\/\n]+\//,contains:[e.BACKSLASH_ESCAPE]},i=_e([e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]),s=_e([{begin:/"""/,end:/"""/},{begin:/'''/,end:/'''/},{begin:"\\$/",end:"/\\$",relevance:10},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE],{className:"string"});return{name:"Groovy",keywords:{built_in:"this super",literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},contains:[e.SHEBANG({binary:"groovy",relevance:10}),t,s,a,i,{className:"class",beginKeywords:"class interface trait enum",end:/\{/,illegal:":",contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{className:"meta",begin:"@[A-Za-z]+",relevance:0},{className:"attr",begin:n+"[ \t]*:",relevance:0},{begin:/\?/,end:/:/,relevance:0,contains:[t,s,a,i,"self"]},{className:"symbol",begin:"^[ \t]*"+fe(n+":"),excludeBegin:!0,end:n+":",relevance:0}],illegal:/#|<\//}};function ve(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var Ne=function(e){const n="HTTP/(2|1\\.[01])",t={className:"attribute",begin:ve("^",/[A-Za-z][A-Za-z0-9-]*/,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},a=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+n+" \\d{3})",end:/$/,contains:[{className:"meta",begin:n},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:a}},{begin:"(?=^[A-Z]+ (.*?) "+n+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:n},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:a}},e.inherit(t,{relevance:0})]}},ye="\\.([0-9](_*[0-9])*)",we="[0-9a-fA-F](_*[0-9a-fA-F])*",xe={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${ye})|\\.)?|(${ye}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${ye})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${ye})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${we})\\.?|(${we})?\\.(${we}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${we})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};var Me=function(e){var n="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",a={className:"meta",begin:"@"+n,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]};const i=xe;return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface enum",end:/[{;=]/,excludeEnd:!0,relevance:1,keywords:"class interface enum",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"class",begin:"record\\s+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,excludeEnd:!0,end:/[{;=]/,keywords:t,contains:[{beginKeywords:"record"},{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[a,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},i,a]}};const Oe="[A-Za-z$_][0-9A-Za-z$_]*",ke=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],Re=["true","false","null","undefined","NaN","Infinity"],Se=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function Ae(e){return Te("(?=",e,")")}function Te(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var Ce=function(e){const n=Oe,t="<>",a=">",i={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{const t=e[0].length+e.index,a=e.input[t];"<"!==a?">"===a&&(((e,{after:n})=>{const t=""+e[0].slice(1);return-1!==e.input.indexOf(t,n)})(e,{after:t})||n.ignoreMatch()):n.ignoreMatch()}},s={$pattern:Oe,keyword:ke,literal:Re,built_in:Se},r="\\.([0-9](_?[0-9])*)",o="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",l={className:"number",variants:[{begin:`(\\b(${o})((${r})|\\.)?|(${r}))[eE][+-]?([0-9](_?[0-9])*)\\b`},{begin:`\\b(${o})\\b((${r})\\b|\\.)?|(${r})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},c={className:"subst",begin:"\\$\\{",end:"\\}",keywords:s,contains:[]},g={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,c],subLanguage:"xml"}},d={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,c],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,c]},b={className:"comment",variants:[e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:n+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]},m=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,d,u,l,e.REGEXP_MODE];c.contains=m.concat({begin:/\{/,end:/\}/,keywords:s,contains:["self"].concat(m)});const h=[].concat(b,c.contains),p=h.concat([{begin:/\(/,end:/\)/,keywords:s,contains:["self"].concat(h)}]),f={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s,contains:p};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:s,exports:{PARAMS_CONTAINS:p},illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,d,u,b,l,{begin:Te(/[{,\n]\s*/,Ae(Te(/(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,n+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:n+Ae("\\s*:"),relevance:0}]},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[b,e.REGEXP_MODE,{className:"function",begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s,contains:p}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:t,end:a},{begin:i.begin,"on:begin":i.isTrulyOpeningTag,end:i.end}],subLanguage:"xml",contains:[{begin:i.begin,end:i.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/,excludeEnd:!0,keywords:s,contains:["self",e.inherit(e.TITLE_MODE,{begin:n}),f],illegal:/%/},{beginKeywords:"while if switch catch for"},{className:"function",begin:e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,contains:[f,e.inherit(e.TITLE_MODE,{begin:n})]},{variants:[{begin:"\\."+n},{begin:"\\$"+n}],relevance:0},{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/,end:/[{;]/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:n}),"self",f]},{begin:"(get|set)\\s+(?="+n+"\\()",end:/\{/,keywords:"get set",contains:[e.inherit(e.TITLE_MODE,{begin:n}),{begin:/\(\)/},f]},{begin:/\$[(.]/}]}};var De=function(e){const n={literal:"true false null"},t=[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],a=[e.QUOTE_STRING_MODE,e.C_NUMBER_MODE],i={end:",",endsWithParent:!0,excludeEnd:!0,contains:a,keywords:n},s={begin:/\{/,end:/\}/,contains:[{className:"attr",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE],illegal:"\\n"},e.inherit(i,{begin:/:/})].concat(t),illegal:"\\S"},r={begin:"\\[",end:"\\]",contains:[e.inherit(i)],illegal:"\\S"};return a.push(s,r),t.forEach((function(e){a.push(e)})),{name:"JSON",contains:a,keywords:n,illegal:"\\S"}},Le="\\.([0-9](_*[0-9])*)",Be="[0-9a-fA-F](_*[0-9a-fA-F])*",$e={className:"number",variants:[{begin:`(\\b([0-9](_*[0-9])*)((${Le})|\\.)?|(${Le}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:`\\b([0-9](_*[0-9])*)((${Le})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${Le})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{begin:`\\b0[xX]((${Be})\\.?|(${Be})?\\.(${Be}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${Be})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};var Ie=function(e){const n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},s={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(s);const r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(s,{className:"meta-string"})]}]},l=$e,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),g={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=g;return d.variants[1].contains=[g],g.variants[1].contains=[d],{name:"Kotlin",aliases:["kt","kts"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},t,r,o,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/,end:/>/,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[g,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,o,s,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/,end:/>/,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,o]},s,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},l]}};function je(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var ze=function(e){const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:je(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?].*?\)/,relevance:1},{begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};a.contains.push(i),i.contains.push(a);let s=[n,t];return a.contains=a.contains.concat(s),i.contains=i.contains.concat(s),s=s.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:s},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:s}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:s,end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}};var Pe=function(e){const n={keyword:"rec with let in inherit assert if else then",literal:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},t={className:"subst",begin:/\$\{/,end:/\}/,keywords:n},a={className:"string",contains:[t],variants:[{begin:"''",end:"''"},{begin:'"',end:'"'}]},i=[e.NUMBER_MODE,e.HASH_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{begin:/[a-zA-Z0-9-_]+(\s*=)/,returnBegin:!0,relevance:0,contains:[{className:"attr",begin:/\S+/}]}];return t.contains=i,{name:"Nix",aliases:["nixos"],keywords:n,contains:i}};var Ue=function(e){const n={$pattern:/-?[A-z\.\-]+\b/,keyword:"if else foreach return do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch hidden static parameter",built_in:"ac asnp cat cd CFS chdir clc clear clhy cli clp cls clv cnsn compare copy cp cpi cpp curl cvpa dbp del diff dir dnsn ebp echo|0 epal epcsv epsn erase etsn exsn fc fhx fl ft fw gal gbp gc gcb gci gcm gcs gdr gerr ghy gi gin gjb gl gm gmo gp gps gpv group gsn gsnp gsv gtz gu gv gwmi h history icm iex ihy ii ipal ipcsv ipmo ipsn irm ise iwmi iwr kill lp ls man md measure mi mount move mp mv nal ndr ni nmo npssc nsn nv ogv oh popd ps pushd pwd r rbp rcjb rcsn rd rdr ren ri rjb rm rmdir rmo rni rnp rp rsn rsnp rujb rv rvpa rwmi sajb sal saps sasv sbp sc scb select set shcm si sl sleep sls sort sp spjb spps spsv start stz sujb sv swmi tee trcm type wget where wjb write"},t={begin:"`[\\s\\S]",relevance:0},a={className:"variable",variants:[{begin:/\$\B/},{className:"keyword",begin:/\$this/},{begin:/\$[\w\d][\w\d_:]*/}]},i={className:"string",variants:[{begin:/"/,end:/"/},{begin:/@"/,end:/^"@/}],contains:[t,a,{className:"variable",begin:/\$[A-z]/,end:/[^A-z]/}]},s={className:"string",variants:[{begin:/'/,end:/'/},{begin:/@'/,end:/^'@/}]},r=e.inherit(e.COMMENT(null,null),{variants:[{begin:/#/,end:/$/},{begin:/<#/,end:/#>/}],contains:[{className:"doctag",variants:[{begin:/\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/},{begin:/\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/}]}]}),o={className:"built_in",variants:[{begin:"(".concat("Add|Clear|Close|Copy|Enter|Exit|Find|Format|Get|Hide|Join|Lock|Move|New|Open|Optimize|Pop|Push|Redo|Remove|Rename|Reset|Resize|Search|Select|Set|Show|Skip|Split|Step|Switch|Undo|Unlock|Watch|Backup|Checkpoint|Compare|Compress|Convert|ConvertFrom|ConvertTo|Dismount|Edit|Expand|Export|Group|Import|Initialize|Limit|Merge|Mount|Out|Publish|Restore|Save|Sync|Unpublish|Update|Approve|Assert|Build|Complete|Confirm|Deny|Deploy|Disable|Enable|Install|Invoke|Register|Request|Restart|Resume|Start|Stop|Submit|Suspend|Uninstall|Unregister|Wait|Debug|Measure|Ping|Repair|Resolve|Test|Trace|Connect|Disconnect|Read|Receive|Send|Write|Block|Grant|Protect|Revoke|Unblock|Unprotect|Use|ForEach|Sort|Tee|Where",")+(-)[\\w\\d]+")}]},l={className:"class",beginKeywords:"class enum",end:/\s*[{]/,excludeEnd:!0,relevance:0,contains:[e.TITLE_MODE]},c={className:"function",begin:/function\s+/,end:/\s*\{|$/,excludeEnd:!0,returnBegin:!0,relevance:0,contains:[{begin:"function",relevance:0,className:"keyword"},{className:"title",begin:/\w[\w\d]*((-)[\w\d]+)*/,relevance:0},{begin:/\(/,end:/\)/,className:"params",relevance:0,contains:[a]}]},g={begin:/using\s/,end:/$/,returnBegin:!0,contains:[i,s,{className:"keyword",begin:/(using|assembly|command|module|namespace|type)/}]},d={variants:[{className:"operator",begin:"(".concat("-and|-as|-band|-bnot|-bor|-bxor|-casesensitive|-ccontains|-ceq|-cge|-cgt|-cle|-clike|-clt|-cmatch|-cne|-cnotcontains|-cnotlike|-cnotmatch|-contains|-creplace|-csplit|-eq|-exact|-f|-file|-ge|-gt|-icontains|-ieq|-ige|-igt|-ile|-ilike|-ilt|-imatch|-in|-ine|-inotcontains|-inotlike|-inotmatch|-ireplace|-is|-isnot|-isplit|-join|-le|-like|-lt|-match|-ne|-not|-notcontains|-notin|-notlike|-notmatch|-or|-regex|-replace|-shl|-shr|-split|-wildcard|-xor",")\\b")},{className:"literal",begin:/(-)[\w\d]+/,relevance:0}]},u={className:"function",begin:/\[.*\]\s*[\w]+[ ]??\(/,end:/$/,returnBegin:!0,relevance:0,contains:[{className:"keyword",begin:"(".concat(n.keyword.toString().replace(/\s/g,"|"),")\\b"),endsParent:!0,relevance:0},e.inherit(e.TITLE_MODE,{endsParent:!0})]},b=[u,r,t,e.NUMBER_MODE,i,s,o,a,{className:"literal",begin:/\$(null|true|false)\b/},{className:"selector-tag",begin:/@\B/,relevance:0}],m={begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[].concat("self",b,{begin:"("+["string","char","byte","int","long","bool","decimal","single","double","DateTime","xml","array","hashtable","void"].join("|")+")",className:"built_in",relevance:0},{className:"type",begin:/[\.\w\d]+/,relevance:0})};return u.contains.unshift(m),{name:"PowerShell",aliases:["ps","ps1"],case_insensitive:!0,keywords:n,contains:b.concat(l,c,g,d,m)}};var Ke=function(e){var n="[ \\t\\f]*",t=n+"[:=]"+n,a="[ \\t\\f]+",i="("+t+"|"+"[ \\t\\f]+)",s="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",r="([^\\\\:= \\t\\f\\n]|\\\\.)+",o={end:i,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\\\"},{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{returnBegin:!0,variants:[{begin:s+t,relevance:1},{begin:s+a,relevance:0}],contains:[{className:"attr",begin:s,endsParent:!0,relevance:0}],starts:o},{begin:r+i,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:r,endsParent:!0,relevance:0}],starts:o},{className:"attr",relevance:0,begin:r+n+"$"}]}};function He(...e){return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}var Ze=function(e){const n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",t={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",built_in:"proc lambda",literal:"true false nil"},a={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},s=[e.COMMENT("#","$",{contains:[a]}),e.COMMENT("^=begin","^=end",{contains:[a],relevance:10}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,keywords:t},o={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?,end:/>/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:/<<[-~]?'?(\w+)\n(?:[^\n]*\n)*?\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,r]})]}]},l="[0-9](_?[0-9])*",c={className:"number",relevance:0,variants:[{begin:`\\b([1-9](_?[0-9])*|0)(\\.(${l}))?([eE][+-]?(${l})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},g={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:t},d=[o,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(s)},{className:"function",begin:He(/def\s+/,(u=n+"\\s*(\\(|;|$)",He("(?=",u,")"))),relevance:0,keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),g].concat(s)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[o,{begin:n}],relevance:0},c,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:t},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(i,s),relevance:0}].concat(i,s);var u;r.contains=d,g.contains=d;const b=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",starts:{end:"$",contains:d}}];return s.unshift(i),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(b).concat(s).concat(d)}};var Ge=function(e){const n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:/\$\{/,end:/\}/}]},t={className:"string",variants:[{begin:'"""',end:'"""'},{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},a={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},i={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},s={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[a]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[a]},i]},r={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[i]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},a,r,s,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}};var qe=function(e){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#]/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}};function Fe(e){return e?"string"==typeof e?e:e.source:null}function We(...e){return e.map((e=>Fe(e))).join("")}function Qe(...e){return"("+e.map((e=>Fe(e))).join("|")+")"}var Xe=function(e){const n=e.COMMENT("--","$"),t=["true","false","unknown"],a=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],i=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],r=i,o=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update ","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!i.includes(e))),l={begin:We(/\b/,Qe(...r),/\s*\(/),keywords:{built_in:r}};return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{$pattern:/\b[\w\.]+/,keyword:function(e,{exceptions:n,when:t}={}){const a=t;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?`${e}|0`:e))}(o,{when:e=>e.length<3}),literal:t,type:a,built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]},contains:[{begin:Qe(...s),keywords:{$pattern:/[\w\.]+/,keyword:o.concat(s),literal:t,type:a}},{className:"type",begin:Qe("double precision","large object","with timezone","without timezone")},l,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,n,{className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}};function Ve(e){return e?"string"==typeof e?e:e.source:null}function Je(e){return Ye("(?=",e,")")}function Ye(...e){return e.map((e=>Ve(e))).join("")}function en(...e){return"("+e.map((e=>Ve(e))).join("|")+")"}var nn=function(e){const n=Ye(/[A-Z_]/,Ye("(",/[A-Z0-9_.-]*:/,")?"),/[A-Z0-9_.-]*/),t={className:"symbol",begin:/&[a-z]+;|[0-9]+;|[a-f0-9]+;/},a={begin:/\s/,contains:[{className:"meta-keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},i=e.inherit(a,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{className:"meta-string"}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"meta-string"}),o={endsWithParent:!0,illegal:/,relevance:0,contains:[{className:"attr",begin:/[A-Za-z0-9._:-]+/,relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[t]},{begin:/'/,end:/'/,contains:[t]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[a,r,s,i,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[a,i,r,s]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/
+
+
+
+
+
+
+
+
springdoc-openapi java library helps to automate the generation of API documentation using spring boot projects.
+springdoc-openapi works by examining an application at runtime to infer API semantics based on spring configurations, class structure and various annotations.
+
+
+
Automatically generates documentation in JSON/YAML and HTML format APIs.
+This documentation can be completed by comments using swagger-api annotations.
+
+
+
This library supports:
+
+
+
+
+
OpenAPI 3
+
+
+
Spring-boot (v1, v2 and v3)
+
+
+
JSR-303, specifically for @NotNull, @Min, @Max, and @Size.
+
+
+
Swagger-ui
+
+
+
OAuth 2
+
+
+
GraalVM native images
+
+
+
+
+
The following video introduces the Library:
+
+
+
+
+
+
+
+
This is a community-based project, not maintained by the Spring Framework Contributors (Pivotal).
+
+
+
+
+
2. Getting Started
+
+
+
For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed)
This will automatically deploy swagger-ui to a spring-boot application:
+
+
+
+
+
Documentation will be available in HTML format, using the official swagger-ui jars
+
+
+
The Swagger UI page will then be available at http://server:port/context-path/swagger-ui.html and the OpenAPI description will be available at the following url for json format: http://server:port/context-path/v3/api-docs
+
+
+
+
server: The server name or IP
+
+
+
port: The server port
+
+
+
context-path: The context path of the application
+
+
+
+
+
+
Documentation will be available in yaml format as well, on the following path : /v3/api-docs.yaml
+
+
+
+
+
+
+
+
+
+
+For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file: .
+
The support for Spring Hateoas is available using the dependency springdoc-openapi-hateoas.
+The projects that use Spring Hateoas should combine this dependency with the springdoc-openapi-ui dependency.
+This dependency enables the support of Spring Hateoas format.
The projects that use spring-data-rest can add the following dependency in combination with the springdoc-openapi-ui dependency.
+This dependency enables the support of spring-boot-starter-data-rest types like: @RepositoryRestResource and QuerydslPredicate annotations.
For a project that uses spring-security, you should add the following dependency, in combination with the springdoc-openapi-ui dependency:
+This dependency helps ignoring @AuthenticationPrincipal in case its used on REST Controllers.
In order to display spring-boot-actuator endpoints, simply add the following property:
+
+
+
+
+
+
springdoc.show-actuator=true
+
+
+
+
Starting from the release 1.5.1, it will be possible to expose the swagger-ui and the openapi endpoints on actuator port.
+
+
+
+
+
+
+
+
+The actuator management port has to be different from the application port.
+
+
+
+
+
+
To expose the swagger-ui, on the management port, you should set
+
+
+
+
springdoc.use-management-port=true
+# This property enables the openapi and swagger-ui endpoints to be exposed beneath the actuator base path.
+management.endpoints.web.exposure.include=openapi, swagger-ui
+
+
+
+
Once enabled, you should also be able to see the springdoc-openapi endpoints under: (host and port depends on your settings)
+- http://serverName:managementPort/actuator
For the example, you should also be able to see the springdoc-openapi endpoints:
+
+
+
+
+
http://serverName:9090/actuator
+
+
+
http://serverName:9090/actuator/swagger-ui
+
+
+
http://serverName:9090/actuator/openapi
+
+
+
+
+
All the path springdoc-openapi properties are not applicable when springdoc.use-management-port=true.
+
+
+
+
+
+
+
+
+If you want to reach the application endpoints, from the swagger-ui deployed beneath the actuator base path, using a different port from your application, CORS for your endpoints on your application level should be enabled.
+
+
+
+
+
+
Additionally, it is also possible to combine this property, with the existing property to display the actuator endpoints in the swagger-ui.
+
+
+
+
springdoc.show-actuator=true
+
+
+
+
Once enabled:
+- A dedicated group for the actuator endpoints will be by default added.
+- If no group is defined for the application, a default one will be added.
+
+
+
The swagger-ui will be then accessible through the actuator port:
If the management port is different from the application port and springdoc.use-management-port is not defined but springdoc.show-actuator is set to true:
+
+
+
+
+
The swagger-ui will be then accessible through the application port. For example: http://serverName:applicationPort/swagger-ui.html
+
+
+
A dedicated group for the actuator endpoints will be by default added.
+
+
+
If no group is defined for the application, a default one will be added.
+
+
+
+
+
+
+
+
+
+
+If you want to reach the actuator endpoints for this case (different port from your application), CORS for your actuator endpoints should be enabled.
+
+
+
+
+
+
Note: The naming of these new endpoints beneath the actuator base path cannot be customized for now.
+
+
+
+
3.8. Spring Cloud Function Web support
+
+
spring-cloud-function-web exposes Java Function as REST endpoint automatically.
+* Since version v1.6.3, the support of functional endpoints has been added.
+
+
+
+
+
These starters will display the OpenAPI description of the spring-cloud-function-web endpoints.
+
+
+
+
If you are using spring-web, simply add the springdoc-openapi-ui dependency.
+
+
+
If you are using spring-webflux, simply add the springdoc-openapi-webflux-ui dependency.
+
+
+
+
+
+
+
+
The customisation of the output can be achieved programmatically through OpenApiCustomizer or with the annotations: @RouterOperations and @RouterOperation.
+For annotation usage, you have:
+* @RouterOperation: It can be used alone, if the customisation is related to a single REST API.
+When using @RouterOperation, it’s not mandatory to fill the path
+
+
+
+
+
@RouterOperation, contains the @Operation annotation.
+The @Operation annotation can also be placed on the bean method level if the property beanMethod is declared.
+
+
+
+
+
+
+
+
+
+
+Don’t forget to set operationId which is mandatory.
+
@RouterOperations: This annotation should be used to describe the multiple REST APIs exposed by spring-cloud-function-web.
+When using RouterOperations, it’s mandatory to fill the method property.
+
+
+
A @RouterOperations, contains many @RouterOperation.
If you are using spring-web, you should combine the springdoc-openapi-kotlin module with springdoc-openapi-ui.
+
+
+
If you are using spring-webflux, you should combine the springdoc-openapi-kotlin module with springdoc-openapi-webflux-ui.
+
+
+
+
+
+
3.10. Groovy support
+
+
For a project that uses Groovy, you should add the following dependency, in combination with the springdoc-openapi-ui dependency:
+This dependency improves the support of Kotlin types:
+If both a swagger-annotation description and a javadoc comment are present. The value of the swagger-annotation description will be used.
+
+
+
+
+
+
+
+
+
4. Springdoc-openapi Features
+
+
+
4.1. Adding API Information and Security documentation
+
+
The library uses spring-boot application auto-configured packages to scan for the following annotations in spring beans: OpenAPIDefinition and Info.
+These annotations declare, API Information: Title, version, licence, security, servers, tags, security and externalDocs.
+For better performance of documentation generation, declare @OpenAPIDefinition and @SecurityScheme annotations within a spring managed bean.
+
+
+
+
4.2. Error Handling for REST using @ControllerAdvice
+
+
To generate documentation automatically, make sure all the methods declare the HTTP Code responses using the annotation: @ResponseStatus
+
+
+
+
4.3. Disabling the springdoc-openapi endpoints
+
+
In order to disable the springdoc-openapi endpoint (/v3/api-docs by default) use the following property:
+
+
+
+
# Disabling the /v3/api-docs endpoint
+springdoc.api-docs.enabled=false
+
+
+
+
+
4.4. Disabling the swagger-ui
+
+
In order to disable the swagger-ui, use the following property:
+
+
+
+
# Disabling the swagger-ui
+springdoc.swagger-ui.enabled=false
+
+
+
+
+
4.5. Swagger-ui configuration
+
+
The library supports the swagger-ui official properties:
You need to declare swagger-ui properties as spring-boot properties.
+All these properties should be declared with the following prefix: springdoc.swagger-ui
+
+
+
+
4.6. Selecting the Rest Controllers to include in the documentation
+
+
Additionally, to @Hidden annotation from swagger-annotations, its possible to restrict the generated OpenAPI description using package or path configuration.
+
+
+
For the list of packages to include, use the following property:
+
+
+
+
# Packages to include
+springdoc.packagesToScan=com.package1, com.package2
+
+
+
+
For the list of paths to include, use the following property:
+
+
+
+
# Paths to include
+springdoc.pathsToMatch=/v1, /api/balance/**
+
+
+
+
+
4.7. Spring-webflux/WebMvc.fn with Functional Endpoints
+
+
Since version v1.5.0, a functional DSL has been introduced, thanks to this enhancement in the spring-framework: #25938
+
+
+
It’s an alternative functional API to the @RouterOperations annotations.
+
+
+
This is a sample DSL, to generate OpenAPI description to the webflux/WebMvc.fn REST endpoints:
+
+
+
+
@Bean
+RouterFunction<?> routes() {
+ return route().GET("/foo", HANDLER_FUNCTION, ops -> ops
+ .operationId("hello")
+ .parameter(parameterBuilder().name("key1").description("My key1 description"))
+ .parameter(parameterBuilder().name("key2").description("My key2 description"))
+ .response(responseBuilder().responseCode("200").description("This is normal response description"))
+ .response(responseBuilder().responseCode("404").description("This is another response description"))
+ ).build();
+}
+
Since version v1.3.8, the support of functional endpoints has been added.
+Two main annotations have been added for this purpose: @RouterOperations and @RouterOperation.
+
+
+
Only REST APIs with the @RouterOperations and @RouterOperation can be displayed on the swagger-ui.
+
+
+
+
+
@RouterOperation: It can be used alone, if the Router bean contains one single route related to the REST API..
+When using @RouterOperation, its not mandatory to fill the path
+
+
+
@RouterOperation, can reference directly a spring Bean (beanClass property) and the underlying method (beanMethod property): Springdoc-openapi, will then inspect this method and the swagger annotations on this method level.
@RouterOperation, contains the @Operation annotation.
+The @Operation annotation can also be placed on the bean method level if the property beanMethod is declared.
+
+
+
+
+
+
+
+
+
+
+Don’t forget to set operationId which is mandatory.
+
@RouterOperations: This annotation should be used if the Router bean contains multiple routes.
+When using RouterOperations, its mandatory to fill the path property.
+
+
+
A @RouterOperations, contains many @RouterOperation.
All the documentations filled using @RouterOperation, might be completed by the router function data.
+For that, @RouterOperation fields must help identify uniquely the concerned route.
+springdoc-openpi scans for a unique route related to a @RouterOperation annotation, using on the following criteria:
+
+
+
+
+
by path
+
+
+
by path and RequestMethod
+
+
+
by path and produces
+
+
+
by path and consumes
+
+
+
by path and RequestMethod and produces
+
+
+
by path and RequestMethod and consumes
+
+
+
by path and produces and consumes
+
+
+
by path and RequestMethod and produces and consumes
+
+
+
+
+
Some code samples are available on GITHUB of demos:
Boolean. To make spring security login-endpoint visible.
+
+
+
springdoc.pre-loading-enabled
+
false
+
Boolean. Pre-loading setting to load OpenAPI on application startup.
+
+
+
springdoc.pre-loading-locales
+
+
List of Strings.The list of locales to load OpenAPI on application startup.(comma separated) If not specified, it will preload with the default Locale.
+
+
+
springdoc.writer-with-order-by-keys
+
false
+
Boolean. Enable a deterministic/alphabetical ordering.
+
+
+
springdoc.use-management-port
+
false
+
Boolean. To expose the swagger-ui on the actuator management port.
+
+
+
springdoc.disable-i18n
+
false
+
Boolean. To disable automatic translation using i18n.
+
+
+
springdoc.show-spring-cloud-functions
+
true
+
Boolean. To display the spring-cloud-function web endpoints.
+
+
+
springdoc.api-docs.version
+
openapi_3_0
+
String. To Choose OpenAPI 3.0 or OpenAPI 3.1 (using the value OPENAPI_3_1).
+
+
+
springdoc.default-flat-param-object
+
false
+
Boolean. To default flatten parameter.
+
+
+
springdoc.default-support-form-data
+
false
+
Boolean. To default set parameters to form data when specifying api to accept form data.
+
+
+
springdoc.nullable-request-parameter-enabled
+
true
+
Boolean. To default Enable Support for nullable request parameters in Kotlin.
+
+
+
springdoc.show-oauth2-endpoints
+
false
+
Boolean. To make spring security oauth2-endpoint visible.
+
+
+
springdoc.api-docs.resolve-extensions-properties
+
false
+
Boolean. To enable support of spring property resolver for @ExtensionProperty.
+
+
+
springdoc.enable-default-api-docs
+
true
+
Boolean. To enable default OpenAPI endpoint /v3/api-docs.
+
+
+
springdoc.trim-kotlin-indent
+
false
+
Boolean. Adjust indentation when parsing the @Operation annotation in Kotlin.
+
+
+
+
+
+
5.2. swagger-ui properties
+
+
+
+
The support of the swagger-ui properties is available on springdoc-openapi. See Official documentation.
+
+
+
You can use the same swagger-ui properties in the documentation as Spring Boot properties.
+
+
+
+
+
+
+
+
+
+
+All these properties should be declared with the following prefix: springdoc.swagger-ui
+
+
+
+
+
+
+
+
+
+
+
+
+
Parameter name
+
Default Value
+
Description
+
+
+
+
+
springdoc.swagger-ui.path
+
/swagger-ui.html
+
String, For custom path of the swagger-ui HTML documentation.
+
+
+
springdoc.swagger-ui.enabled
+
true
+
Boolean. To disable the swagger-ui endpoint (/swagger-ui.html by default).
+
+
+
springdoc.swagger-ui.configUrl
+
/v3/api-docs/swagger-config
+
String. URL to fetch external configuration document from.
+
+
+
springdoc.swagger-ui.layout
+
BaseLayout
+
String. The name of a component available via the plugin system to use as the top-level layout for Swagger UI.
+
+
+
springdoc.swagger-ui.validatorUrl
+
+
By default, Swagger UI does not validate specs. You can use this parameter to set a validator URL, for example for against swagger.io’s online validator.
+
+
+
springdoc.swagger-ui.tryItOutEnabled
+
true
+
Boolean. Controls whether the "Try it out" section should be enabled by default.
+
+
+
springdoc.swagger-ui.filter
+
false
+
Boolean OR String. If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be Boolean to enable or disable, or a string, in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
+
+
+
springdoc.swagger-ui.operationsSorter
+
+
Function=(a ⇒ a). Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
+
+
+
springdoc.swagger-ui.tagsSorter
+
+
Function=(a ⇒ a). Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function see Array.prototype.sort() to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger UI.
+
+
+
springdoc.swagger-ui.oauth2RedirectUrl
+
/swagger-ui/oauth2-redirect.html
+
String. OAuth redirect URL.
+
+
+
springdoc.swagger-ui.displayOperationId
+
false
+
Boolean. Controls the display of operationId in operations list. The default is false.
+
+
+
springdoc.swagger-ui.displayRequestDuration
+
false
+
Boolean. Controls the display of the request duration (in milliseconds) for "Try it out" requests.
Number. The default expansion depth for models (set to -1 completely hide the models).
+
+
+
springdoc.swagger-ui.defaultModelExpandDepth
+
1
+
Number. The default expansion depth for the model on the model-example section.
+
+
+
springdoc.swagger-ui.defaultModelRendering
+
+
String=["example"*, "model"]. Controls how the model is shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.)
+
+
+
springdoc.swagger-ui.docExpansion
+
+
String=["list"*, "full", "none"]. Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing).
+
+
+
springdoc.swagger-ui.maxDisplayedTags
+
+
Number. If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
+
+
+
springdoc.swagger-ui.showExtensions
+
false
+
Boolean. Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema.
+
+
+
springdoc.swagger-ui.url
+
+
String.To configure, the path of a custom OpenAPI file . Will be ignored if urls is used.
+
+
+
springdoc.swagger-ui.showCommonExtensions
+
false
+
Boolean. Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields and values for Parameters.
+
+
+
springdoc.swagger-ui.supportedSubmitMethods
+
+
Array=[get, put, post, delete, options, head, patch, trace]. List of HTTP methods that have the "Try it out" feature enabled. An empty array disables "Try it out" for all operations. This does not filter the operations from the display.
+
+
+
springdoc.swagger-ui.queryConfigEnabled
+
false
+
Boolean. Disabled since v1.6.0. This parameter enables (legacy) overriding configuration parameters via URL search params. See security advisory before enabling this feature.
String. Additional query parameters added to authorizationUrl and tokenUrl.
+
+
+
springdoc.swagger-ui.disable-swagger-default-url
+
false
+
Boolean. To disable the swagger-ui default petstore url. (Available since v1.4.1).
+
+
+
springdoc.swagger-ui.urls[0].url
+
+
URL. The url of the swagger group, used by Topbar plugin. URLs must be unique among all items in this array, since they’re used as identifiers.
+
+
+
springdoc.swagger-ui.urls[0].name
+
+
String. The name of the swagger group, used by Topbar plugin. Names must be unique among all items in this array, since they’re used as identifiers.
+
+
+
springdoc.swagger-ui.urlsPrimaryName
+
+
String. The name of the swagger group which will be displayed when Swagger UI loads.
+
+
+
springdoc.swagger-ui.oauth.clientId
+
+
String. Default clientId. MUST be a string.
+
+
+
springdoc.swagger-ui.oauth.clientSecret
+
+
String. Default clientSecret. Never use this parameter in your production environment. It exposes crucial security information. This feature is intended for dev/test environments only.
+
+
+
springdoc.swagger-ui.oauth.realm
+
+
String. realm query parameter (for OAuth 1) added to authorizationUrl and tokenUrl.
+
+
+
springdoc.swagger-ui.oauth.appName
+
+
String. OAuth application name, displayed in authorization popup.
+
+
+
springdoc.swagger-ui.oauth.scopeSeparator
+
+
String. OAuth scope separator for passing scopes, encoded before calling, default value is a space (encoded value %20).
+
+
+
springdoc.swagger-ui.csrf.enabled
+
false
+
Boolean. To enable CSRF support
+
+
+
springdoc.swagger-ui.csrf.use-local-storage
+
false
+
Boolean. To get the CSRF token from the Local Storage.
+
+
+
springdoc.swagger-ui.csrf.use-session-storage
+
false
+
Boolean. To get the CSRF token from the Session Storage.
+
+
+
springdoc.swagger-ui.csrf.cookie-name
+
XSRF-TOKEN
+
String. Optional CSRF, to set the CSRF cookie name.
+
+
+
springdoc.swagger-ui.csrf.header-name
+
X-XSRF-TOKEN
+
String. Optional CSRF, to set the CSRF header name.
+
+
+
springdoc.swagger-ui.syntaxHighlight.activated
+
true
+
Boolean. Whether syntax highlighting should be activated or not.
+
+
+
springdoc.swagger-ui.syntaxHighlight.theme
+
agate
+
String. String=["agate"*, "arta", "monokai", "nord", "obsidian", "tomorrow-night"]. Highlight.js syntax coloring theme to use. (Only these 6 styles are available.)
Boolean. Only activated for the accessCode flow. During the authorization_code request to the tokenUrl, pass the Client Password using the HTTP Basic Authentication scheme (Authorization header with Basic base64encode(client_id + client_secret)).
Boolean.Only applies to authorizatonCode flows. Proof Key for Code Exchange brings enhanced security for OAuth public clients.
+
+
+
springdoc.swagger-ui.persistAuthorization
+
false
+
Boolean. If set to true, it persists authorization data and it would not be lost on browser close/refresh
+
+
+
springdoc.swagger-ui.use-root-path
+
false
+
Boolean. If set to true, the swagger-ui will be accessible from the application root path directly.
+
+
+
+
+
+
+
+
6. Springdoc-openapi Plugins
+
+
+
6.1. Maven plugin
+
+
The aim of springdoc-openapi-maven-plugin is to generate json and yaml OpenAPI description during build time.
+The plugin works during integration-tests phase, and generate the OpenAPI description.
+The plugin works in conjunction with spring-boot-maven plugin.
+
+
+
You can test it during the integration tests phase using the maven command:
+
+
+
+
mvn verify
+
+
+
+
In order to use this functionality, you need to add the plugin declaration on the plugins section of your pom.xml:
Replace swagger 2 annotations with swagger 3 annotations (it is already included with springdoc-openapi-ui dependency).
+Package for swagger 3 annotations is io.swagger.v3.oas.annotations.
+
+
+
+
@Api → @Tag
+
+
+
@ApiIgnore → @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
If issues are not created by the end of the month, the remaining ones are lost.
+
+
+
+
+
+
+
+
11. Special Thanks
+
+
+
+
+
Thank you to The Spring Team for sharing all relevant resources around Spring projects.
+
+
+
Thanks a lot JetBrains for supporting springdoc-openapi project.
+
+
+
+
+
+
+
+
+
+
+
+
12. F.A.Q
+
+
+
12.1. How can I define multiple OpenAPI definitions in one Spring Boot project?
+
+
You can define your own groups of API based on the combination of: API paths and packages to scan. Each group should have a unique groupName.
+The OpenAPI description of this group, will be available by default on:
12.20. Can springdoc-openapi generate API only for @RestController?
+
+
+
+
@RestController is equivalent to @Controller + @RequestMapping on the type level.
+
+
+
For some legacy apps, we are constrained to still support both.
+
+
+
If you need to hide the @Controller on the type level, in this case, you can use: @Hidden on controller level.
+
+
+
Please note this annotation can be also used to hide some methods from the generated documentation.
+
+
+
+
+
+
12.21. Are the following validation annotations supported : @NotEmpty@NotBlank@PositiveOrZero@NegativeOrZero?
+
+
+
+
Yes
+
+
+
+
+
+
12.22. How can I map Pageable (spring-data-commons) object to correct URL-Parameter in Swagger UI?
+
+
The support for Pageable of spring-data-commons is available out-of-the box since springdoc-openapi v1.6.0.
+For this, you have to combine @ParameterObject annotation with the Pageable type.
+
+
+
Before springdoc-openapi v1.6.0:
+
+
+
+
+
You can use as well @ParameterObject instead of @PageableAsQueryParam for HTTP GET methods.
Another solution, is to configure Pageable manually:
+
+
+
+
you will have to declare the explicit mapping of Pageable fields as Query Params and add the @Parameter(hidden = true) Pageable pageable on your pageable parameter.
+
+
+
You should also, declare the annotation @PageableAsQueryParam provided by springdoc-openapi on the method level, or declare your own if need to define your custom description, defaultValue, …
+
+
+
+
+
+
+
+
If you want to disable the support of spring Pageable Type, you can use:
12.24. How can I deploy springdoc-openapi-ui behind a reverse proxy?
+
+
+
+
If your application is running behind a proxy, a load-balancer or in the cloud, the request information (like the host, port, scheme…) might change along the way. Your application may be running on 10.10.10.10:8080, but HTTP clients should only see example.org.
+
+
+
RFC7239 "Forwarded Headers" defines the Forwarded HTTP header; proxies can use this header to provide information about the original request. You can configure your application to read those headers and automatically use that information when creating links and sending them to clients in HTTP 302 responses, JSON documents or HTML pages. There are also non-standard headers, like X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, and X-Forwarded-Prefix.
+
+
+
If the proxy adds the commonly used X-Forwarded-For and X-Forwarded-Proto headers, setting server.forward-headers-strategy to NATIVE is enough to support those. With this option, the Web servers themselves natively support this feature; you can check their specific documentation to learn about specific behavior.
+
+
+
You need to make sure the following header is set in your reverse proxy configuration: X-Forwarded-Prefix
+
+
+
For example, using Apache 2, configuration:
+
+
+
+
+
+
RequestHeader set X-Forwarded-Prefix "/custom-path"
+
+
+
+
+
+
Then, in your Spring Boot application make sure your application handles this header: X-Forwarded-For. There are two ways to achieve this:
+
+
+
+
+
+
server.use-forward-headers=true
+
+
+
+
+
+
If this is not enough, Spring Framework provides a ForwardedHeaderFilter. You can register it as a Servlet Filter in your application by setting server.forward-headers-strategy is set to FRAMEWORK.
+
+
+
Since Spring Boot 2.2, this is the new property to handle reverse proxy headers:
+
+
+
+
+
+
server.forward-headers-strategy=framework
+
+
+
+
+
+
And you can add the following bean to your application:
+
+
+
+
+
+
@Bean
+ForwardedHeaderFilter forwardedHeaderFilter() {
+ return new ForwardedHeaderFilter();
+}
+
+
+
+
+
+
12.25. Is @JsonView annotations in Spring MVC APIs supported?
+
+
+
+
Yes
+
+
+
+
+
+
12.26. Adding springdoc-openapi-ui dependency breaks my public/index.html welcome page
+
+
+
+
If you already have static content on your root, and you don’t want it to be overridden by springdoc-openapi-ui configuration, you can just define a custom configuration of the swagger-ui, in order not to override the configuration of your files from in your context-root:
12.30. How are endpoints with multiple consuming media types supported?
+
+
+
+
An overloaded method on the same class, with the same HTTP Method and path, will have as a result, only one OpenAPI Operation generated.
+
+
+
In addition, it’s recommended to have the @Operation in the level of one of the overloaded methods. Otherwise it might be overridden if it’s declared many times within the same overloaded method.
+
+
+
+
+
+
12.31. How can I get yaml and json (OpenAPI) in compile time?
+
+
+
+
You can use springdoc-openapi-maven-plugin for this functionality:
@Bean
+public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .components(new Components()
+ .addSecuritySchemes("bearer-key",
+ new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
+}
+
+
+
+
+
+
12.35. Differentiation to Springfox project
+
+
+
+
OAS 3 was released in July 2017, and there was no release of springfox to support OAS 3.
+springfox covers for the moment only swagger 2 integration with Spring Boot. The latest release date is June 2018. So, in terms of maintenance there is a big lack of support lately.
+
+
+
We decided to move forward and share the library that we already used on our internal projects, with the community.
+
+
+
The biggest difference with springfox, is that we integrate new features not covered by springfox:
+
+
+
The integration between Spring Boot and OpenAPI 3 standard.
+
+
+
We rely on on swagger-annotations and swagger-ui only official libraries.
+
+
+
We support new features on Spring 5, like spring-webflux with annotated and functional style.
+
+
+
We do our best to answer all the questions and address all issues or enhancement requests
+
+
+
+
+
+
12.36. How do I migrate to OpenAPI 3 with springdoc-openapi
+
+
+
+
There is no relation between springdoc-openapi and springfox.If you want to migrate to OpenAPI 3:
+
+
+
Remove all the dependencies and the related code to springfox
+
+
+
Add springdoc-openapi-ui dependency
+
+
+
If you don’t want to serve the UI from your root path or there is a conflict with an existing configuration, you can just change the following property:
You may have global parameters with Standard OpenAPI description.
+
+
+
If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi, you can use OpenAPI Bean.
+
+
+
You can define common parameters under parameters in the global components section and reference them elsewhere via $ref. You can also define global header parameters.
+
+
+
For this, you can override to OpenAPI Bean, and set the global headers or parameters definition on the components level.
+
+
+
+
+
+
@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"))
+ .addParameters("myHeader1", new Parameter().in("header").schema(new StringSchema()).name("myHeader1")).addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema())))
+ .info(new Info()
+ .title("Petstore API")
+ .version(appVersion)
+ .description("This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.")
+ .termsOfService("http://swagger.io/terms/")
+ .license(new License().name("Apache 2.0").url("http://springdoc.org")));
+}
+
+
+
+
+
+
12.38. Are Callbacks supported?
+
+
+
+
Yes
+
+
+
+
+
+
12.39. How can I define SecurityScheme?
+
+
+
+
You can use: @SecurityScheme annotation.
+
+
+
Or you can define it programmatically, by overriding OpenAPI Bean:
12.48. What is the URL of the swagger-ui, when I set a different context-path?
+
+
+
+
If you use different context-path:
+
+
+
+
+
+
server.servlet.context-path= /foo
+
+
+
+
+
+
The swagger-ui will be available on the following URL:
+
+
+
+
http://server:port/foo/swagger-ui.html
+
+
+
+
+
+
+
+
+
12.49. Can I customize OpenAPI object programmatically?
+
+
+
+
You can Define your own OpenAPI Bean: If you need the definitions to appear globally (within every group), no matter if the group fulfills the conditions specified on the GroupedOpenApi, you can use OpenAPI Bean.
If you need the definitions to appear within a specific group, and respect the conditions specified on the GroupedOpenApi, you can add OpenApiCustomiser to your GroupedOpenApi definition.
+
+
+
+
+
+
GroupedOpenApi.builder().group("users").pathsToMatch(paths).packagesToScan(packagedToMatch).addOpenApiCustomiser(customerGlobalHeaderOpenApiCustomiser())
+ .build()
+
+@Bean
+public OpenApiCustomiser customerGlobalHeaderOpenApiCustomiser() {
+ return openApi -> openApi.path("/foo",
+ new PathItem().get(new Operation().operationId("foo").responses(new ApiResponses()
+ .addApiResponse("default", new ApiResponse().description("")
+ .content(new Content().addMediaType("fatz", new MediaType()))))));
+}
+
+
+
+
+
+
12.50. Where can I find the source code of the demo applications?
+
+
+
+
The source code of the application is available at the following GitHub repository:
The library supports the main file types: MultipartFile, @RequestPart, FilePart
+
+
+
+
+
+
12.54. Can I use @Parameter inside @Operation annotation?
+
+
+
+
Yes, it’s supported
+
+
+
+
+
+
12.55. Why my parameter is marked as required?
+
+
+
+
Any @GetMapping parameters is marked as required, even if @RequestParam is missing.
+
+
+
You can add @Parameter(required=false) annotation if you need different behaviour.
+
+
+
Query parameters with defaultValue specified are marked as required.
+
+
+
+
+
+
12.56. How are overloaded methods with the same endpoints, but with different parameters
+
+
+
+
springdoc-openapi renders these methods as a single endpoint. It detects the overloaded endpoints, and generates parameters.schema.oneOf.
+
+
+
+
+
+
12.57. What is a proper way to set up Swagger UI to use provided spec.yml?
+
+
+
+
With this property, all the springdoc-openapi auto-configuration beans are disabled:
+
+
+
+
+
+
springdoc.api-docs.enabled=false
+
+
+
+
+
+
Then enable the minimal Beans configuration, by adding this Bean:
+
+
+
+
+
+
@Bean
+SpringDocConfiguration springDocConfiguration(){
+ return new SpringDocConfiguration();
+}
+
+@Bean
+SpringDocConfigProperties springDocConfigProperties() {
+ return new SpringDocConfigProperties();
+}
+
+@Bean
+ObjectMapperProvider objectMapperProvider(SpringDocConfigProperties springDocConfigProperties){
+ return new ObjectMapperProvider(springDocConfigProperties);
+}
+
+
+
+
+
+
+
Then configure, the path of your custom UI yaml file.
+
+
+
+
+
+
springdoc.swagger-ui.url=/api-docs.yaml
+
+
+
+
+
12.58. Is there a way to send authorization header through the @Parameter tag?
+
+
+
+
The OpenAPI 3 specification does not allow explicitly adding Authorization header.
+Note: Header parameters named Accept, Content-Type and Authorization are not allowed. To describe these headers
12.61. How can I extract fields from parameter object?
+
+
+
+
You can use springdoc annotation @ParameterObject.
+
+
+
Request parameter annotated with @ParameterObject will help adding each field of the parameter as a separate request parameter.
+
+
+
This is compatible with Spring MVC request parameters mapping to POJO object.
+
+
+
This annotation does not support nested parameter objects.
+
+
+
POJO object must contain getters for fields with mandatory prefix get. Otherwise, the swagger documentation will not show the fields of the annotated entity.
+
+
+
+
+
+
12.62. How to Integrate Open API 3 with Spring project (not Spring Boot)?
+
+
When your application is using spring without (spring-boot), you need to add beans and auto-configuration that are natively provided in spring-boot.
+
+
+
For example, lets assume you want load the swagger-ui in spring-mvc application:
+
+
+
+
+
You mainly, need to add the springdoc-openapi module
If you don’t have the spring-boot and spring-boot-autoconfigure dependencies, you need to add them. And pay attention to the compatibility matrix, between you spring.version and spring-boot.version. For example, in this case (spring.version=5.1.12.RELEASE):
Another solution, without using springdoc-openapi MonetaryAmount, would be:
+
+
+
+
+
+
SpringDocUtils.getConfig().replaceWithSchema(MonetaryAmount.class, new ObjectSchema()
+ .addProperties("amount", new NumberSchema()).example(99.96)
+ .addProperties("currency", new StringSchema().example("USD")));
+
+
+
+
+
+
12.65. How can i aggregate external endpoints (exposing OPENAPI 3 spec) inside one single application?
+
+
The properties springdoc.swagger-ui.urls.*, are suitable to configure external (/v3/api-docs url).
+For example, if you want to aggregate all the endpoints of other services, inside one single application.
+IMPORTANT: Don’t forget that CORS needs to be enabled as well.
+
+
+
+
12.66. How can use custom json/yml file instead of generated one?
+
+
If your file open-api.json, contains the OpenAPI documentation in OpenAPI 3 format.
+Then simply declare: The file name can be anything you want, from the moment your declaration is consistent yaml or json OpenAPI Spec.
+
+
+
+
springdoc.swagger-ui.url=/open-api.json
+
+
+
+
Then the file open-api.json, should be located in: src/main/resources/static
+No additional configuration is needed.
+
+
+
+
12.67. How can i enable CSRF support?
+
+
If you are using standard headers. (For example, using spring-security headers)
+If the CSRF Token is required, swagger-ui automatically sends the new XSRF-TOKEN during each HTTP REQUEST.
+
+
+
If your XSRF-TOKEN isn’t standards-based, you can use a requestInterceptor to manually capture and attach the latest xsrf token to requests programmatically via spring resource transformer:
12.69. Is @PageableDefault supported, to enhance the OpenAPI 3 documentation?
+
+
Yes, you can use it in conjunction with @ParameterObject annotation.
+Also, the spring-boot spring.data.web. and spring.data.rest.default. properties are supported since v1.4.5
+
+
+
+
12.70. How can I make spring security login-endpoint visible?
+
+
You can use the following property:
+
+
+
+
springdoc.show-login-endpoint=true
+
+
+
+
+
12.71. How can I show schema definitions even if the schema is not referenced?
The whole idea of springdoc-openapi is to get your documentation the closest to the code, with minimal code changes.
+If the code contains @Deprecated, sprindoc-openapi will consider its schema as Deprecated as well.
+If you want to declare a field on swagger as non deprecated, even with the java code, the field contains @Depreacted,
+You can use the following property that is available since release v1.4.3:
12.73. How can i display a method that returns ModelAndView?
+
+
You can use the following property:
+
+
+
+
springdoc.model-and-view-allowed=true
+
+
+
+
+
12.74. How can i have pretty-printed output of the OpenApi specification?
+
+
You can use the following property:
+
+
+
+
springdoc.writer-with-default-pretty-printer=true
+
+
+
+
+
12.75. How can i define different schemas for the same class?
+
+
Complex objects are always resolved as a reference to a schema defined in components.
+For example, let’s consider a Instance class with an workAddress and homeAddress attribute of type Address:
You can customize swagger documentation static resources located in META-INF/resources/webjars/swagger-ui/{swagger.version}/. The list of resources includes:
+
+
+
+
+
index.html
+
+
+
swagger-ui-bundle.js
+
+
+
swagger-ui.css
+
+
+
swagger-ui-standalone-preset.js
+
+
+
swagger-ui.css.map
+
+
+
swagger-ui-bundle.js.map
+
+
+
swagger-ui-standalone-preset.js.map
+
+
+
favicon-32x32.png
+
+
+
+
+
To do this, you need to extend the implementation of SwaggerIndexPageTransformer
+
+
+
+
public class SwaggerCodeBlockTransformer
+ extends SwaggerIndexPageTransformer {
+ // < constructor >
+ @Override
+ public Resource transform(HttpServletRequest request,
+ Resource resource,
+ ResourceTransformerChain transformer)
+ throws IOException {
+ if (resource.toString().contains("swagger-ui.css")) {
+ final InputStream is = resource.getInputStream();
+ final InputStreamReader isr = new InputStreamReader(is);
+ try (BufferedReader br = new BufferedReader(isr)) {
+ final String css = br.lines().collect(Collectors.joining());
+ final byte[] transformedContent = css.replace("old", "new").getBytes();
+ return new TransformedResource(resource, transformedContent);
+ } // AutoCloseable br > isr > is
+ }
+ return super.transform(request, resource, transformer);
+ }
+
+}
+
+
+
+
+
Next, add transformer @Bean to your @Configuration
+
+
+
+
@Configuration
+public class OpenApiConfig {
+ @Bean
+ public SwaggerIndexTransformer swaggerIndexTransformer(
+ SwaggerUiConfigProperties a,
+ SwaggerUiOAuthProperties b,
+ SwaggerUiConfigParameters c,
+ SwaggerWelcomeCommon d) {
+ return new SwaggerCodeBlockTransformer(a, b, c, d);
+ }
+}
+
+
+
+
+
Illustrative example
+
+
+
+
+
+
+
+
+
12.78. What is the compatibility matrix of springdoc-openapi with spring-boot ?
+
+
springdoc-openapi is compatible with spring-boot 1 and spring-boot 2.
+
+
+
In general, you should only pick the last stable version as per today 1.8.0.
+
+
+
More precisely, this the exhaustive list of spring-boot versions against which springdoc-openapi has been built:
+
+
+
+
+
+
+
+
+
spring-boot Versions
+
Minimum springdoc-openapi Versions
+
+
+
+
+
3.0.x
+
2.0.x+
+
+
+
2.7.x, 1.5.x
+
1.6.11+
+
+
+
2.6.x, 1.5.x
+
1.6.0+
+
+
+
2.5.x, 1.5.x
+
1.5.9+
+
+
+
2.4.x, 1.5.x
+
1.5.0+
+
+
+
2.3.x, 1.5.x
+
1.4.0+
+
+
+
2.2.x, 1.5.x
+
1.2.1+
+
+
+
2.0.x, 1.5.x
+
1.0.0+
+
+
+
+
+
+
12.79. Why am i getting an error: Swagger UI unable to render definition, when overriding the default spring registered HttpMessageConverter?
+
+
When overriding the default spring-boot registered HttpMessageConverter, you should have ByteArrayHttpMessageConverter registered as well to have proper springdoc-openapi support.