This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 7d1e0b8f1422 CAMEL-18552: Add camel-jbang --openapi-ui with Swagger UI 
at /q/openapi
7d1e0b8f1422 is described below

commit 7d1e0b8f142241cb8023cb0a1058ee6b29ca8cba
Author: Omar Atie <[email protected]>
AuthorDate: Mon Aug 3 03:04:48 2026 -0700

    CAMEL-18552: Add camel-jbang --openapi-ui with Swagger UI at /q/openapi
    
    Expose bundled Swagger UI on the embedded management server and wire
    the JBang --openapi-ui flag to enable REST OpenAPI at /q/openapi.json.
    
    Closes #25202
    
    Co-authored-by: Cursor <[email protected]>
---
 .../org/apache/camel/catalog/docs/main.adoc        |   4 +-
 .../jbang/camel-jbang-configuration-metadata.json  |   1 +
 .../main/camel-main-configuration-metadata.json    |   2 +
 components/camel-platform-http-main/pom.xml        |  12 ++
 .../http/main/DefaultMainHttpServerFactory.java    |   2 +
 .../platform/http/main/ManagementHttpServer.java   |  29 +++++
 .../platform/http/main/OpenApiUiSupport.java       | 144 +++++++++++++++++++++
 .../http/main/OpenApiUiHttpServerTest.java         |  95 ++++++++++++++
 .../platform/http/main/OpenApiUiRestMainTest.java  |  96 ++++++++++++++
 .../platform/http/main/OpenApiUiSupportTest.java   |  53 ++++++++
 ...entServerConfigurationPropertiesConfigurer.java |  14 ++
 .../camel-main-configuration-metadata.json         |   2 +
 core/camel-main/src/main/docs/main.adoc            |   4 +-
 ...ttpManagementServerConfigurationProperties.java |  45 +++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    |   8 ++
 .../ROOT/pages/camel-jbang-configuration.adoc      |   3 +-
 .../modules/ROOT/pages/camel-jbang-managing.adoc   |  17 +++
 .../pages/jbang-commands/camel-jbang-debug.adoc    |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-dev.adoc |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-run.adoc |   1 +
 .../META-INF/camel-jbang-commands-metadata.json    |   6 +-
 .../camel-jbang-configuration-metadata.json        |   1 +
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  39 ++++++
 .../dsl/jbang/core/common/CamelJBangConstants.java |   4 +
 .../core/commands/RunOpenApiUiOptionsTest.java     |  74 +++++++++++
 .../java/org/apache/camel/main/KameletMain.java    |  28 ++++
 parent/pom.xml                                     |   1 +
 .../maven/packaging/PrepareCamelJBangMojo.java     |   5 +
 28 files changed, 686 insertions(+), 6 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
index 71ff06d3aee5..352d5a8e8fd5 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
@@ -225,7 +225,7 @@ The camel.server supports 21 options, which are listed 
below.
 
 
 === Camel Embedded HTTP management Server (only for standalone; not Spring 
Boot or Quarkus) configurations
-The camel.management supports 27 options, which are listed below.
+The camel.management supports 29 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -251,6 +251,8 @@ The camel.management supports 27 options, which are listed 
below.
 | *camel.management.jwtKeystorePath* | Path to the keystore file used for JWT 
tokens validation. |  | String
 | *camel.management.jwtKeystoreType* | Type of the keystore used for JWT 
tokens validation (jks, pkcs12, etc.). |  | String
 | *camel.management.metricsEnabled* | Whether to enable metrics. If enabled 
then you can access metrics on context-path: /observe/metrics | false | boolean
+| *camel.management.openapiUiEnabled* | Whether to enable Swagger UI for REST 
DSL OpenAPI documents. If enabled then you can browse the API at context-path: 
/q/openapi. The OpenAPI document is expected at openapiUiSpecPath (by default 
/q/openapi.json from REST DSL apiContextPath ). | false | boolean
+| *camel.management.openapiUiSpecPath* | Path or URL of the OpenAPI document 
loaded by Swagger UI at /q/openapi. | /q/openapi.json | String
 | *camel.management.path* | Context-path to use for embedded HTTP server | / | 
String
 | *camel.management.port* | Port to use for binding embedded HTTP management 
server. Use 0 to dynamic assign a free random port number. | 8080 | int
 | *camel.management.sendEnabled* | Whether to enable sending messages to Camel 
