diff --git a/bom/pom.xml b/bom/pom.xml
index 5d8c04b819b..7e168024ef1 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -1045,6 +1045,11 @@
helidon-microprofile-openapi${helidon.version}
+
+ io.helidon.integrations.openapi-ui
+ helidon-integrations-openapi-ui
+ ${helidon.version}
+ io.helidon.webserver.cors
diff --git a/common/common/src/main/java/io/helidon/common/FeatureCatalog.java b/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
index 82987967fd8..884bf838cbe 100644
--- a/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
+++ b/common/common/src/main/java/io/helidon/common/FeatureCatalog.java
@@ -179,6 +179,11 @@ final class FeatureCatalog {
.experimental(true)
.nativeSupported(true)
.flavor(HelidonFlavor.SE));
+ add("io.helidon.integrations.openapi.ui",
+ FeatureDescriptor.builder()
+ .name("OpenAPI U/I")
+ .description("OpenAPI U/I integration")
+ .path("OpenAPI U/I"));
add("io.helidon.integrations.vault",
FeatureDescriptor.builder()
.name("HCP Vault")
diff --git a/docs/config/config_reference.adoc b/docs/config/config_reference.adoc
index be22a1d07cc..c386cf19c06 100644
--- a/docs/config/config_reference.adoc
+++ b/docs/config/config_reference.adoc
@@ -63,6 +63,7 @@ The following section lists all configurable types in Helidon.
- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig (security.providers.oidc.common)]
- xref:{rootdir}/config/io_helidon_security_providers_oidc_OidcProvider.adoc[OidcProvider (security.providers.oidc)]
- xref:{rootdir}/config/io_helidon_openapi_OpenAPISupport.adoc[OpenAPISupport (openapi)]
+- xref:{rootdir}/config/io_helidon_openapi_OpenApiUi.adoc[OpenApiUi (openapi)]
- xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig (security.providers.common)]
- xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget (security.providers.common)]
- xref:{rootdir}/config/io_helidon_common_pki_KeyConfig_PemBuilder.adoc[PemBuilder (common.pki.KeyConfig)]
diff --git a/docs/config/io_helidon_openapi_OpenAPISupport.adoc b/docs/config/io_helidon_openapi_OpenAPISupport.adoc
index 693ec8cd66a..4844e76722e 100644
--- a/docs/config/io_helidon_openapi_OpenAPISupport.adoc
+++ b/docs/config/io_helidon_openapi_OpenAPISupport.adoc
@@ -46,6 +46,7 @@ Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenAPISuppo
|`cors` |xref:{rootdir}/config/io_helidon_webserver_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Assigns the CORS settings for the OpenAPI endpoint.
|`static-file` |string |`META-INF/openapi.*` |Sets the file system path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`.
+|`ui` |xref:{rootdir}/config/io_helidon_openapi_OpenApiUi.adoc[OpenApiUi] |{nbsp} |Assigns the OpenAPI UI builder the `OpenAPISupport` service should use in preparing the U/I.
|`web-context` |string |`/openapi` |Sets the web context path for the OpenAPI endpoint.
|===
diff --git a/docs/config/io_helidon_openapi_OpenApiUi.adoc b/docs/config/io_helidon_openapi_OpenApiUi.adoc
new file mode 100644
index 00000000000..5f543655702
--- /dev/null
+++ b/docs/config/io_helidon_openapi_OpenApiUi.adoc
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+
+ Copyright (c) 2022 Oracle and/or its affiliates.
+
+ 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.
+
+///////////////////////////////////////////////////////////////////////////////
+
+ifndef::rootdir[:rootdir: {docdir}/..]
+:description: Configuration of io.helidon.openapi.OpenApiUi
+:keywords: helidon, config, io.helidon.openapi.OpenApiUi
+:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiUi
+include::{rootdir}/includes/attributes.adoc[]
+
+= OpenApiUi (openapi) Configuration
+
+// tag::config[]
+
+
+Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiUi.html[io.helidon.openapi.OpenApiUi]
+
+
+[source,text]
+.Config key
+----
+ui
+----
+
+
+
+== Configuration options
+
+
+
+.Optional configuration options
+[cols="3,3a,2,5a"]
+
+|===
+|key |type |default value |description
+
+|`enabled` |boolean |`true` |Sets whether the UI should be enabled.
+|`options` |Map<string, string> |{nbsp} |Sets implementation-specific UI options.
+|`web-context` |string |{nbsp} |web context (path) where the UI will respond
+
+|===
+
+// end::config[]
\ No newline at end of file
diff --git a/docs/config/io_helidon_openapi_SEOpenAPISupport.adoc b/docs/config/io_helidon_openapi_SEOpenAPISupport.adoc
index d111e6f6ce0..e6c4ceb68a5 100644
--- a/docs/config/io_helidon_openapi_SEOpenAPISupport.adoc
+++ b/docs/config/io_helidon_openapi_SEOpenAPISupport.adoc
@@ -58,6 +58,7 @@ openapi
|`servers.operation.*` |string[] |{nbsp} |Sets alternative servers to service the indicated operation (represented here by '*'). Repeat for multiple operations.
|`servers.path.*` |string[] |{nbsp} |Sets alternative servers to service all operations at the indicated path (represented here by '*'). Repeat for multiple paths.
|`static-file` |string |`META-INF/openapi.*` |Sets the file system path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`.
+|`ui` |xref:{rootdir}/config/io_helidon_openapi_OpenApiUi.adoc[OpenApiUi] |{nbsp} |Assigns the OpenAPI U/I builder the `OpenAPISupport` service should use in preparing the U/I.
|`web-context` |string |`/openapi` |Sets the web context path for the OpenAPI endpoint.
|===
diff --git a/docs/images/openapi-ui-screen-capture-greeting-mp-expanded.png b/docs/images/openapi-ui-screen-capture-greeting-mp-expanded.png
new file mode 100644
index 00000000000..b5a310594c0
Binary files /dev/null and b/docs/images/openapi-ui-screen-capture-greeting-mp-expanded.png differ
diff --git a/docs/images/openapi-ui-screen-capture-greeting-mp-start.png b/docs/images/openapi-ui-screen-capture-greeting-mp-start.png
new file mode 100644
index 00000000000..707e59bd771
Binary files /dev/null and b/docs/images/openapi-ui-screen-capture-greeting-mp-start.png differ
diff --git a/docs/images/openapi-ui-screen-capture-greeting-se-expanded.png b/docs/images/openapi-ui-screen-capture-greeting-se-expanded.png
new file mode 100644
index 00000000000..372ca09df30
Binary files /dev/null and b/docs/images/openapi-ui-screen-capture-greeting-se-expanded.png differ
diff --git a/docs/images/openapi-ui-screen-capture-greeting-se-start.png b/docs/images/openapi-ui-screen-capture-greeting-se-start.png
new file mode 100644
index 00000000000..29f47a63b95
Binary files /dev/null and b/docs/images/openapi-ui-screen-capture-greeting-se-start.png differ
diff --git a/docs/includes/attributes.adoc b/docs/includes/attributes.adoc
index 35c24218d31..e3f1d7d440a 100644
--- a/docs/includes/attributes.adoc
+++ b/docs/includes/attributes.adoc
@@ -77,6 +77,7 @@ endif::[]
:version-plugin-jib: 0.10.1
:version-plugin-jandex: 1.0.6
:version-lib-micrometer: 1.6.6
+:version-lib-smallrye-open-api: 2.1.16
:jdk-version: 17
@@ -204,6 +205,7 @@ endif::[]
:mp-tyrus-javadoc-base-url: {javadoc-base-url}/io.helidon.microprofile.tyrus
:mp-restclient-javadoc-base-url: {javadoc-base-url}/io.helidon.microprofile.restclient
:openapi-javadoc-base-url: {javadoc-base-url}/io.helidon.openapi
+:openapi-ui-javadoc-base-url: {javadoc-base-url}/io.helidon.integrations.openapi.ui
:reactive-base-url: {javadoc-base-url}/io.helidon.common.reactive
:scheduling-javadoc-base-url: {javadoc-base-url}/io.helidon.microprofile.scheduling
:security-integration-jersey-base-url: {javadoc-base-url}/io.helidon.security.integration.jersey
@@ -271,4 +273,7 @@ endif::[]
:openapi-generator-tool-generators-docs-url: {openapi-generator-tool-docs-url}/generators
:openapi-generator-tool-site-url: https://openapi-generator.tech
+// OpenAPI UI
+:smallrye-openapi-ui-base-url: https://github.com/smallrye/smallrye-open-api/tree/{version-lib-smallrye-open-api}/ui/open-api-ui
+
endif::attributes-included[]
diff --git a/docs/includes/openapi/openapi-generator.adoc b/docs/includes/openapi/openapi-generator.adoc
index 7333a5d4c76..1589aca811a 100644
--- a/docs/includes/openapi/openapi-generator.adoc
+++ b/docs/includes/openapi/openapi-generator.adoc
@@ -140,7 +140,7 @@ For the Maven plug-in, use elements within the `` section of the
[source,xml]
----
- petstore.yaml
+ petstore.yaml
----
* _additional properties_
diff --git a/docs/includes/openapi/openapi-ui.adoc b/docs/includes/openapi/openapi-ui.adoc
new file mode 100644
index 00000000000..65a79f118ed
--- /dev/null
+++ b/docs/includes/openapi/openapi-ui.adoc
@@ -0,0 +1,200 @@
+///////////////////////////////////////////////////////////////////////////////
+
+ Copyright (c) 2022 Oracle and/or its affiliates.
+
+ 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.
+
+///////////////////////////////////////////////////////////////////////////////
+
+ifndef::rootdir[:rootdir: {docdir}/../..]
+// Following make editing the included file a little easier
+:flavor-lc: se
+:flavor-uc: SE
+:se-flavor:
+
+// tag::preamble[]
+:feature-name: Helidon OpenAPI UI support
+:screen-capture-start: openapi-ui-screen-capture-greeting-{flavor-lc}-start.png
+:screen-capture-expanded: openapi-ui-screen-capture-greeting-{flavor-lc}-expanded.png
+// end::preamble[]
+
+// tag::intro[]
+
+== Contents
+
+- <>
+- <>
+- <>
+- <>
+- <>
+- <>
+
+// end::intro[]
+
+// tag::overview[]
+== Overview
+
+SmallRye offers an link:{smallrye-openapi-ui-base-url}[OpenAPI user interface component] which displays a web page based on your application's OpenAPI document.
+Through that UI, users can invoke the operations declared in the document.
+While not generally suitable for end-users, the OpenAPI UI can be useful for demonstrating and "test driving" your service's endpoints.
+
+The Helidon OpenAPI component allows you to integrate the SmallRye UI into your application, adding the UI web page to your application very simply.
+
+
+// end::overview[]
+
+// tag::dependencies[]
+include::{rootdir}/includes/dependencies.adoc[]
+
+[source,xml,subs=+macros]
+----
+
+ io.helidon.integrations.openapi-ui
+ helidon-integrations-openapi-ui
+ifdef::mp-flavor[ runtime]
+
+----
+
+// end::dependencies[]
+
+// tag::usage[]
+// tag::usage-start[]
+== Usage
+ifdef::se-flavor[]
+Make sure your application creates a Helidon `OpenAPISupport` instance and registers it for routing (described in detail in link:{openapi-page}[the Helidon OpenAPI documentation]). `OpenAPISupport` automatically prepares the OpenAPI UI with default settings if you also declare a dependency on the Helidon OpenAPI UI integration component as explained above. The <> section below illustrates adding OpenAPI to your application and customizing the UI behavior.
+endif::se-flavor[]
+
+After you modify, build, and start your Helidon {flavor-uc} service, you can access the OpenAPI UI by default at `http://your-host:your-port/openapi/ui`.
+Helidon also uses conventional content negotiation at `http://your-host:your-port/openapi` returning the UI to browsers (or any client that accepts HTML) and the OpenAPI document otherwise.
+
+You can customize the path using
+ifdef::se-flavor[either the API or ]
+xref:Configuration[configuration].
+
+The example below shows the UI
+ifdef::se-flavor[]
+if you modify the Helidon SE QuickStart greeting application to contain a static OpenAPI file which describes the service endpoints.
+endif::se-flavor[]
+ifdef::mp-flavor[]
+for the Helidon MP QuickStart greeting application.
+endif::mp-flavor[]
+
+.OpenAPI UI Screen for Helidon {flavor-uc} QuickStart Greeting Application
+image::{screen-capture-start}[align="center",title="Example OpenAPI UI Screen"]
+
+// end::usage-start[]
+
+// tag::usage-expanded-screen[]
+With the OpenAPI UI displayed, follow these steps to access one of your service's operations.
+
+. Find the operation you want to run and click on its row in the list.
+. The UI expands the operation, showing any input parameters and the possible responses. Click the "Try it out" button in the operation's row.
+. The UI now allows you to type into the input parameter field(s) to the right of each parameter name. Enter any required parameter values (first highlighted rectangle) and any non-required values you wish, then click "Execute" (highlighted arrow).
+. Just below the "Execute" button the UI shows several sections: +
+* the equivalent `curl` command for submitting the request with your inputs,
+* the URL used for the request, and
+* a new "Server response" section (second highlighted rectangle) containing several items from the response: +
+** HTTP status code
+** body
+** headers
+
+The next image shows the screen after you submit the "Returns a personalized greeting" operation.
+
+Note that the UI shows the actual response from invoking the operation in the "Server response" section. The "Responses" section farther below describes the possible responses from the operation as declared in the OpenAPI document for the application.
+
+.Example OpenAPI UI Screen
+image::{screen-capture-expanded}[align="center",title="Example OpenAPI UI Screen"]
+
+// end::usage-expanded-screen[]
+// end::usage[]
+
+// tag::config-intro[]
+== Configuration
+To use configuration to control how the Helidon OpenAPI UI service behaves, add an `openapi.ui` section to
+ifdef::mp-flavor[your `META-INF/microprofile-config.properties` file.]
+ifdef::se-flavor[your configuration file, such as `application.yaml`.]
+
+include::{rootdir}/config/io_helidon_openapi_OpenApiUi.adoc[tag=config,leveloffset=+1]
+The default UI `web-context` value is the web context for your `OpenAPISupport` service with the added suffix `/ui`. If you use the default web context for both `OpenAPISupport` and the UI, the UI responds at `/openapi/ui`.
+
+// end::config-intro[]
+
+// tag::config-details[]
+
+You can use configuration to affect the UI path in two ways:
+
+* Configure the OpenAPI endpoint path (the `/openapi` part).
++
+Recall that you can xref:{openapi-page}#config[configure the Helidon OpenAPI component] to change where it serves the OpenAPI document.
++
+.Configuring the OpenAPI web context
+ifdef::se-flavor[]
+[source,yaml]
+----
+openapi:
+ web-context: /my-openapi
+----
+endif::se-flavor[]
+ifdef::mp-flavor[]
+[source,properties]
+----
+openapi.web-context=/my-openapi
+----
+endif::mp-flavor[]
++
+In this case, the path for the UI component is your customized OpenAPI path with `/ui` as a suffix.
+With the example above, the UI responds at `/my-openapi/ui` and
+Helidon uses standard content negotiation at `/my-openapi` to return either the OpenAPI document or the UI.
+* Separately, configure the entire web context path for the UI independently from the web context for OpenAPI.
++
+.Configuring the OpenAPI UI web context
+ifdef::se-flavor[]
+[source,yaml]
+----
+openapi:
+ ui:
+ web-context: /my-ui
+----
+endif::se-flavor[]
+ifdef::mp-flavor[]
+[source,properties]
+----
+openapi.ui.web-context=/my-ui
+----
+endif::mp-flavor[]
++
+[NOTE]
+====
+The `openapi.ui.web-context` setting assigns the _entire_ web-context for the UI, not the suffix appended to the `OpenAPISupport` endpoint.
+====
+With this configuration, the UI responds at `/my-ui` regardless of the path for OpenAPI itself.
+
+The SmallRye OpenAPI UI component accepts several options, but they are of minimal use to application developers and they must be passed to the SmallRye UI code programmatically.
+Helidon allows you to specify these values using configuration in the `openapi.ui.options` section. Helidon then passes the corresponding options to SmallRye for you.
+To configure any of these settings, use the enum values--they are all lower case--declared in the SmallRye link:{smallrye-openapi-ui-base-url}/src/main/java/io/smallrye/openapi/ui/Option.java[`Option.java`] class as the keys in your Helidon configuration.
+
+[NOTE]
+====
+Helidon prepares several of the SmallRye options automatically based on other settings.
+Any options you configure override the values Helidon assigns, possibly interfering with the proper operation of the UI.
+====
+
+// end::config-details[]
+
+// tag::additional-info[]
+== Additional Information
+
+xref:{openapi-page}[Helidon OpenAPI {flavor-uc} documentation]
+
+link:{smallrye-openapi-ui-base-url}[SmallRye OpenAPI UI GitHub site]
+// end::additional-info[]
\ No newline at end of file
diff --git a/docs/includes/openapi/openapi.adoc b/docs/includes/openapi/openapi.adoc
index e0a7952378f..fd2c8daac03 100644
--- a/docs/includes/openapi/openapi.adoc
+++ b/docs/includes/openapi/openapi.adoc
@@ -47,6 +47,14 @@ The SPI defines an interface you can implement in your application which can mas
// end::overview[]
+// tag::mp-depc[]
+
+ io.helidon.microprofile.openapi
+ helidon-microprofile-openapi
+ runtime
+
+// end::mp-depc[]
+
// tag::furnish-openapi-info[]
==== Furnish OpenAPI information about your endpoints
@@ -139,8 +147,8 @@ class name of your class.
Once you add the {flavor-uc} OpenAPI dependency to your
ifdef::mp-flavor[project,]
ifdef::se-flavor[project and add code to create the `OpenAPISupport` object to your routing,]
-your application will automatically respond to the built-in endpoint --
-`/openapi` -- and it will return the OpenAPI document describing the endpoints
+your application automatically responds to the built-in endpoint --
+`/openapi` -- and it returns the OpenAPI document describing the endpoints
in your application.
By default, per the MicroProfile OpenAPI spec, the default format of the OpenAPI document is YAML.
diff --git a/docs/mp/openapi/openapi-ui.adoc b/docs/mp/openapi/openapi-ui.adoc
new file mode 100644
index 00000000000..f86b2a9d355
--- /dev/null
+++ b/docs/mp/openapi/openapi-ui.adoc
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+
+ Copyright (c) 2022 Oracle and/or its affiliates.
+
+ 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.
+
+///////////////////////////////////////////////////////////////////////////////
+
+= OpenAPI UI
+:toc:
+:toc-placement: preamble
+:description: Helidon MP OpenAPI UI Support
+:keywords: helidon, mp, openapi ui
+:rootdir: {docdir}/../..
+:incdir: {rootdir}/includes/openapi
+:openapi-inc: {incdir}/openapi.adoc
+:ui-inc: {incdir}/openapi-ui.adoc
+
+include::{rootdir}/includes/mp.adoc[]
+include::{rootdir}/includes/pages.adoc[]
+:javadoc-path: {openapi-ui-javadoc-base-url}/io/helidon/integrations/openapi/ui
+:openapi-javadoc-path: {openapi-javadoc-base-url}/io/helidon/openapi
+
+include::{ui-inc}[tag=preamble]
+
+include::{ui-inc}[tags=intro;overview]
+
+include::{ui-inc}[tag=dependencies]
+
+Also make sure your project has the following dependency to include OpenAPI support in your Helidon MP application.
+[source,xml]
+----
+include::{openapi-inc}[tag=mp-depc]
+----
+
+include::{ui-inc}[tag=usage]
+
+== API
+
+Your Helidon MP application does not use any API to enable or control Helidon OpenAPI UI support.
+Adding the dependency as described earlier is sufficient, and you can control the UI behavior using <>.
+
+include::{ui-inc}[tag=config-intro]
+
+include::{ui-inc}[tag=config-details]
+
+include::{ui-inc}[tag=additional-info]
\ No newline at end of file
diff --git a/docs/mp/openapi/openapi.adoc b/docs/mp/openapi/openapi.adoc
index 5e3db05910c..9b5d0c05810 100644
--- a/docs/mp/openapi/openapi.adoc
+++ b/docs/mp/openapi/openapi.adoc
@@ -46,20 +46,16 @@ include::{rootdir}/includes/dependencies.adoc[]
[source,xml,subs="attributes+"]
----
-
-
+include::{incdir}/openapi.adoc[tag=mp-depc]
+----
+If you do not use the `helidon-microprofile-bundle` also add the following dependency which defines the MicroProfile OpenAPI annotations so you can use them in your code:
+[source,xml]
+----
+ org.eclipse.microprofile.openapimicroprofile-openapi-api
-
- io.helidon.microprofile.openapi
- helidon-microprofile-openapi
- runtime
-
-
----
-<1> Defines the MicroProfile OpenAPI annotations so you can use them in your code.
-<2> Adds the Helidon MP OpenAPI runtime support.
== Usage
diff --git a/docs/se/openapi.adoc b/docs/se/openapi.adoc
deleted file mode 100644
index 11d493551e8..00000000000
--- a/docs/se/openapi.adoc
+++ /dev/null
@@ -1,123 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-
- Copyright (c) 2019, 2022 Oracle and/or its affiliates.
-
- 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.
-
-///////////////////////////////////////////////////////////////////////////////
-
-= OpenAPI
-:toc:
-:toc-placement: preamble
-:description: Helidon SE OpenAPI Support
-:keywords: helidon, se, openapi
-:feature-name: OpenAPI
-:rootdir: {docdir}/..
-
-include::{rootdir}/includes/se.adoc[]
-
-== Contents
-
-- <>
-- <>
-- <>
-- <>
-- <>
-- <>
-- <>
-
-== Overview
-
-include::{rootdir}/includes/openapi.adoc[tag=overview]
-
-include::{rootdir}/includes/dependencies.adoc[]
-
-[source,xml]
-----
-
- io.helidon.openapi
- helidon-openapi
-
-----
-
-== Usage
-
-You can very simply add support for OpenAPI to your Helidon SE application. This
-document shows what changes you need to make to your application and how to access
-the OpenAPI document for your application at runtime.
-
-=== Changing your application
-
-==== Register `OpenAPISupport` in your application routing
-
-Helidon SE provides the link:{openapi-javadoc-base-url}/OpenAPISupport.html[`OpenAPISupport`] class which your application uses to assemble the in-memory model and expose the `/openapi` endpoint to clients. You can create an instance either using a static `create` method or by instantiating its link:{openapi-javadoc-base-url}/OpenAPISupport.Builder.html[`Builder`]. The xref:#register_openapisupport[example below] illustrates one way to do this.
-
-include::{rootdir}/includes/openapi.adoc[tag=furnish-openapi-info]
-
-==== Add OpenAPI dependency
-If you implement either a model reader or a filter, add this dependency to your
-`pom.xml`:
-
-[source,xml,subs="attributes+"]
-----
-
- org.eclipse.microprofile.openapi
- microprofile-openapi-api
- {microprofile-openapi-version}
-
-----
-
-include::{rootdir}/includes/openapi.adoc[tag=usage-access-endpoint]
-
-== API
-
-include::{rootdir}/includes/openapi.adoc[tag=api]
-
-Helidon {flavor-uc} provides an API for creating and setting up the REST endpoint which serves OpenAPI documents to clients at the `/openapi` path. Use either static methods on link:{openapi-javadoc-base-url}/OpenAPISupport.html[`OpenAPISupport`] or use its link:{openapi-javadoc-base-url}/OpenAPISupport.Builder.html[`Builder`] to create an instance of `OpenAPISupport`. Then add that instance to your application's routing. The <<#register_openapisupport,example>> below shows how to do this.
-
-== Configuration
-
-Helidon SE OpenAPI configuration supports the following settings:
-
-include::{rootdir}/config/io_helidon_openapi_SEOpenAPISupport.adoc[leveloffset=+1,tag=config]
-
-
-
-== Examples
-
-Helidon SE provides a link:{helidon-github-tree-url}/examples/openapi[complete OpenAPI example]
-based on the SE QuickStart sample app which includes a model reader and a filter.
-
-Most Helidon {flavor-uc} applications need only to create and register `OpenAPISupport`.
-
-[#register_openapisupport]
-=== Register `OpenAPISupport`
-
-.Java Code to Register `OpenAPISupport` for Routing
-[source,java]
-----
-Config config = Config.create();
-return Routing.builder()
- .register(JsonSupport.create())
- .register(OpenAPISupport.create(config)) // <1>
- .register(health) // Health at "/health"
- .register(metrics) // Metrics at "/metrics"
- .register("/greet", greetService)
- .build();
-----
-<1> Adds the `OpenAPISupport` service to your server.
-
-If you need more control over the `OpenAPISupport` instance, invoke `OpenAPISupport.builder()` to get an `OpenAPISupport.Builder` object and work with it.
-
-== Additional Information
-include::{rootdir}/includes/openapi.adoc[tag=additional-building-jandex]
\ No newline at end of file
diff --git a/docs/se/openapi/openapi-ui.adoc b/docs/se/openapi/openapi-ui.adoc
new file mode 100644
index 00000000000..9927147b707
--- /dev/null
+++ b/docs/se/openapi/openapi-ui.adoc
@@ -0,0 +1,133 @@
+///////////////////////////////////////////////////////////////////////////////
+
+ Copyright (c) 2022 Oracle and/or its affiliates.
+
+ 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.
+
+///////////////////////////////////////////////////////////////////////////////
+
+= OpenAPI UI
+:toc:
+:toc-placement: preamble
+:description: Helidon SE OpenAPI UI Support
+:keywords: helidon, se, openapi ui
+:rootdir: {docdir}/../..
+:incdir: {rootdir}/includes/openapi
+:ui-inc: {incdir}/openapi-ui.adoc
+
+include::{rootdir}/includes/se.adoc[]
+include::{rootdir}/includes/pages.adoc[]
+:javadoc-path: {openapi-ui-javadoc-base-url}/io/helidon/integrations/openapi/ui
+:openapi-javadoc-path: {openapi-javadoc-base-url}/io/helidon/openapi
+
+include::{ui-inc}[tag=preamble]
+
+include::{ui-inc}[tags=intro;overview]
+
+include::{ui-inc}[tag=dependencies]
+
+Also, make sure your project has the following dependency.
+
+include::{openapi-page}[tag=depc]
+
+This dependency allows your application to create, configure, and register the `OpenAPISupport` service.
+
+include::{ui-inc}[tag=usage]
+
+== API
+=== Creating `OpenAPISupport` with Automatic UI Behavior
+With the Helidon OpenAPI UI dependency in your `pom.xml` file, any `OpenAPISupport` object your application builds prepares the default OpenAPI UI behavior, possibly modified by any UI settings you have in your configuration.
+
+[source,java]
+.Create `OpenAPISupport` with automatic UI
+----
+Config config = Config.create(); // <1>
+Config openApiConfig = config.get(OpenAPISupport.Builder.CONFIG_KEY)); // <2>
+
+OpenAPISupport openApiSupport =
+ OpenAPISupport.builder()
+ .config(openApiConfig) // <3>
+ .build();
+----
+<1> Load the configuration.
+<2> Extract the `OpenAPISupport` configuration.
+<3> Build the `OpenAPISupport` instance using the configuration.
+
+If your code invokes the `OpenAPISupport.Builder` `config` method, Helidon automatically applies the `ui` section of the `openapi` configuration to the UI.
+
+=== Customizing the UI Behavior
+You can control some of the behavior of the UI programmatically in two steps:
+
+. Create an link:{javadoc-path}/OpenApiUi.Builder.html[`OpenApiUi.Builder`] and invoke methods on it to set the UI behavior.
+. Invoke the `ui` method on link:{openapi-javadoc-base-url}/io.helidon.openapi.OpenAPISupport.Builder.html[`OpenAPISupport.Builder`], passing the `OpenApiUi.Builder` you prepared above.
+
+The following example illustrates these steps, combining configuration with explicit programmatic settings.
+
+[source,java]
+.Create `OpenApiUi` and `OpenAPISupport` instances
+----
+Config config = Config.create(); // <1>
+Config openApiConfig = config.get(OpenAPISupport.Builder.CONFIG_KEY)); // <2>
+
+OpenApiUi.Builder uiBuilder =
+ OpenApiUi.builder() // <3>
+ .webContext("/my-openapi-ui"); // <4>
+
+OpenAPISupport openApiSupport =
+ OpenAPISupport.builder() // <5>
+ .ui(uiBuilder)
+ .config(openApiConfig) // <6>
+ .build();
+
+
+----
+<1> Load the configuration.
+<2> Extract the `OpenAPISupport` configuration.
+<3> Create the `OpenApiUi.Builder` instance.
+<4> Explicitly set the web context where the UI should respond.
+<5> Create the `OpenAPISupport` instance using the `OpenApiUi.Builder` just created.
+You can refine the behavior of the `OpenAPISupport` object by invoking additional methods on its builder before invoking its `build` method.
+<6> Apply the `openapi` configuration to the `OpenAPISupport` builder. This also automatically applies any `openapi.ui` configuration to the UI.
+
+The order in which your code invokes the methods on `OpenApiUi.Builder` and `OpenAPISupport.Builder` determines the outcome.
+For instance, the example above sets the UI on the `OpenAPISupport.Builder` _before_ applying configuration.
+If the configuration contains a setting for the UI's `web-context` value then the UI uses the configured value, not the programmatic value, because your code applied the configuration later.
+Your code should typically apply configuration _after_ setting any values programmatically.
+Doing so allows users or deployers of your service to set the behavior using configuration according to their particular needs which your code might not be able to anticipate.
+
+[NOTE]
+====
+The `webContext(String)` method on `OpenApiUi.Builder` sets the web context where the UI should respond instead of the default `/openapi/ui`.
+Helidon uses the provided string to set the _entire_ web context for the UI, not as a suffix appended to the web context for the `OpenAPISupport` service.
+====
+
+=== Registering `OpenAPISupport`
+Whether or not your code tailors the UI or `OpenAPISupport` behavior, it must register the resulting `OpenAPISupport` instance so that the OpenAPI and UI endpoints can respond correctly.
+
+[source,java]
+.Register services for routing
+----
+Routing.builder()
+ .register(openApiSupport)
+ // Add registrations of your service(s) and other Helidon services you need.
+ .build();
+----
+
+The UI is implemented as part of the `OpenAPISupport` service which registers the UI automatically.
+Your code does not register the UI explicitly.
+
+include::{ui-inc}[tag=config-intro]
+
+include::{ui-inc}[tag=config-details]
+
+include::{ui-inc}[tag=additional-info]
\ No newline at end of file
diff --git a/docs/se/openapi/openapi.adoc b/docs/se/openapi/openapi.adoc
index 0c9f1b1e814..9a45837debd 100644
--- a/docs/se/openapi/openapi.adoc
+++ b/docs/se/openapi/openapi.adoc
@@ -26,6 +26,7 @@
:incdir: {rootdir}/includes/openapi
include::{rootdir}/includes/se.adoc[]
+:javadoc-path: {openapi-javadoc-base-url}/io.helidon.openapi
== Contents
@@ -43,6 +44,7 @@ include::{incdir}/openapi.adoc[tag=overview]
include::{rootdir}/includes/dependencies.adoc[]
+// tag::depc[]
[source,xml]
----
@@ -50,6 +52,7 @@ include::{rootdir}/includes/dependencies.adoc[]
helidon-openapi
----
+// end::depc[]
== Usage
@@ -61,7 +64,7 @@ the OpenAPI document for your application at runtime.
==== Register `OpenAPISupport` in your application routing
-Helidon SE provides the link:{openapi-javadoc-base-url}/OpenAPISupport.html[`OpenAPISupport`] class which your application uses to assemble the in-memory model and expose the `/openapi` endpoint to clients. You can create an instance either using a static `create` method or by instantiating its link:{openapi-javadoc-base-url}/OpenAPISupport.Builder.html[`Builder`]. The xref:#register_openapisupport[example below] illustrates one way to do this.
+Helidon SE provides the link:{javadoc-path}/OpenAPISupport.html[`OpenAPISupport`] class which your application uses to assemble the in-memory model and expose the `/openapi` endpoint to clients. You can create an instance either using a static `create` method or by instantiating its link:{javadoc-path}/OpenAPISupport.Builder.html[`Builder`]. The xref:#register_openapisupport[example below] illustrates one way to do this.
include::{incdir}/openapi.adoc[tag=furnish-openapi-info]
@@ -84,8 +87,9 @@ include::{incdir}/openapi.adoc[tag=usage-access-endpoint]
include::{incdir}/openapi.adoc[tag=api]
-Helidon {flavor-uc} provides an API for creating and setting up the REST endpoint which serves OpenAPI documents to clients at the `/openapi` path. Use either static methods on link:{openapi-javadoc-base-url}/OpenAPISupport.html[`OpenAPISupport`] or use its link:{openapi-javadoc-base-url}/OpenAPISupport.Builder.html[`Builder`] to create an instance of `OpenAPISupport`. Then add that instance to your application's routing. The <<#register_openapisupport,example>> below shows how to do this.
+Helidon {flavor-uc} provides an API for creating and setting up the REST endpoint which serves OpenAPI documents to clients at the `/openapi` path. Use either static methods on link:{javadoc-path}/OpenAPISupport.html[`OpenAPISupport`] or use its link:{javadoc-base}/OpenAPISupport.Builder.html[`Builder`] to create an instance of `OpenAPISupport`. Then add that instance to your application's routing. The <<#register_openapisupport,example>> below shows how to do this.
+[[config]]
== Configuration
Helidon SE OpenAPI configuration supports the following settings:
diff --git a/docs/sitegen.yaml b/docs/sitegen.yaml
index d300fe9b10f..cb72050e5fa 100644
--- a/docs/sitegen.yaml
+++ b/docs/sitegen.yaml
@@ -173,6 +173,7 @@ backend:
sources:
- "openapi.adoc"
- "openapi-generator.adoc"
+ - "openapi-ui.adoc"
- type: "MENU"
title: "Integrations"
dir: "integrations"
@@ -384,6 +385,7 @@ backend:
sources:
- "openapi.adoc"
- "openapi-generator.adoc"
+ - "openapi-ui.adoc"
- type: "MENU"
title: "Integrations"
dir: "integrations"
diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
index 293e03bf641..87795470565 100644
--- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
+++ b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2022 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,4 +17,11 @@
/**
* Quickstart MicroProfile example.
*/
+@OpenAPIDefinition(info = @Info(title = "Helidon MP QuickStart Example",
+ version = "1.0.0",
+ description = "A very simple application to reply with friendly greetings")
+)
package io.helidon.examples.quickstart.mp;
+
+import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
+import org.eclipse.microprofile.openapi.annotations.info.Info;
diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
index ca190d47ecf..fe70bc6d0d0 100644
--- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
+++ b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2019, 2022 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,4 +17,12 @@
/**
* Quickstart MicroProfile example.
*/
+@OpenAPIDefinition(info = @Info(title = "Helidon MP QuickStart Example",
+ version = "1.0.0",
+ description = "A very simple application to reply with friendly greetings")
+)
package io.helidon.examples.quickstart.mp;
+
+import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
+import org.eclipse.microprofile.openapi.annotations.info.Info;
+
diff --git a/integrations/micrometer/cdi/pom.xml b/integrations/micrometer/cdi/pom.xml
index 143978b1b43..38fdb01c1f7 100644
--- a/integrations/micrometer/cdi/pom.xml
+++ b/integrations/micrometer/cdi/pom.xml
@@ -115,6 +115,11 @@
helidon-microprofile-tests-junit5test
+
+ io.helidon.config
+ helidon-config-testing
+ test
+
diff --git a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java
index bbfb288db1a..c38ac5b19df 100644
--- a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java
+++ b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2022 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@
import jakarta.ws.rs.core.MediaType;
import org.junit.jupiter.api.Test;
+import static io.helidon.config.testing.MatcherWithRetry.assertThatWithRetry;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -83,7 +85,7 @@ void testTimer() {
}
@Test
- public void testSlowTimer() {
+ public void testSlowTimer() throws InterruptedException {
int exp = 3;
AtomicReference result = new AtomicReference<>();
IntStream.range(0, exp).forEach(
@@ -95,11 +97,11 @@ public void testSlowTimer() {
assertThat("Returned from HTTP request", result.get(), is(HelloWorldResource.SLOW_RESPONSE));
Timer slowTimer = registry.timer(HelloWorldResource.SLOW_MESSAGE_TIMER);
assertThat("Slow message timer", slowTimer, is(notNullValue()));
- assertThat("Slow message timer count", slowTimer.count(), is((long) exp));
+ assertThatWithRetry("Slow message timer count", slowTimer::count, is((long) exp));
}
@Test
- public void testFastFailCounter() {
+ public void testFastFailCounter() throws InterruptedException {
int exp = 8;
IntStream.range(0, exp).forEach(
i -> {
@@ -116,7 +118,7 @@ public void testFastFailCounter() {
Counter counter = registry.counter(HelloWorldResource.FAST_MESSAGE_COUNTER);
assertThat("Failed message counter", counter, is(notNullValue()));
- assertThat("Failed message counter count", counter.count(), is((double) exp / 2));
+ assertThatWithRetry("Failed message counter count", counter::count, is((double) exp / 2));
}
@Test
@@ -134,7 +136,7 @@ public void testSlowFailNoCounter() {
}
@Test
- public void testSlowFailCounter() {
+ public void testSlowFailCounter() throws InterruptedException {
int exp = 6;
IntStream.range(0, exp).forEach(
i -> {
@@ -151,7 +153,7 @@ public void testSlowFailCounter() {
Counter counter = registry.counter(HelloWorldResource.SLOW_MESSAGE_FAIL_COUNTER);
assertThat("Failed message counter", counter, is(notNullValue()));
- assertThat("Failed message counter count", counter.count(), is((double) 3));
+ assertThatWithRetry("Failed message counter count", counter::count, is((double) 3));
}
void checkMicrometerURL(int iterations) {
diff --git a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/MeteredBeanTest.java b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/MeteredBeanTest.java
index 88d80538485..27ad240967f 100644
--- a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/MeteredBeanTest.java
+++ b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/MeteredBeanTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2022 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
+import static io.helidon.config.testing.MatcherWithRetry.assertThatWithRetry;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -39,25 +41,29 @@ public class MeteredBeanTest {
MeterRegistry registry;
@Test
- public void testSimpleCounted() {
+ public void testSimpleCounted() throws InterruptedException {
int exp = 3;
IntStream.range(0, exp).forEach(i -> meteredBean.count());
- assertThat("Value from simple counted meter", registry.counter(MeteredBean.COUNTED).count(), is((double) exp));
+ assertThatWithRetry("Value from simple counted meter", () -> registry.counter(MeteredBean.COUNTED).count(),
+ is((double) exp));
}
@Test
- public void testSinglyTimed() {
+ public void testSinglyTimed() throws InterruptedException {
int exp = 4;
IntStream.range(0, exp).forEach(i -> meteredBean.timed());
- assertThat("Count from singly-timed meter", registry.timer(MeteredBean.TIMED_1).count(), is((long) exp));
+ assertThatWithRetry("Count from singly-timed meter", () -> registry.timer(MeteredBean.TIMED_1).count(),
+ is((long) exp));
}
@Test
- public void testDoublyTimed() {
+ public void testDoublyTimed() throws InterruptedException {
int exp = 5;
IntStream.range(0, exp).forEach(i -> meteredBean.timedA());
- assertThat("Count from doubly-timed meter (A)", registry.timer(MeteredBean.TIMED_A).count(), is((long) exp));
- assertThat("Count from doubly-timed meter (B)", registry.timer(MeteredBean.TIMED_B).count(), is((long) exp));
+ assertThatWithRetry("Count from doubly-timed meter (A)", () -> registry.timer(MeteredBean.TIMED_A).count(),
+ is((long) exp));
+ assertThatWithRetry("Count from doubly-timed meter (B)", () -> registry.timer(MeteredBean.TIMED_B).count(),
+ is((long) exp));
}
@Test
diff --git a/integrations/openapi-ui/pom.xml b/integrations/openapi-ui/pom.xml
new file mode 100644
index 00000000000..06f9936a70a
--- /dev/null
+++ b/integrations/openapi-ui/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+
+ 4.0.0
+
+ io.helidon.integrations
+ helidon-integrations-project
+ 3.0.3-SNAPSHOT
+
+
+ io.helidon.integrations.openapi-ui
+ helidon-integrations-openapi-ui
+
+ Helidon OpenAPI UI Integration
+
+
+ Integration in Helidon of the OpenAPI UI
+
+
+
+
+
+ io.helidon.webserver
+ helidon-webserver
+
+
+ io.helidon.service-common
+ helidon-service-common-rest
+
+
+ io.helidon.openapi
+ helidon-openapi
+
+
+ io.helidon.webserver
+ helidon-webserver-static-content
+
+
+ io.smallrye
+ smallrye-open-api-ui
+ ${version.lib.smallrye-openapi}
+
+
+ io.helidon.config
+ helidon-config-metadata
+ provided
+ true
+
+
+ io.helidon.config
+ helidon-config-metadata-processor
+ provided
+ true
+
+
+ io.helidon.microprofile.bundles
+ helidon-microprofile
+ test
+
+
+ io.helidon.microprofile.tests
+ helidon-microprofile-tests-junit5
+
+
+ io.helidon.webclient
+ helidon-webclient
+ test
+
+
+ io.helidon.config
+ helidon-config-testing
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+
diff --git a/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFactoryFull.java b/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFactoryFull.java
new file mode 100644
index 00000000000..4ac7744a4e9
--- /dev/null
+++ b/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFactoryFull.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+package io.helidon.integrations.openapi.ui;
+
+import io.helidon.openapi.OpenApiUiFactory;
+
+/**
+ * Implementation of the {@link io.helidon.openapi.OpenApiUiFactory} contract for a full implementation of
+ * {@link io.helidon.openapi.OpenApiUi}.
+ */
+public class OpenApiUiFactoryFull implements OpenApiUiFactory {
+
+ /**
+ * Creates a new instance of the factory for a full UI implementation.
+ */
+ public OpenApiUiFactoryFull() {
+ }
+
+ @Override
+ public OpenApiUiFull.Builder builder() {
+ return OpenApiUiFull.builder();
+ }
+}
diff --git a/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFull.java b/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFull.java
new file mode 100644
index 00000000000..ad1d8f87abb
--- /dev/null
+++ b/integrations/openapi-ui/src/main/java/io/helidon/integrations/openapi/ui/OpenApiUiFull.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2022 Oracle and/or its affiliates.
+ *
+ * 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.
+ */
+
+package io.helidon.integrations.openapi.ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import io.helidon.common.http.Http;
+import io.helidon.common.http.MediaType;
+import io.helidon.config.Config;
+import io.helidon.openapi.OpenApiUi;
+import io.helidon.openapi.OpenApiUiBase;
+import io.helidon.webserver.Routing;
+import io.helidon.webserver.ServerRequest;
+import io.helidon.webserver.ServerResponse;
+import io.helidon.webserver.staticcontent.StaticContentSupport;
+
+import io.smallrye.openapi.ui.IndexHtmlCreator;
+import io.smallrye.openapi.ui.Option;
+
+/**
+ * Support for the OpenAPI UI component from SmallRye.
+ *
+ * This service supports Helidon configuration of the UI and furnishes Helidon-specific defaults for some settings.
+ *
+ */
+class OpenApiUiFull extends OpenApiUiBase {
+
+ /**
+ *
+ * @return new builder for an {@code OpenApiUiFull} service
+ */
+ static OpenApiUiFull.Builder builder() {
+ return new Builder();
+ }
+
+ private static final String LOGO_RESOURCE = "logo.svg";
+ private static final String HELIDON_IO_LINK = "https://helidon.io";
+
+ private static final Logger LOGGER = Logger.getLogger(OpenApiUiFull.class.getName());
+
+ private static final MediaType[] SUPPORTED_TEXT_MEDIA_TYPES_AT_UI_ENDPOINT = new MediaType[] {
+ MediaType.TEXT_HTML,
+ MediaType.TEXT_PLAIN,
+ MediaType.TEXT_YAML
+ };
+
+ private static final MediaType[] SUPPORTED_TEXT_MEDIA_TYPES_AT_OPENAPI_ENDPOINT = new MediaType[] {
+ MediaType.TEXT_HTML,
+ MediaType.TEXT_PLAIN
+ };
+
+ private final byte[] indexHtml;
+
+ private OpenApiUiFull(Builder builder) {
+ super(builder, builder.documentPreparer(), builder.openApiSupportWebContext());
+ Map
+ *
+ * Combine with {@link io.helidon.config.testing.OptionalMatcher}:
+ *