via HTTP. This makes it possible to use Camel to send messages to Camel 
endpoint URIs via HTTP. | false | boolean
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
index 4f02be84a402..2009c64f7a0c 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
@@ -36,6 +36,7 @@
     { "name": "camel.jbang.mavenWrapper", "required": false, "description": 
"Include Maven Wrapper files in the exported project", "type": "boolean", 
"javaType": "boolean", "defaultValue": true, "secret": false },
     { "name": "camel.jbang.metrics", "required": false, "description": 
"Metrics (Micrometer and Prometheus) at \/observe\/metrics on local HTTP server 
(port 8080 by default) when running standalone Camel", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false, "deprecated": 
true },
     { "name": "camel.jbang.openApi", "required": false, "description": "File 
name of open-api spec file (JSON or YAML) to generate routes from the 
swagger\/openapi API spec file.", "type": "string", "javaType": "String", 
"secret": false },
+    { "name": "camel.jbang.openapiUi", "required": false, "description": 
"Swagger UI for REST OpenAPI at \/q\/openapi on local HTTP server (port 8080 by 
default)", "type": "boolean", "javaType": "boolean", "defaultValue": false, 
"secret": false, "security": "insecure:dev" },
     { "name": "camel.jbang.packageScanJars", "required": false, "description": 
"Whether to automatic package scan JARs for custom Spring or Quarkus beans 
making them available for Camel CLI", "label": "advanced", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false },
     { "name": "camel.jbang.parentPom", "required": false, "description": 
"Parent POM coordinate (groupId:artifactId:version) to use in the exported 
project", "type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.prompt", "required": false, "description": "Allow 
user to type in required parameters in prompt if not present in application", 
"label": "advanced", "type": "boolean", "javaType": "boolean", "defaultValue": 
false, "secret": false },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index feb0abb216fb..d16fb079e975 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -310,6 +310,8 @@
     { "name": "camel.management.jwtKeystorePath", "required": false, 
"description": "Path to the keystore file used for JWT tokens validation.", 
"sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.management.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.management.metricsEnabled", "required": false, 
"description": "Whether to enable metrics. If enabled then you can access 
metrics on context-path: \/observe\/metrics", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
+    { "name": "camel.management.openapiUiEnabled", "required": false, 
"description": "Whether to enable Swagger UI for REST DSL OpenAPI documents. If 
enabled then you can browse the API at context-path: \/q\/openapi. The OpenAPI 
document is expected at openapiUiSpecPath (by default \/q\/openapi.json from 
REST DSL apiContextPath ).", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": [...]
+    { "name": "camel.management.openapiUiSpecPath", "required": false, 
"description": "Path or URL of the OpenAPI document loaded by Swagger UI at 
\/q\/openapi.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/q\/openapi.json", 
"secret": false },
     { "name": "camel.management.path", "required": false, "description": 
"Context-path to use for embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/", "secret": false 
},
     { "name": "camel.management.port", "required": false, "description": "Port 
to use for binding embedded HTTP management server. Use 0 to dynamic assign a 
free random port number.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"integer", "javaType": "int", "defaultValue": 8080, "secret": false },
     { "name": "camel.management.sendEnabled", "required": false, 
"description": "Whether to enable sending messages to Camel via HTTP. This 
makes it possible to use Camel to send messages to Camel endpoint URIs via 
HTTP.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false, 
"security": "insecure:dev" },
diff --git a/components/camel-platform-http-main/pom.xml 
b/components/camel-platform-http-main/pom.xml
index 9b4cd83e1dbe..80f9088f1288 100644
--- a/components/camel-platform-http-main/pom.xml
+++ b/components/camel-platform-http-main/pom.xml
@@ -68,6 +68,13 @@
             <version>${vertx-version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.webjars</groupId>
+            <artifactId>swagger-ui</artifactId>
+            <version>${swagger-ui-version}</version>
+            <optional>true</optional>
+        </dependency>
+
         <!-- test dependencies -->
         <dependency>
             <groupId>org.apache.camel</groupId>
@@ -84,6 +91,11 @@
             <artifactId>camel-console</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-openapi-java</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
index 40446c3c39e8..c5fb8e2f4835 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
@@ -105,6 +105,8 @@ public class DefaultMainHttpServerFactory implements 
CamelContextAware, MainHttp
         server.setUploadSourceDir(configuration.getUploadSourceDir());
         server.setDownloadEnabled(configuration.isDownloadEnabled());
         server.setSendEnabled(configuration.isSendEnabled());
+        server.setOpenapiUiEnabled(configuration.isOpenapiUiEnabled());
+        server.setOpenapiUiSpecPath(configuration.getOpenapiUiSpecPath());
 
         if (configuration.isAuthenticationEnabled()) {
             configureAuthentication(server, configuration);
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
index 6d9dfe93629c..b04e9b4fa80b 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
@@ -129,6 +129,8 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
     private String uploadSourceDir;
     private boolean downloadEnabled;
     private boolean sendEnabled;
+    private boolean openapiUiEnabled;
+    private String openapiUiSpecPath = OpenApiUiSupport.DEFAULT_SPEC_PATH;
 
     @Override
     public CamelContext getCamelContext() {
@@ -358,6 +360,30 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
         this.sendEnabled = sendEnabled;
     }
 
+    @ManagedAttribute(description = "Whether OpenAPI Swagger UI is enabled 
(q/openapi)")
+    public boolean isOpenapiUiEnabled() {
+        return openapiUiEnabled;
+    }
+
+    /**
+     * Whether Swagger UI is enabled at {@link 
OpenApiUiSupport#OPENAPI_UI_PATH}.
+     */
+    public void setOpenapiUiEnabled(boolean openapiUiEnabled) {
+        this.openapiUiEnabled = openapiUiEnabled;
+    }
+
+    @ManagedAttribute(description = "OpenAPI document URL used by Swagger UI")
+    public String getOpenapiUiSpecPath() {
+        return openapiUiSpecPath;
+    }
+
+    /**
+     * Path or URL of the OpenAPI document loaded by Swagger UI (default 
{@value OpenApiUiSupport#DEFAULT_SPEC_PATH}).
+     */
+    public void setOpenapiUiSpecPath(String openapiUiSpecPath) {
+        this.openapiUiSpecPath = openapiUiSpecPath;
+    }
+
     public VertxPlatformHttpServerConfiguration.Cors getCors() {
         return configuration.getCors();
     }
@@ -457,6 +483,9 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
         if (sendEnabled) {
             setupSendConsole();
         }
+        if (openapiUiEnabled) {
+            OpenApiUiSupport.setup(router, platformHttpComponent, 
openapiUiSpecPath);
+        }
         // metrics will be setup in camel-micrometer-prometheus
     }
 
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/OpenApiUiSupport.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/OpenApiUiSupport.java
new file mode 100644
index 000000000000..0a7c9d8a7d44
--- /dev/null
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/OpenApiUiSupport.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.platform.http.main;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import io.vertx.core.http.HttpMethod;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.handler.StaticHandler;
+import org.apache.camel.component.platform.http.PlatformHttpComponent;
+import org.apache.camel.component.platform.http.vertx.VertxPlatformHttpRouter;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * Serves Swagger UI at {@value #OPENAPI_UI_PATH} for exploring REST DSL 
OpenAPI documents.
+ */
+final class OpenApiUiSupport {
+
+    static final String OPENAPI_UI_PATH = "/q/openapi";
+    static final String DEFAULT_SPEC_PATH = "/q/openapi.json";
+    private static final String SWAGGER_UI_WEBJAR_VERSION = 
resolveSwaggerUiWebjarVersion();
+
+    private OpenApiUiSupport() {
+    }
+
+    static void setup(VertxPlatformHttpRouter router, PlatformHttpComponent 
platformHttpComponent, String specPath) {
+        ObjectHelper.notNull(router, "router");
+        ObjectHelper.notNull(platformHttpComponent, "platformHttpComponent");
+        String spec = normalizeSpecPath(specPath);
+
+        String webjarsRoot = "META-INF/resources/webjars/swagger-ui/" + 
SWAGGER_UI_WEBJAR_VERSION;
+        StaticHandler assets = 
StaticHandler.create(webjarsRoot).setCachingEnabled(true);
+
+        Route assetsRoute = router.route(OPENAPI_UI_PATH + "/webjars/*");
+        assetsRoute.method(HttpMethod.GET);
+        assetsRoute.handler(assets);
+
+        String html = buildIndexHtml(spec);
+
+        Route ui = router.route(OPENAPI_UI_PATH);
+        ui.method(HttpMethod.GET);
+        ui.handler(ctx -> {
+            ctx.response().putHeader("content-type", 
"text/html;charset=utf-8");
+            ctx.end(html);
+        });
+
+        Route uiSlash = router.route(OPENAPI_UI_PATH + "/");
+        uiSlash.method(HttpMethod.GET);
+        uiSlash.handler(ctx -> {
+            ctx.response().putHeader("content-type", 
"text/html;charset=utf-8");
+            ctx.end(html);
+        });
+
+        platformHttpComponent.addHttpManagementEndpoint(OPENAPI_UI_PATH, 
"GET", null, "text/html", null);
+    }
+
+    private static String buildIndexHtml(String specPath) {
+        String prefix = OPENAPI_UI_PATH + "/webjars";
+        String escapedSpecPath = escapeForJavaScriptString(specPath);
+        return """
+                <!DOCTYPE html>
+                <html lang="en">
+                <head>
+                  <meta charset="UTF-8"/>
+                  <title>Camel OpenAPI</title>
+                  <link rel="stylesheet" href="%s/swagger-ui.css"/>
+                </head>
+                <body>
+                <div id="swagger-ui"></div>
+                <script src="%s/swagger-ui-bundle.js"></script>
+                <script src="%s/swagger-ui-standalone-preset.js"></script>
+                <script>
+                window.onload = function () {
+                  window.ui = SwaggerUIBundle({
+                    url: "%s",
+                    dom_id: '#swagger-ui',
+                    deepLinking: true,
+                    presets: [SwaggerUIBundle.presets.apis, 
SwaggerUIStandalonePreset],
+                    layout: "StandaloneLayout"
+                  });
+                };
+                </script>
+                </body>
+                </html>
+                """.formatted(prefix, prefix, prefix, escapedSpecPath);
+    }
+
+    static String normalizeSpecPath(String specPath) {
+        String spec = ObjectHelper.isNotEmpty(specPath) ? specPath : 
DEFAULT_SPEC_PATH;
+        if (spec.startsWith("http://";) || spec.startsWith("https://";)) {
+            return spec;
+        }
+        if (!spec.startsWith("/")) {
+            spec = "/" + spec;
+        }
+        return spec;
+    }
+
+    static String escapeForJavaScriptString(String value) {
+        if (value == null) {
+            return "";
+        }
+        return value.replace("\\", "\\\\")
+                .replace("\"", "\\\"")
+                .replace("'", "\\'")
+                .replace("<", "\\u003c")
+                .replace(">", "\\u003e")
+                .replace("\n", "\\n")
+                .replace("\r", "\\r");
+    }
+
+    static String resolveSwaggerUiWebjarVersion() {
+        try (InputStream is = OpenApiUiSupport.class.getResourceAsStream(
+                "/META-INF/maven/org.webjars/swagger-ui/pom.properties")) {
+            if (is != null) {
+                Properties properties = new Properties();
+                properties.load(is);
+                String version = properties.getProperty("version");
+                if (version != null && !version.isBlank()) {
+                    return version;
+                }
+            }
+        } catch (IOException e) {
+            // fall through
+        }
+        throw new IllegalStateException("Unable to resolve swagger-ui webjar 
version from classpath");
+    }
+}
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiHttpServerTest.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiHttpServerTest.java
new file mode 100644
index 000000000000..8f177bd63a01
--- /dev/null
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiHttpServerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.platform.http.main;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class OpenApiUiHttpServerTest {
+
+    @RegisterExtension
+    AvailablePortFinder.Port port = AvailablePortFinder.find();
+
+    private CamelContext camelContext;
+    private ManagementHttpServer server;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        camelContext = new DefaultCamelContext();
+        camelContext.start();
+
+        server = new ManagementHttpServer();
+        server.setCamelContext(camelContext);
+        server.setHost("0.0.0.0");
+        server.setPort(port.getPort());
+        server.setPath("/");
+        server.setOpenapiUiEnabled(true);
+        server.start();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        if (server != null) {
+            server.stop();
+        }
+        if (camelContext != null) {
+            camelContext.stop();
+        }
+    }
+
+    @Test
+    void openApiUiPageContainsSwaggerBundle() throws IOException, 
InterruptedException {
+        HttpRequest request = HttpRequest.newBuilder()
+                .uri(URI.create("http://localhost:"; + port.getPort() + 
OpenApiUiSupport.OPENAPI_UI_PATH))
+                .GET()
+                .build();
+
+        HttpResponse<String> response = 
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
+
+        assertThat(response.statusCode()).isEqualTo(200);
+        
assertThat(response.headers().firstValue("content-type").orElse("")).contains("text/html");
+        assertThat(response.body()).contains("SwaggerUIBundle");
+        
assertThat(response.body()).contains(OpenApiUiSupport.DEFAULT_SPEC_PATH);
+    }
+
+    @Test
+    void openApiUiWebjarServesSwaggerCss() throws IOException, 
InterruptedException {
+        HttpRequest request = HttpRequest.newBuilder()
+                .uri(URI.create("http://localhost:"; + port.getPort() + 
OpenApiUiSupport.OPENAPI_UI_PATH
+                                + "/webjars/swagger-ui.css"))
+                .GET()
+                .build();
+
+        HttpResponse<String> response = 
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
+
+        assertThat(response.statusCode()).isEqualTo(200);
+        
assertThat(response.headers().firstValue("content-type").orElse("")).contains("text/css");
+    }
+}
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiRestMainTest.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiRestMainTest.java
new file mode 100644
index 000000000000..5265f9836de4
--- /dev/null
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiRestMainTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.platform.http.main;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.Properties;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.main.Main;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class OpenApiUiRestMainTest {
+
+    @RegisterExtension
+    AvailablePortFinder.Port port = AvailablePortFinder.find();
+
+    private Main main;
+
+    @BeforeEach
+    void setUp() {
+        Properties properties = new Properties();
+        properties.setProperty("camel.server.enabled", "true");
+        properties.setProperty("camel.server.port", 
Integer.toString(port.getPort()));
+        properties.setProperty("camel.management.enabled", "true");
+        properties.setProperty("camel.management.port", 
Integer.toString(port.getPort()));
+        properties.setProperty("camel.management.openapiUiEnabled", "true");
+        properties.setProperty("camel.rest.component", "platform-http");
+        properties.setProperty("camel.rest.apiContextPath", 
OpenApiUiSupport.DEFAULT_SPEC_PATH);
+
+        main = new Main();
+        main.setOverrideProperties(properties);
+        main.configure().addRoutesBuilder(new RouteBuilder() {
+            @Override
+            public void configure() {
+                restConfiguration().apiProperty("api.title", "Sample 
API").apiProperty("api.version", "1.0.0");
+                rest("/demo").get("/ping").to("direct:ping");
+                from("direct:ping").setBody(constant("pong"));
+            }
+        });
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        if (main != null) {
+            main.stop();
+        }
+    }
+
+    @Test
+    void restOpenApiDocumentAndUiAreAvailable() throws Exception {
+        main.start();
+
+        HttpClient client = HttpClient.newHttpClient();
+
+        HttpResponse<String> spec = client.send(HttpRequest.newBuilder()
+                .uri(URI.create("http://localhost:"; + port.getPort() + 
OpenApiUiSupport.DEFAULT_SPEC_PATH))
+                .header("Accept", "application/json")
+                .GET()
+                .build(), HttpResponse.BodyHandlers.ofString());
+
+        assertThat(spec.statusCode()).isEqualTo(200);
+        assertThat(spec.body()).contains("\"openapi\"");
+        assertThat(spec.body()).contains("/demo/ping");
+
+        HttpResponse<String> ui = client.send(HttpRequest.newBuilder()
+                .uri(URI.create("http://localhost:"; + port.getPort() + 
OpenApiUiSupport.OPENAPI_UI_PATH))
+                .GET()
+                .build(), HttpResponse.BodyHandlers.ofString());
+
+        assertThat(ui.statusCode()).isEqualTo(200);
+        assertThat(ui.body()).contains("SwaggerUIBundle");
+    }
+}
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiSupportTest.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiSupportTest.java
new file mode 100644
index 000000000000..8079b464fc97
--- /dev/null
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/OpenApiUiSupportTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.platform.http.main;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class OpenApiUiSupportTest {
+
+    @Test
+    void normalizeSpecPathDefaultsToOpenApiJson() {
+        
assertThat(OpenApiUiSupport.normalizeSpecPath(null)).isEqualTo(OpenApiUiSupport.DEFAULT_SPEC_PATH);
+        
assertThat(OpenApiUiSupport.normalizeSpecPath("")).isEqualTo(OpenApiUiSupport.DEFAULT_SPEC_PATH);
+    }
+
+    @Test
+    void normalizeSpecPathAddsLeadingSlashForRelativePaths() {
+        
assertThat(OpenApiUiSupport.normalizeSpecPath("api-docs.json")).isEqualTo("/api-docs.json");
+    }
+
+    @Test
+    void normalizeSpecPathPreservesAbsoluteHttpUrls() {
+        String url = "http://localhost:9090/q/openapi.json";;
+        assertThat(OpenApiUiSupport.normalizeSpecPath(url)).isEqualTo(url);
+    }
+
+    @Test
+    void escapeForJavaScriptStringEscapesQuotesAndScriptDelimiters() {
+        
assertThat(OpenApiUiSupport.escapeForJavaScriptString("/q/openapi.json")).isEqualTo("/q/openapi.json");
+        
assertThat(OpenApiUiSupport.escapeForJavaScriptString("http://host/path\";</script>"))
+                .isEqualTo("http://host/path\\\"\\u003c/script\\u003e";);
+    }
+
+    @Test
+    void resolveSwaggerUiWebjarVersionMatchesClasspathArtifact() {
+        
assertThat(OpenApiUiSupport.resolveSwaggerUiWebjarVersion()).matches("\\d+\\.\\d+\\.\\d+");
+    }
+}
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
index 701f3a5f97f3..22c4403b0c29 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
@@ -43,6 +43,8 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         map.put("JwtKeystorePath", java.lang.String.class);
         map.put("JwtKeystoreType", java.lang.String.class);
         map.put("MetricsEnabled", boolean.class);
+        map.put("OpenapiUiEnabled", boolean.class);
+        map.put("OpenapiUiSpecPath", java.lang.String.class);
         map.put("Path", java.lang.String.class);
         map.put("Port", int.class);
         map.put("SendEnabled", boolean.class);
@@ -96,6 +98,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "jwtKeystoreType": 
target.setJwtKeystoreType(property(camelContext, java.lang.String.class, 
value)); return true;
         case "metricsenabled":
         case "metricsEnabled": target.setMetricsEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "openapiuienabled":
+        case "openapiUiEnabled": 
target.setOpenapiUiEnabled(property(camelContext, boolean.class, value)); 
return true;
+        case "openapiuispecpath":
+        case "openapiUiSpecPath": 
target.setOpenapiUiSpecPath(property(camelContext, java.lang.String.class, 
value)); return true;
         case "path": target.setPath(property(camelContext, 
java.lang.String.class, value)); return true;
         case "port": target.setPort(property(camelContext, int.class, value)); 
return true;
         case "sendenabled":
@@ -158,6 +164,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "jwtKeystoreType": return java.lang.String.class;
         case "metricsenabled":
         case "metricsEnabled": return boolean.class;
+        case "openapiuienabled":
+        case "openapiUiEnabled": return boolean.class;
+        case "openapiuispecpath":
+        case "openapiUiSpecPath": return java.lang.String.class;
         case "path": return java.lang.String.class;
         case "port": return int.class;
         case "sendenabled":
@@ -216,6 +226,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "jwtKeystoreType": return target.getJwtKeystoreType();
         case "metricsenabled":
         case "metricsEnabled": return target.isMetricsEnabled();
+        case "openapiuienabled":
+        case "openapiUiEnabled": return target.isOpenapiUiEnabled();
+        case "openapiuispecpath":
+        case "openapiUiSpecPath": return target.getOpenapiUiSpecPath();
         case "path": return target.getPath();
         case "port": return target.getPort();
         case "sendenabled":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index feb0abb216fb..d16fb079e975 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -310,6 +310,8 @@
     { "name": "camel.management.jwtKeystorePath", "required": false, 
"description": "Path to the keystore file used for JWT tokens validation.", 
"sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.management.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.management.metricsEnabled", "required": false, 
"description": "Whether to enable metrics. If enabled then you can access 
metrics on context-path: \/observe\/metrics", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
+    { "name": "camel.management.openapiUiEnabled", "required": false, 
"description": "Whether to enable Swagger UI for REST DSL OpenAPI documents. If 
enabled then you can browse the API at context-path: \/q\/openapi. The OpenAPI 
document is expected at openapiUiSpecPath (by default \/q\/openapi.json from 
REST DSL apiContextPath ).", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": [...]
+    { "name": "camel.management.openapiUiSpecPath", "required": false, 
"description": "Path or URL of the OpenAPI document loaded by Swagger UI at 
\/q\/openapi.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/q\/openapi.json", 
"secret": false },
     { "name": "camel.management.path", "required": false, "description": 
"Context-path to use for embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/", "secret": false 
},
     { "name": "camel.management.port", "required": false, "description": "Port 
to use for binding embedded HTTP management server. Use 0 to dynamic assign a 
free random port number.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"integer", "javaType": "int", "defaultValue": 8080, "secret": false },
     { "name": "camel.management.sendEnabled", "required": false, 
"description": "Whether to enable sending messages to Camel via HTTP. This 
makes it possible to use Camel to send messages to Camel endpoint URIs via 
HTTP.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false, 
"security": "insecure:dev" },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 71ff06d3aee5..352d5a8e8fd5 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -225,7 +225,7 @@ The camel.server supports 21 options, which are listed 
below.
 
 
 === Camel Embedded HTTP management Server (only for standalone; not Spring 
Boot or Quarkus) configurations
-The camel.management supports 27 options, which are listed below.
+The camel.management supports 29 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -251,6 +251,8 @@ The camel.management supports 27 options, which are listed 
below.
 | *camel.management.jwtKeystorePath* | Path to the keystore file used for JWT 
tokens validation. |  | String
 | *camel.management.jwtKeystoreType* | Type of the keystore used for JWT 
tokens validation (jks, pkcs12, etc.). |  | String
 | *camel.management.metricsEnabled* | Whether to enable metrics. If enabled 
then you can access metrics on context-path: /observe/metrics | false | boolean
+| *camel.management.openapiUiEnabled* | Whether to enable Swagger UI for REST 
DSL OpenAPI documents. If enabled then you can browse the API at context-path: 
/q/openapi. The OpenAPI document is expected at openapiUiSpecPath (by default 
/q/openapi.json from REST DSL apiContextPath ). | false | boolean
+| *camel.management.openapiUiSpecPath* | Path or URL of the OpenAPI document 
loaded by Swagger UI at /q/openapi. | /q/openapi.json | String
 | *camel.management.path* | Context-path to use for embedded HTTP server | / | 
String
 | *camel.management.port* | Port to use for binding embedded HTTP management 
server. Use 0 to dynamic assign a free random port number. | 8080 | int
 | *camel.management.sendEnabled* | Whether to enable sending messages to Camel 
via HTTP. This makes it possible to use Camel to send messages to Camel 
endpoint URIs via HTTP. | false | boolean
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
index a705f287a334..405635887d8e 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
@@ -57,6 +57,11 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
     @Metadata(security = "insecure:dev")
     private boolean sendEnabled;
 
+    @Metadata(security = "insecure:dev")
+    private boolean openapiUiEnabled;
+    @Metadata(defaultValue = "/q/openapi.json")
+    private String openapiUiSpecPath = "/q/openapi.json";
+
     @Metadata(label = "security")
     private boolean useGlobalSslContextParameters;
     @Metadata(label = "security")
@@ -290,6 +295,30 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
         this.sendEnabled = sendEnabled;
     }
 
+    public boolean isOpenapiUiEnabled() {
+        return openapiUiEnabled;
+    }
+
+    /**
+     * Whether to enable Swagger UI for REST DSL OpenAPI documents. If enabled 
then you can browse the API at
+     * context-path: /q/openapi. The OpenAPI document is expected at {@link 
#openapiUiSpecPath} (by default
+     * /q/openapi.json from REST DSL {@code apiContextPath}).
+     */
+    public void setOpenapiUiEnabled(boolean openapiUiEnabled) {
+        this.openapiUiEnabled = openapiUiEnabled;
+    }
+
+    public String getOpenapiUiSpecPath() {
+        return openapiUiSpecPath;
+    }
+
+    /**
+     * Path or URL of the OpenAPI document loaded by Swagger UI at /q/openapi.
+     */
+    public void setOpenapiUiSpecPath(String openapiUiSpecPath) {
+        this.openapiUiSpecPath = openapiUiSpecPath;
+    }
+
     public boolean isAuthenticationEnabled() {
         return authenticationEnabled;
     }
@@ -528,6 +557,22 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
         return this;
     }
 
+    /**
+     * Whether to enable Swagger UI at /q/openapi (not intended for production 
use).
+     */
+    public HttpManagementServerConfigurationProperties 
withOpenapiUiEnabled(boolean openapiUiEnabled) {
+        this.openapiUiEnabled = openapiUiEnabled;
+        return this;
+    }
+
+    /**
+     * Path or URL of the OpenAPI document loaded by Swagger UI.
+     */
+    public HttpManagementServerConfigurationProperties 
withOpenapiUiSpecPath(String openapiUiSpecPath) {
+        this.openapiUiSpecPath = openapiUiSpecPath;
+        return this;
+    }
+
     /**
      * Whether to enable HTTP authentication for embedded server (for 
standalone applications; not Spring Boot or
      * Quarkus).
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index 79a5b665050d..0ab406ff49dd 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -62,6 +62,14 @@ The Camel CLI and TUI AI prompt now support native **Google 
Gemini** when `GEMIN
 the `generativelanguage.googleapis.com` API with function-calling support.
 See xref:camel-jbang-ai.adoc[Camel CLI - AI Tools] for the full detection 
order.
 
+`camel run`, `camel dev`, and `camel debug` accept `--openapi-ui` to expose 
Swagger UI for REST DSL OpenAPI
+at `/q/openapi` on the embedded HTTP server (OpenAPI JSON at `/q/openapi.json` 
by default). The feature is
+gated as developer-only (`insecure:dev`) via `camel.jbang.openapiUi` and 
`camel.management.openapiUiEnabled`.
+When `--port` is set without `--management-port`, the management server is 
co-bound to the same port so the UI
+and spec stay together. `--openapi-ui` also sets override properties for 
`camel.rest.component=platform-http`
+and `camel.rest.apiContextPath=/q/openapi.json`, which take precedence over 
values in `application.properties`
+or other property sources (same as other CLI `--` server flags that use 
override properties).
+
 The `camel cmd route-diagram` and `camel cmd route-topology` now accept one or 
more Camel route source files
 (instead of only the name/pid of a running integration), so diagrams and 
inter-route topology can be
 generated at design/source time without starting the application first, for 
example:
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
index 56301db3ccf3..16d59ff73148 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
@@ -4,7 +4,7 @@ This page covers configuring the Camel CLI — available options, 
configuration
 
 // jbang options: START
 == Camel CLI configurations
-The camel.jbang supports 50 options, which are listed below.
+The camel.jbang supports 51 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -42,6 +42,7 @@ The camel.jbang supports 50 options, which are listed below.
 | *camel.jbang.mavenWrapper* | Include Maven Wrapper files in the exported 
project | true | boolean
 | *camel.jbang.metrics* | Metrics (Micrometer and Prometheus) at 
/observe/metrics on local HTTP server (port 8080 by default) when running 
standalone Camel | false | boolean
 | *camel.jbang.openApi* | File name of open-api spec file (JSON or YAML) to 
generate routes from the swagger/openapi API spec file. |  | String
+| *camel.jbang.openapiUi* | Swagger UI for REST OpenAPI at /q/openapi on local 
HTTP server (port 8080 by default) | false | boolean
 | *camel.jbang.packageScanJars* | Whether to automatic package scan JARs for 
custom Spring or Quarkus beans making them available for Camel CLI | false | 
boolean
 | *camel.jbang.parentPom* | Parent POM coordinate (groupId:artifactId:version) 
to use in the exported project |  | String
 | *camel.jbang.prompt* | Allow user to type in required parameters in prompt 
if not present in application | false | boolean
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
index 9bb2551d7c22..107421fb034d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
@@ -303,6 +303,23 @@ curl -s -X POST -H "Accept: application/json" -H 
"Content-Type: application/json
   http://0.0.0.0:8080/q/dev/eval-language | jq
 ----
 
+== OpenAPI Swagger UI
+
+For integrations using the xref:manual::rest-dsl.adoc[REST DSL], you can 
browse the generated OpenAPI
+document in Swagger UI (similar to Hawtio for JMX):
+
+[source,bash]
+----
+camel run hello.java --openapi-ui
+----
+
+Swagger UI is served at http://localhost:8080/q/openapi. The OpenAPI JSON 
document is at
+http://localhost:8080/q/openapi.json (configured automatically via 
`camel.rest.apiContextPath`).
+
+You can combine this with REST routes defined in Java, YAML, or XML DSL. The 
flag also works on
+`camel run --dev` and adds `camel-openapi-java` and `camel-platform-http-main` 
to the runtime
+classpath when needed.
+
 == Message history
 
 *Available since Camel 4.17*
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
index 402bfb81a441..de73fa1b3b02 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
@@ -68,6 +68,7 @@ camel debug [options]
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
 | `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries (HTTP clients, JDBC, Kafka 
clients, gRPC, etc.). Traces are shown in the TUI Spans tab with Camel spans in 
cyan and 3rd-party agent spans in magenta. | false | boolean
 | `--open-telemetry-agent-export` | Where to export OpenTelemetry Agent 
telemetry: tui (embedded receiver in TUI), otlp (external OTLP collector for 
traces), or observability (full stack with traces and logs). With otlp, start a 
trace backend first (e.g. 'camel infra run jaeger'). With observability, start 
the stack via 'camel infra run observability'. The value 'jaeger' is deprecated 
and works as an alias for 'otlp'. | tui | String
+| `--openapi-ui` | Swagger UI for REST OpenAPI at /q/openapi (OpenAPI document 
at /q/openapi.json; port 8080 by default) | false | boolean
 | `--output` | File to store the current message body (will override). This 
allows for manual inspecting the message later. |  | String
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel CLI | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
index 3511b72ca9de..fbe37951b652 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
@@ -64,6 +64,7 @@ camel dev [options]
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
 | `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries (HTTP clients, JDBC, Kafka 
clients, gRPC, etc.). Traces are shown in the TUI Spans tab with Camel spans in 
cyan and 3rd-party agent spans in magenta. | false | boolean
 | `--open-telemetry-agent-export` | Where to export OpenTelemetry Agent 
telemetry: tui (embedded receiver in TUI), otlp (external OTLP collector for 
traces), or observability (full stack with traces and logs). With otlp, start a 
trace backend first (e.g. 'camel infra run jaeger'). With observability, start 
the stack via 'camel infra run observability'. The value 'jaeger' is deprecated 
and works as an alias for 'otlp'. | tui | String
+| `--openapi-ui` | Swagger UI for REST OpenAPI at /q/openapi (OpenAPI document 
at /q/openapi.json; port 8080 by default) | false | boolean
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel CLI | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
 | `--profile` | Profile to run (dev, test, prod). | dev | String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
index 25bc7a10095e..205ec1b76c99 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
@@ -64,6 +64,7 @@ camel run [options]
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
 | `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries (HTTP clients, JDBC, Kafka 
clients, gRPC, etc.). Traces are shown in the TUI Spans tab with Camel spans in 
cyan and 3rd-party agent spans in magenta. | false | boolean
 | `--open-telemetry-agent-export` | Where to export OpenTelemetry Agent 
telemetry: tui (embedded receiver in TUI), otlp (external OTLP collector for 
traces), or observability (full stack with traces and logs). With otlp, start a 
trace backend first (e.g. 'camel infra run jaeger'). With observability, start 
the stack via 'camel infra run observability'. The value 'jaeger' is deprecated 
and works as an alias for 'otlp'. | tui | String
+| `--openapi-ui` | Swagger UI for REST OpenAPI at /q/openapi (OpenAPI document 
at /q/openapi.json; port 8080 by default) | false | boolean
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel CLI | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
 | `--profile` | Profile to run (dev, test, prod). | dev | String
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 0aa243db48fb..cda747041dbc 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -6,9 +6,9 @@
     { "name": "cmd", "fullName": "cmd", "description": "Performs commands in 
the running Camel integrations, such as start\/stop route, or change logging 
levels.", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"browse", "fullName": "cmd browse", "description": "Browse pending messages on 
endpoints [...]
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
-    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
+    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
     { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
-    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
+    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
     { "name": "dirty", "fullName": "dirty", "description": "Check if there are 
dirty files from previous Camel runs that did not terminate gracefully", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Dirty", 
"options": [ { "names": "--clean", "description": "Clean dirty files which are 
no longer in use", "defaultValue": "false", "javaType": "boolean", "type": 
"boolean" }, { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", " [...]
     { "name": "doc", "fullName": "doc", "description": "Shows documentation 
for kamelet, component, and other Camel resources", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogDoc", "options": [ { 
"names": "--camel-version", "description": "To use a different Camel version 
than the default version", "javaType": "java.lang.String", "type": "string" }, 
{ "names": "--download", "description": "Whether to allow automatic downloading 
JAR dependencies (over the internet [...]
     { "name": "doctor", "fullName": "doctor", "description": "Checks the 
environment and reports potential issues", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Doctor", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
@@ -26,7 +26,7 @@
     { "name": "plugin", "fullName": "plugin", "description": "Manage plugins 
that add sub-commands to this CLI", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "add", 
"fullName": "plugin add", "description": "Add new plugin", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginA [...]
     { "name": "ps", "fullName": "ps", "description": "List running Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "--pid", "description": "List only 
pid in the output", "javaType": "boolean", "type": "boolean" }, { "names": 
"--remote", "description": "Break down counters into remote\/total pairs", 
"javaType": [...]
     { "name": "restart", "fullName": "restart", "description": "Restarts 
running Camel integrations (stop + re-launch)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.RestartProcess", "options": [ 
{ "names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ] },
-    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
+    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
     { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
     { "name": "script", "fullName": "script", "description": "Run Camel 
integration as shell script for terminal scripting", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Script", "options": [ { "names": 
"--logging", "description": "Can be used to turn on logging (logs to file in 
<user home>\/.camel directory)", "defaultValue": "false", "javaType": 
"boolean", "type": "boolean" }, { "names": "--logging-level", "description": 
"Logging level (ERROR, WARN, INFO, DEBUG, TRACE)", "d [...]
     { "name": "shell", "fullName": "shell", "description": "Interactive Camel 
CLI shell.", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Shell", 
"options": [ { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", "type": "boolean" } ] },
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
index 4f02be84a402..2009c64f7a0c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
@@ -36,6 +36,7 @@
     { "name": "camel.jbang.mavenWrapper", "required": false, "description": 
"Include Maven Wrapper files in the exported project", "type": "boolean", 
"javaType": "boolean", "defaultValue": true, "secret": false },
     { "name": "camel.jbang.metrics", "required": false, "description": 
"Metrics (Micrometer and Prometheus) at \/observe\/metrics on local HTTP server 
(port 8080 by default) when running standalone Camel", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false, "deprecated": 
true },
     { "name": "camel.jbang.openApi", "required": false, "description": "File 
name of open-api spec file (JSON or YAML) to generate routes from the 
swagger\/openapi API spec file.", "type": "string", "javaType": "String", 
"secret": false },
+    { "name": "camel.jbang.openapiUi", "required": false, "description": 
"Swagger UI for REST OpenAPI at \/q\/openapi on local HTTP server (port 8080 by 
default)", "type": "boolean", "javaType": "boolean", "defaultValue": false, 
"secret": false, "security": "insecure:dev" },
     { "name": "camel.jbang.packageScanJars", "required": false, "description": 
"Whether to automatic package scan JARs for custom Spring or Quarkus beans 
making them available for Camel CLI", "label": "advanced", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false },
     { "name": "camel.jbang.parentPom", "required": false, "description": 
"Parent POM coordinate (groupId:artifactId:version) to use in the exported 
project", "type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.prompt", "required": false, "description": "Allow 
user to type in required parameters in prompt if not present in application", 
"label": "advanced", "type": "boolean", "javaType": "boolean", "defaultValue": 
false, "secret": false },
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index c6b1b7a7449f..29bf3e3d3b04 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -69,6 +69,7 @@ import org.apache.camel.dsl.jbang.core.common.SourceHelper;
 import org.apache.camel.dsl.jbang.core.common.SourceScheme;
 import org.apache.camel.dsl.jbang.core.common.TemplateHelper;
 import org.apache.camel.dsl.jbang.core.common.VersionHelper;
+import org.apache.camel.main.BaseMainSupport;
 import org.apache.camel.main.KameletMain;
 import org.apache.camel.main.download.DownloadListener;
 import org.apache.camel.main.util.SuggestSimilarHelper;
@@ -845,6 +846,7 @@ public class Run extends CamelCommand {
         writeSetting(main, profileProperties, HEALTH, serverOptions.health ? 
"true" : "false");
         writeSetting(main, profileProperties, METRICS, serverOptions.metrics ? 
"true" : "false");
         writeSetting(main, profileProperties, CONSOLE, serverOptions.console ? 
"true" : "false");
+        writeSetting(main, profileProperties, OPENAPI_UI, 
serverOptions.openapiUi ? "true" : "false");
         writeSetting(main, profileProperties, VERBOSE, verbose ? "true" : 
"false");
         // the runtime version of Camel is what is loaded via the catalog
         writeSetting(main, profileProperties, CAMEL_VERSION, new 
DefaultCamelCatalog().getCatalogVersion());
@@ -914,6 +916,7 @@ public class Run extends CamelCommand {
         writeSetting(main, profileProperties, 
"camel.main.durationMaxIdleSeconds",
                 () -> executionLimitOptions.maxIdleSeconds > 0
                         ? String.valueOf(executionLimitOptions.maxIdleSeconds) 
: null);
+        prepareOpenApiUiServerOptions();
         if (serverOptions.port != -1) {
             // enable the main HTTP server when --port is explicitly specified
             writeSetting(main, profileProperties, "camel.server.enabled", 
"true");
@@ -1250,6 +1253,11 @@ public class Run extends CamelCommand {
             dependencies.add("camel:observability-services");
             main.addOverrideProperty("camel.metrics.logMetricsOnShutdown", 
"false");
         }
+        if (serverOptions.openapiUi) {
+            dependencies.add("camel:platform-http-main");
+            dependencies.add("camel:openapi-java");
+            applyOpenApiUiRuntimeOptions(main);
+        }
         if (debugOptions.openTelemetryAgent) {
             dependencies.add("camel:opentelemetry2");
             boolean externalExport = 
"otlp".equals(debugOptions.openTelemetryAgentExport)
@@ -3081,6 +3089,10 @@ public class Run extends CamelCommand {
                 description = "Developer console at /q/dev on local HTTP 
server (port 8080 by default)")
         boolean console;
 
+        @Option(names = { "--openapi-ui" }, defaultValue = "false",
+                description = "Swagger UI for REST OpenAPI at /q/openapi 
(OpenAPI document at /q/openapi.json; port 8080 by default)")
+        boolean openapiUi;
+
         @Deprecated
         @Option(names = { "--health" }, defaultValue = "false",
                 description = "Deprecated: use --observe instead. Health check 
at /q/health on local HTTP server (port 8080 by default)")
@@ -3096,6 +3108,33 @@ public class Run extends CamelCommand {
         boolean observe;
     }
 
+    /**
+     * Align HTTP and management ports when OpenAPI UI is enabled so Swagger 
UI and the REST OpenAPI document are
+     * co-hosted (same Vert.x server when ports match).
+     */
+    void prepareOpenApiUiServerOptions() {
+        if (!serverOptions.openapiUi) {
+            return;
+        }
+        if (serverOptions.port == -1) {
+            serverOptions.port = 8080;
+        }
+        if (serverOptions.managementPort == -1) {
+            serverOptions.managementPort = serverOptions.port;
+        }
+    }
+
+    void applyOpenApiUiRuntimeOptions(BaseMainSupport main) {
+        if (!serverOptions.openapiUi) {
+            return;
+        }
+        main.addOverrideProperty("camel.rest.apiContextPath", 
"/q/openapi.json");
+        main.addOverrideProperty("camel.rest.component", "platform-http");
+        main.addOverrideProperty("camel.management.openapiUiEnabled", "true");
+        main.addOverrideProperty("camel.server.enabled", "true");
+        main.addOverrideProperty("camel.management.enabled", "true");
+    }
+
     static class FilesConsumer extends ParameterConsumer<Run> {
         @Override
         protected void doConsumeParameters(Stack<String> args, Run cmd) {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
index e97203d1d431..334cd054afb5 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
@@ -201,6 +201,10 @@ public final class CamelJBangConstants {
               javaType = "boolean")
     public static final String CONSOLE = "camel.jbang.console";
 
+    @Metadata(description = "Swagger UI for REST OpenAPI at /q/openapi on 
local HTTP server (port 8080 by default)",
+              javaType = "boolean", security = "insecure:dev")
+    public static final String OPENAPI_UI = "camel.jbang.openapiUi";
+
     @Metadata(description = "Verbose output of startup activity (dependency 
resolution and downloading",
               javaType = "boolean")
     public static final String VERBOSE = "camel.jbang.verbose";
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunOpenApiUiOptionsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunOpenApiUiOptionsTest.java
new file mode 100644
index 000000000000..d7cb8965533a
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunOpenApiUiOptionsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.dsl.jbang.core.commands;
+
+import org.apache.camel.main.Main;
+import org.junit.jupiter.api.Test;
+import picocli.CommandLine;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RunOpenApiUiOptionsTest {
+
+    @Test
+    void shouldParseOpenApiUiFlag() {
+        Run run = new Run(new CamelJBangMain());
+        CommandLine cmd = new CommandLine(run);
+
+        cmd.parseArgs("--openapi-ui", "hello.java");
+
+        assertThat(run.serverOptions.openapiUi).isTrue();
+        assertThat(run.files).containsExactly("hello.java");
+    }
+
+    @Test
+    void shouldAlignManagementPortWithAppPortForOpenApiUi() {
+        Run run = new Run(new CamelJBangMain());
+        new CommandLine(run).parseArgs("--openapi-ui", "--port=9090", 
"hello.java");
+
+        run.prepareOpenApiUiServerOptions();
+
+        assertThat(run.serverOptions.port).isEqualTo(9090);
+        assertThat(run.serverOptions.managementPort).isEqualTo(9090);
+    }
+
+    @Test
+    void shouldPreserveExplicitManagementPortForOpenApiUi() {
+        Run run = new Run(new CamelJBangMain());
+        new CommandLine(run).parseArgs("--openapi-ui", "--port=9090", 
"--management-port=9999", "hello.java");
+
+        run.prepareOpenApiUiServerOptions();
+
+        assertThat(run.serverOptions.port).isEqualTo(9090);
+        assertThat(run.serverOptions.managementPort).isEqualTo(9999);
+    }
+
+    @Test
+    void shouldApplyOpenApiUiOverrideProperties() {
+        Run run = new Run(new CamelJBangMain());
+        new CommandLine(run).parseArgs("--openapi-ui", "hello.java");
+        Main main = new Main();
+
+        run.applyOpenApiUiRuntimeOptions(main);
+
+        
assertThat(main.getOverrideProperties().getProperty("camel.rest.component")).isEqualTo("platform-http");
+        
assertThat(main.getOverrideProperties().getProperty("camel.rest.apiContextPath")).isEqualTo("/q/openapi.json");
+        
assertThat(main.getOverrideProperties().getProperty("camel.management.openapiUiEnabled")).isEqualTo("true");
+        
assertThat(main.getOverrideProperties().getProperty("camel.server.enabled")).isEqualTo("true");
+        
assertThat(main.getOverrideProperties().getProperty("camel.management.enabled")).isEqualTo("true");
+    }
+}
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index 4c666e8756b1..7d7cade212fe 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -573,6 +573,18 @@ public class KameletMain extends MainCommandLineSupport {
             configure().httpManagementServer().withInfoEnabled(true);
             configure().httpManagementServer().withJolokiaEnabled(true);
         }
+        boolean openapiUi = 
"true".equals(getInitialProperties().get(getInstanceType() + ".openapiUi"));
+        if (openapiUi) {
+            configure().httpManagementServer().withEnabled(true);
+            configure().httpManagementServer().withOpenapiUiEnabled(true);
+            configure().httpServer().withEnabled(true);
+            if (!isConfigured("camel.rest.component")) {
+                configure().rest().withComponent("platform-http");
+            }
+            if (!isConfigured("camel.rest.apiContextPath")) {
+                configure().rest().withApiContextPath("/q/openapi.json");
+            }
+        }
         boolean tracing = 
"true".equals(getInitialProperties().get(getInstanceType() + 
".backlogTracing"));
         if (tracing) {
             configure().tracerConfig().withEnabled(true);
@@ -987,6 +999,22 @@ public class KameletMain extends MainCommandLineSupport {
         blueprintXmlBeansHandler.createAndRegisterBeans(camelContext);
     }
 
+    private boolean isConfigured(String key) {
+        if (getOverrideProperties() != null) {
+            String value = getOverrideProperties().getProperty(key);
+            if (value != null && !value.isBlank()) {
+                return true;
+            }
+        }
+        if (getInitialProperties() != null) {
+            String value = getInitialProperties().getProperty(key);
+            if (value != null && !value.isBlank()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static String getPid() {
         return String.valueOf(ProcessHandle.current().pid());
     }
diff --git a/parent/pom.xml b/parent/pom.xml
index fb09ab8b89ad..5958e4dcf9e6 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -504,6 +504,7 @@
         <swagger-java-parser-version>1.0.65</swagger-java-parser-version>
         
<swagger-openapi3-java-parser-version>2.1.45</swagger-openapi3-java-parser-version>
         
<swagger-request-validator-version>2.46.1</swagger-request-validator-version>
+        <swagger-ui-version>5.21.0</swagger-ui-version>
         <stringtemplate-version>4.3.4</stringtemplate-version>
         <tahu-version>1.0.21</tahu-version>
         <tamboui-version>0.4.0</tamboui-version>
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangMojo.java
index 491acba04431..9dc44ce47db4 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangMojo.java
@@ -83,6 +83,10 @@ public class PrepareCamelJBangMojo extends 
AbstractGeneratorMojo {
                 String desc = as.getStringValue("description");
                 String label = as.getStringValue("label");
                 boolean secret = "true".equals(as.getStringValue("secret"));
+                String security = as.getStringValue("security");
+                if ("secret".equals(security) && !secret) {
+                    secret = true;
+                }
                 boolean required = 
"true".equals(as.getStringValue("required"));
                 boolean deprecated = clazz.getAnnotation(Deprecated.class) != 
null || f.getAnnotation(Deprecated.class) != null;
                 JBangModel.JBangOptionModel model = new 
JBangModel.JBangOptionModel();
@@ -93,6 +97,7 @@ public class PrepareCamelJBangMojo extends 
AbstractGeneratorMojo {
                 model.setSourceType(null);
                 model.setDeprecated(deprecated);
                 model.setSecret(secret);
+                model.setSecurity(security);
                 model.setRequired(required);
                 List<String> enums = null;
                 String text = as.getStringValue("enums");

Reply via email to