You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/28 14:40:42 UTC

(camel) 28/38: CAMEL-20557: Rest DSL to use openapi spec directly

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

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

commit 8353ab70809e6d7380e51e9f86a8017ba0c6dfd3
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Mar 27 09:14:06 2024 +0100

    CAMEL-20557: Rest DSL to use openapi spec directly
---
 .../org/apache/camel/catalog/models.properties     |   1 +
 .../org/apache/camel/catalog/models/openApi.json   |  20 ++
 .../org/apache/camel/catalog/models/rest.json      |   5 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  28 ++
 ...PlatformHttpRestOpenApiConsumerRestDslTest.java | 281 +++++++++++++++++++++
 .../org/apache/camel/model/rest/openApi.json       |  20 ++
 .../META-INF/org/apache/camel/model/rest/rest.json |   5 +-
 .../services/org/apache/camel/model.properties     |   1 +
 .../org/apache/camel/model/rest/jaxb.index         |   1 +
 .../apache/camel/model/rest/OpenApiDefinition.java |  83 ++++++
 .../apache/camel/model/rest/RestDefinition.java    | 125 ++++++++-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  11 +
 .../java/org/apache/camel/xml/out/ModelWriter.java |  15 ++
 .../org/apache/camel/yaml/out/ModelWriter.java     |  15 ++
 .../dsl/yaml/deserializers/ModelDeserializers.java |  67 +++++
 .../deserializers/ModelDeserializersResolver.java  |   3 +
 .../generated/resources/schema/camelYamlDsl.json   |  33 +++
 17 files changed, 709 insertions(+), 5 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
index 6d987b78e44..5fcbcefbaea 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
@@ -100,6 +100,7 @@ ognl
 onCompletion
 onException
 onFallback
+openApi
 openIdConnect
 optimisticLockRetryPolicy
 otherwise
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/openApi.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/openApi.json
new file mode 100644
index 00000000000..2fec558b620
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/openApi.json
@@ -0,0 +1,20 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "openApi",
+    "title": "Open Api",
+    "description": "To use OpenApi as contract-first with Camel Rest DSL.",
+    "deprecated": false,
+    "label": "rest",
+    "javaType": "org.apache.camel.model.rest.OpenApiDefinition",
+    "abstract": false,
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime." },
+    "specification": { "index": 3, "kind": "attribute", "displayName": "Specification", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false }
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/rest.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/rest.json
index 81e71f12400..f11e6751b04 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/rest.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/rest.json
@@ -25,7 +25,8 @@
     "enableNoContentResponse": { "index": 10, "kind": "attribute", "displayName": "Enable No Content Response", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to return HTTP 204 with an empty body when a response contains an empty JSON object or XML root object. The default value is false." },
     "apiDocs": { "index": 11, "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. This option will override what may be configured on a parent level. The default value is true." },
     "tag": { "index": 12, "kind": "attribute", "displayName": "Tag", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To configure a special tag for the operations within this rest definition." },
-    "securityDefinitions": { "index": 13, "kind": "element", "displayName": "Security Definitions", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestSecuritiesDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security definitions such as Basic, OAuth2 etc." },
-    "securityRequirements": { "index": 14, "kind": "element", "displayName": "Security Requirements", "label": "security", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.SecurityDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security requirement(s) for all endpoints." }
+    "openApi": { "index": 13, "kind": "element", "displayName": "Open Api", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.OpenApiDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "To use an existing OpenAPI specification as contract-first for Camel Rest DSL." },
+    "securityDefinitions": { "index": 14, "kind": "element", "displayName": "Security Definitions", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestSecuritiesDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security definitions such as Basic, OAuth2 etc." },
+    "securityRequirements": { "index": 15, "kind": "element", "displayName": "Security Requirements", "label": "security", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.SecurityDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security requirement(s) for all endpoints." }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index de2db82edea..53195be2296 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -986,6 +986,15 @@ Route to be executed when an exception is thrown
       <xs:documentation xml:lang="en">
 <![CDATA[
 Route to be executed when Circuit Breaker EIP executes fallback
+]]>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:element>
+  <xs:element name="openApi" type="tns:openApiDefinition">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+<![CDATA[
+To use OpenApi as contract-first with Camel Rest DSL.
 ]]>
       </xs:documentation>
     </xs:annotation>
@@ -16368,6 +16377,24 @@ The URL to be used for obtaining refresh tokens. This MUST be in the form of a U
             <xs:documentation xml:lang="en">
 <![CDATA[
 The flow used by the OAuth2 security scheme. Valid values are implicit, password, application or accessCode.
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="openApiDefinition">
+    <xs:complexContent>
+      <xs:extension base="tns:optionalIdentifiedDefinition">
+        <xs:sequence/>
+        <xs:attribute name="specification" type="xs:string" use="required"/>
+        <xs:attribute name="disabled" type="xs:string">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST
+service has been disabled then it cannot be enabled later at runtime. Default value: false
 ]]>
             </xs:documentation>
           </xs:annotation>
@@ -16819,6 +16846,7 @@ custom name of the data format, not to refer to an existing data format instance
     <xs:complexContent>
       <xs:extension base="tns:optionalIdentifiedDefinition">
         <xs:sequence>
+          <xs:element minOccurs="0" ref="tns:openApi"/>
           <xs:element minOccurs="0" ref="tns:securityDefinitions"/>
           <xs:element maxOccurs="unbounded" minOccurs="0" name="securityRequirements" type="tns:securityDefinition">
             <xs:annotation>
diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java
new file mode 100644
index 00000000000..f91954d1ceb
--- /dev/null
+++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java
@@ -0,0 +1,281 @@
+/*
+ * 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.vertx;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.openapi.RestOpenApiComponent;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.equalToCompressingWhiteSpace;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class PlatformHttpRestOpenApiConsumerRestDslTest {
+
+    @Test
+    public void testRestOpenApi() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("ignore");
+
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .get("/api/v3/pet/123")
+                    .then()
+                    .statusCode(200)
+                    .body(equalTo("{\"pet\": \"tony the tiger\"}"));
+
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiDevMode() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+        // run in developer mode
+        context.getCamelContextExtension().setProfile("dev");
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .get("/api/v3/pet/123")
+                    .then()
+                    .statusCode(200)
+                    .body(equalTo("{\"pet\": \"tony the tiger\"}"));
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiMock() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("mock");
+
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .get("/api/v3/pet/123")
+                    .then()
+                    .statusCode(200)
+                    .body(equalTo("{\"pet\": \"tony the tiger\"}"));
+
+            // mocked gives empty response
+            given()
+                    .when()
+                    .get("/api/v3/pet/findByTags")
+                    .then()
+                    .statusCode(204)
+                    .body(equalTo(""));
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiMissingOperation() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+            fail();
+        } catch (IllegalArgumentException e) {
+            Assertions.assertTrue(
+                    e.getMessage().startsWith("OpenAPI specification has 18 unmapped operations to corresponding routes"));
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiNotFound() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("ignore");
+
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .get("/api/v3/pet/123/unknown")
+                    .then()
+                    .statusCode(404);
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiNotAllowed() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("ignore");
+
+                    rest().openApi("openapi-v3.json");
+
+                    from("direct:getPetById")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .put("/api/v3/pet/123")
+                    .then()
+                    .statusCode(405);
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiValidate() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("ignore");
+
+                    rest().clientRequestValidation(true).openApi("openapi-v3.json");
+
+                    from("direct:updatePet")
+                            .setBody().constant("{\"pet\": \"tony the tiger\"}");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .put("/api/v3/pet")
+                    .then()
+                    .statusCode(405); // no request body
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testRestOpenApiMockData() throws Exception {
+        final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    RestOpenApiComponent c = context.getComponent("rest-openapi", RestOpenApiComponent.class);
+                    c.setMissingOperation("mock");
+
+                    rest().openApi("openapi-v3.json");
+                }
+            });
+
+            context.start();
+
+            given()
+                    .when()
+                    .contentType("application/json")
+                    .get("/api/v3/pet/444")
+                    .then()
+                    .statusCode(200)
+                    .body(equalToCompressingWhiteSpace(
+                            """
+                                    {
+                                      "pet": "donald the dock"
+                                    }"""));
+        } finally {
+            context.stop();
+        }
+    }
+
+}
diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/openApi.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/openApi.json
new file mode 100644
index 00000000000..2fec558b620
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/openApi.json
@@ -0,0 +1,20 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "openApi",
+    "title": "Open Api",
+    "description": "To use OpenApi as contract-first with Camel Rest DSL.",
+    "deprecated": false,
+    "label": "rest",
+    "javaType": "org.apache.camel.model.rest.OpenApiDefinition",
+    "abstract": false,
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime." },
+    "specification": { "index": 3, "kind": "attribute", "displayName": "Specification", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false }
+  }
+}
diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/rest.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/rest.json
index 81e71f12400..f11e6751b04 100644
--- a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/rest.json
+++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/rest/rest.json
@@ -25,7 +25,8 @@
     "enableNoContentResponse": { "index": 10, "kind": "attribute", "displayName": "Enable No Content Response", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to return HTTP 204 with an empty body when a response contains an empty JSON object or XML root object. The default value is false." },
     "apiDocs": { "index": 11, "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. This option will override what may be configured on a parent level. The default value is true." },
     "tag": { "index": 12, "kind": "attribute", "displayName": "Tag", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To configure a special tag for the operations within this rest definition." },
-    "securityDefinitions": { "index": 13, "kind": "element", "displayName": "Security Definitions", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestSecuritiesDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security definitions such as Basic, OAuth2 etc." },
-    "securityRequirements": { "index": 14, "kind": "element", "displayName": "Security Requirements", "label": "security", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.SecurityDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security requirement(s) for all endpoints." }
+    "openApi": { "index": 13, "kind": "element", "displayName": "Open Api", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.OpenApiDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "To use an existing OpenAPI specification as contract-first for Camel Rest DSL." },
+    "securityDefinitions": { "index": 14, "kind": "element", "displayName": "Security Definitions", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestSecuritiesDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security definitions such as Basic, OAuth2 etc." },
+    "securityRequirements": { "index": 15, "kind": "element", "displayName": "Security Requirements", "label": "security", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.SecurityDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the security requirement(s) for all endpoints." }
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
index 4d33e1f087c..c6b3ace6879 100644
--- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
+++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
@@ -101,6 +101,7 @@ ognl
 onCompletion
 onException
 onFallback
+openApi
 openIdConnect
 optimisticLockRetryPolicy
 otherwise
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/jaxb.index
index d5151db1b43..dc35df6c3c5 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/jaxb.index
@@ -8,6 +8,7 @@ GetDefinition
 HeadDefinition
 MutualTLSDefinition
 OAuth2Definition
+OpenApiDefinition
 OpenIdConnectDefinition
 ParamDefinition
 PatchDefinition
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/OpenApiDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/OpenApiDefinition.java
new file mode 100644
index 00000000000..f2d34c56d81
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/OpenApiDefinition.java
@@ -0,0 +1,83 @@
+/*
+ * 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.model.rest;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.model.OptionalIdentifiedDefinition;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * To use OpenApi as contract-first with Camel Rest DSL.
+ */
+@Metadata(label = "rest")
+@XmlRootElement(name = "openApi")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OpenApiDefinition extends OptionalIdentifiedDefinition<OpenApiDefinition> {
+
+    @XmlTransient
+    private RestDefinition rest;
+
+    @XmlAttribute(required = true)
+    private String specification;
+    @XmlAttribute
+    @Metadata(label = "advanced", javaType = "java.lang.Boolean")
+    private String disabled;
+
+    @Override
+    public String getShortName() {
+        return "openApi";
+    }
+
+    @Override
+    public String getLabel() {
+        return "openApi";
+    }
+
+    public String getSpecification() {
+        return specification;
+    }
+
+    public void setSpecification(String specification) {
+        this.specification = specification;
+    }
+
+    public String getDisabled() {
+        return disabled;
+    }
+
+    /**
+     * Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST
+     * service has been disabled then it cannot be enabled later at runtime.
+     */
+    public void setDisabled(String disabled) {
+        this.disabled = disabled;
+    }
+
+    // Fluent API
+    // -------------------------------------------------------------------------
+
+    public RestDefinition specification(String specification) {
+        this.specification = specification;
+        return rest;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
index cb17ab754f9..379d5f46cde 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java
@@ -37,6 +37,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.model.OptionalIdentifiedDefinition;
 import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.StopDefinition;
 import org.apache.camel.model.ToDefinition;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.NodeIdFactory;
@@ -49,6 +50,7 @@ import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.URISupport;
 
+import static org.apache.camel.support.CamelContextHelper.parseBoolean;
 import static org.apache.camel.support.CamelContextHelper.parseText;
 
 /**
@@ -90,6 +92,8 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
     @XmlAttribute
     @Metadata(label = "advanced")
     private String tag;
+    @XmlElement
+    private OpenApiDefinition openApi;
     @XmlElement(name = "securityDefinitions") // use the name Swagger/OpenAPI uses
     @Metadata(label = "security")
     private RestSecuritiesDefinition securityDefinitions;
@@ -285,6 +289,17 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
         this.apiDocs = apiDocs;
     }
 
+    public OpenApiDefinition getOpenApi() {
+        return openApi;
+    }
+
+    /**
+     * To use an existing OpenAPI specification as contract-first for Camel Rest DSL.
+     */
+    public void setOpenApi(OpenApiDefinition openApi) {
+        this.openApi = openApi;
+    }
+
     public Resource getResource() {
         return resource;
     }
@@ -296,6 +311,14 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
     // Fluent API
     // -------------------------------------------------------------------------
 
+    /**
+     * To use an existing OpenAPI specification as contract-first for Camel Rest DSL.
+     */
+    public RestDefinition openApi(String specification) {
+        openApi = new OpenApiDefinition();
+        return openApi.specification(specification);
+    }
+
     /**
      * To set the base path of this REST service
      */
@@ -750,6 +773,13 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
         return "rest:" + verb.asVerb() + ":" + buildUri(camelContext, verb);
     }
 
+    /**
+     * Build the from endpoint uri for the open-api
+     */
+    public String buildFromUri(CamelContext camelContext, OpenApiDefinition openApi) {
+        return "rest-openapi:" + parseText(camelContext, openApi.getSpecification());
+    }
+
     // Implementation
     // -------------------------------------------------------------------------
 
@@ -803,6 +833,18 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
             }
         }
 
+        // any open-api contracts
+        if (openApi != null) {
+            disabled = CamelContextHelper.parseBoolean(camelContext, openApi.getDisabled());
+            if (disabled != null && disabled) {
+                openApi = null;
+            }
+        }
+        if (!filter.isEmpty() && openApi != null) {
+            // we cannot have both code-first and contract-first in rest-dsl
+            throw new IllegalArgumentException("Cannot have both code-first and contract-first in Rest DSL");
+        }
+
         // sanity check this rest definition do not have duplicates
         validateUniquePaths(filter);
 
@@ -811,7 +853,12 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
             // sanity check this rest definition do not have duplicates linked routes via direct endpoints
             validateUniqueDirects(filter);
         }
-        addRouteDefinition(camelContext, filter, answer, config.getComponent(), config.getProducerComponent());
+        if (!filter.isEmpty()) {
+            addRouteDefinition(camelContext, filter, answer, config.getComponent(), config.getProducerComponent());
+        }
+        if (openApi != null) {
+            addRouteDefinition(camelContext, openApi, answer, config.getComponent(), config.getProducerComponent());
+        }
 
         return answer;
     }
@@ -909,6 +956,82 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
     }
 
     @SuppressWarnings("rawtypes")
+    private void addRouteDefinition(
+            CamelContext camelContext, OpenApiDefinition openApi, List<RouteDefinition> answer,
+            String component, String producerComponent) {
+
+        RouteDefinition route = new RouteDefinition();
+        // add dummy empty stop
+        route.getOutputs().add(new StopDefinition());
+
+        RestBindingDefinition binding = new RestBindingDefinition();
+        binding.setComponent(component);
+        if (binding.getBindingMode() != null) {
+            String mode = binding.getBindingMode();
+            if ("json".equals(mode)) {
+                binding.setConsumes("application/json");
+                binding.setProduces("application/json");
+            } else if ("xml".equals(mode)) {
+                binding.setConsumes("application/xml");
+                binding.setProduces("application/xml");
+            } else if ("json_xml".equals(mode)) {
+                binding.setConsumes("application/json;application/xml");
+                binding.setProduces("application/json;application/xml");
+            }
+        }
+        binding.setSkipBindingOnErrorCode(getSkipBindingOnErrorCode());
+        binding.setClientRequestValidation(getClientRequestValidation());
+        binding.setEnableCORS(getEnableCORS());
+        binding.setEnableNoContentResponse(getEnableNoContentResponse());
+
+        route.setRestBindingDefinition(binding);
+
+        // append options
+        Map<String, Object> options = new HashMap<>();
+        if (binding.getConsumes() != null) {
+            options.put("consumes", binding.getConsumes());
+        }
+        if (binding.getProduces() != null) {
+            options.put("produces", binding.getProduces());
+        }
+        if (component != null && !component.isEmpty()) {
+            options.put("consumerComponentName", component);
+        }
+        if (producerComponent != null && !producerComponent.isEmpty()) {
+            options.put("producerComponentName", producerComponent);
+        }
+        Boolean validate = parseBoolean(camelContext, getClientRequestValidation());
+        if (validate != null && validate) {
+            options.put("requestValidationEnabled", "true");
+        }
+
+        // include optional description
+        String description = openApi.getDescription();
+        if (description == null) {
+            description = getDescriptionText();
+        }
+        if (description != null) {
+            options.put("description", parseText(camelContext, description));
+        }
+
+        // create the from endpoint uri which is using the rest-openapi component
+        String from = buildFromUri(camelContext, openApi);
+
+        // append additional options
+        if (!options.isEmpty()) {
+            try {
+                from = URISupport.appendParametersToURI(from, options);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeCamelException(e);
+            }
+        }
+
+        // the route should be from this rest endpoint
+        route.fromRest(from);
+        route.setRestDefinition(this);
+        answer.add(route);
+    }
+
     private void addRouteDefinition(
             CamelContext camelContext, List<VerbDefinition> verbs, List<RouteDefinition> answer,
             String component, String producerComponent) {
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 0befa365a29..754fdcd576c 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -1121,6 +1121,7 @@ public class ModelParser extends BaseParser {
                 case "patch": doAdd(doParsePatchDefinition(), def.getVerbs(), def::setVerbs); break;
                 case "post": doAdd(doParsePostDefinition(), def.getVerbs(), def::setVerbs); break;
                 case "put": doAdd(doParsePutDefinition(), def.getVerbs(), def::setVerbs); break;
+                case "openApi": def.setOpenApi(doParseOpenApiDefinition()); break;
                 case "securityDefinitions": def.setSecurityDefinitions(doParseRestSecuritiesDefinition()); break;
                 case "securityRequirements": doAdd(doParseSecurityDefinition(), def.getSecurityRequirements(), def::setSecurityRequirements); break;
                 default: return optionalIdentifiedDefinitionElementHandler().accept(def, key);
@@ -3298,6 +3299,16 @@ public class ModelParser extends BaseParser {
             return true;
         }, noElementHandler(), noValueHandler());
     }
+    protected OpenApiDefinition doParseOpenApiDefinition() throws IOException, XmlPullParserException {
+        return doParse(new OpenApiDefinition(), (def, key, val) -> {
+            switch (key) {
+                case "disabled": def.setDisabled(val); break;
+                case "specification": def.setSpecification(val); break;
+                default: return optionalIdentifiedDefinitionAttributeHandler().accept(def, key, val);
+            }
+            return true;
+        }, optionalIdentifiedDefinitionElementHandler(), noValueHandler());
+    }
     protected OpenIdConnectDefinition doParseOpenIdConnectDefinition() throws IOException, XmlPullParserException {
         return doParse(new OpenIdConnectDefinition(), (def, key, val) -> {
             if ("url".equals(key)) {
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index f4ea46fe3c5..86c297846c1 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -981,6 +981,9 @@ public class ModelWriter extends BaseWriter {
     public void writeOAuth2Definition(OAuth2Definition def) throws IOException {
         doWriteOAuth2Definition("oauth2", def);
     }
+    public void writeOpenApiDefinition(OpenApiDefinition def) throws IOException {
+        doWriteOpenApiDefinition("openApi", def);
+    }
     public void writeOpenIdConnectDefinition(
             OpenIdConnectDefinition def)
             throws IOException {
@@ -4410,6 +4413,16 @@ public class ModelWriter extends BaseWriter {
         doWriteList(null, "scopes", def.getScopes(), this::doWriteRestPropertyDefinition);
         endElement(name);
     }
+    protected void doWriteOpenApiDefinition(
+            String name,
+            OpenApiDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteOptionalIdentifiedDefinitionAttributes(def);
+        doWriteAttribute("specification", def.getSpecification());
+        doWriteAttribute("disabled", def.getDisabled());
+        endElement(name);
+    }
     protected void doWriteOpenIdConnectDefinition(
             String name,
             OpenIdConnectDefinition def)
@@ -4561,6 +4574,7 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("disabled", def.getDisabled());
         doWriteAttribute("tag", def.getTag());
         doWriteAttribute("consumes", def.getConsumes());
+        doWriteElement("openApi", def.getOpenApi(), this::doWriteOpenApiDefinition);
         doWriteList(null, "securityRequirements", def.getSecurityRequirements(), this::doWriteSecurityDefinition);
         doWriteList(null, null, def.getVerbs(), this::doWriteVerbDefinitionRef);
         doWriteElement("securityDefinitions", def.getSecurityDefinitions(), this::doWriteRestSecuritiesDefinition);
@@ -4939,6 +4953,7 @@ public class ModelWriter extends BaseWriter {
                 case "DeleteDefinition" -> doWriteDeleteDefinition("delete", (DeleteDefinition) v);
                 case "GetDefinition" -> doWriteGetDefinition("get", (GetDefinition) v);
                 case "HeadDefinition" -> doWriteHeadDefinition("head", (HeadDefinition) v);
+                case "OpenApiDefinition" -> doWriteOpenApiDefinition("openApi", (OpenApiDefinition) v);
                 case "PatchDefinition" -> doWritePatchDefinition("patch", (PatchDefinition) v);
                 case "PostDefinition" -> doWritePostDefinition("post", (PostDefinition) v);
                 case "PutDefinition" -> doWritePutDefinition("put", (PutDefinition) v);
diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index 1de6d98bbfd..00ba07c5722 100644
--- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -981,6 +981,9 @@ public class ModelWriter extends BaseWriter {
     public void writeOAuth2Definition(OAuth2Definition def) throws IOException {
         doWriteOAuth2Definition("oauth2", def);
     }
+    public void writeOpenApiDefinition(OpenApiDefinition def) throws IOException {
+        doWriteOpenApiDefinition("openApi", def);
+    }
     public void writeOpenIdConnectDefinition(
             OpenIdConnectDefinition def)
             throws IOException {
@@ -4410,6 +4413,16 @@ public class ModelWriter extends BaseWriter {
         doWriteList(null, "scopes", def.getScopes(), this::doWriteRestPropertyDefinition);
         endElement(name);
     }
+    protected void doWriteOpenApiDefinition(
+            String name,
+            OpenApiDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteOptionalIdentifiedDefinitionAttributes(def);
+        doWriteAttribute("specification", def.getSpecification());
+        doWriteAttribute("disabled", def.getDisabled());
+        endElement(name);
+    }
     protected void doWriteOpenIdConnectDefinition(
             String name,
             OpenIdConnectDefinition def)
@@ -4561,6 +4574,7 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("disabled", def.getDisabled());
         doWriteAttribute("tag", def.getTag());
         doWriteAttribute("consumes", def.getConsumes());
+        doWriteElement("openApi", def.getOpenApi(), this::doWriteOpenApiDefinition);
         doWriteList(null, "securityRequirements", def.getSecurityRequirements(), this::doWriteSecurityDefinition);
         doWriteList(null, null, def.getVerbs(), this::doWriteVerbDefinitionRef);
         doWriteElement("securityDefinitions", def.getSecurityDefinitions(), this::doWriteRestSecuritiesDefinition);
@@ -4939,6 +4953,7 @@ public class ModelWriter extends BaseWriter {
                 case "DeleteDefinition" -> doWriteDeleteDefinition("delete", (DeleteDefinition) v);
                 case "GetDefinition" -> doWriteGetDefinition("get", (GetDefinition) v);
                 case "HeadDefinition" -> doWriteHeadDefinition("head", (HeadDefinition) v);
+                case "OpenApiDefinition" -> doWriteOpenApiDefinition("openApi", (OpenApiDefinition) v);
                 case "PatchDefinition" -> doWritePatchDefinition("patch", (PatchDefinition) v);
                 case "PostDefinition" -> doWritePostDefinition("post", (PostDefinition) v);
                 case "PutDefinition" -> doWritePutDefinition("put", (PutDefinition) v);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 6e27b84e32f..2080a28405f 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -223,6 +223,7 @@ import org.apache.camel.model.rest.GetDefinition;
 import org.apache.camel.model.rest.HeadDefinition;
 import org.apache.camel.model.rest.MutualTLSDefinition;
 import org.apache.camel.model.rest.OAuth2Definition;
+import org.apache.camel.model.rest.OpenApiDefinition;
 import org.apache.camel.model.rest.OpenIdConnectDefinition;
 import org.apache.camel.model.rest.ParamDefinition;
 import org.apache.camel.model.rest.PatchDefinition;
@@ -10345,6 +10346,66 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         }
     }
 
+    @YamlType(
+            nodes = {
+                    "open-api",
+                    "openApi"
+            },
+            types = org.apache.camel.model.rest.OpenApiDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            displayName = "Open Api",
+            description = "To use OpenApi as contract-first with Camel Rest DSL.",
+            deprecated = false,
+            properties = {
+                    @YamlProperty(name = "description", type = "string", description = "Sets the description of this node", displayName = "Description"),
+                    @YamlProperty(name = "disabled", type = "boolean", description = "Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", displayName = "Disabled"),
+                    @YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
+                    @YamlProperty(name = "specification", type = "string", required = true, displayName = "Specification")
+            }
+    )
+    public static class OpenApiDefinitionDeserializer extends YamlDeserializerBase<OpenApiDefinition> {
+        public OpenApiDefinitionDeserializer() {
+            super(OpenApiDefinition.class);
+        }
+
+        @Override
+        protected OpenApiDefinition newInstance() {
+            return new OpenApiDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(OpenApiDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            propertyKey = org.apache.camel.util.StringHelper.dashToCamelCase(propertyKey);
+            switch(propertyKey) {
+                case "disabled": {
+                    String val = asText(node);
+                    target.setDisabled(val);
+                    break;
+                }
+                case "specification": {
+                    String val = asText(node);
+                    target.setSpecification(val);
+                    break;
+                }
+                case "id": {
+                    String val = asText(node);
+                    target.setId(val);
+                    break;
+                }
+                case "description": {
+                    String val = asText(node);
+                    target.setDescription(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
     @YamlType(
             nodes = {
                     "open-id-connect",
@@ -14053,6 +14114,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "get", type = "array:org.apache.camel.model.rest.GetDefinition"),
                     @YamlProperty(name = "head", type = "array:org.apache.camel.model.rest.HeadDefinition"),
                     @YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
+                    @YamlProperty(name = "openApi", type = "object:org.apache.camel.model.rest.OpenApiDefinition", description = "To use an existing OpenAPI specification as contract-first for Camel Rest DSL.", displayName = "Open Api"),
                     @YamlProperty(name = "patch", type = "array:org.apache.camel.model.rest.PatchDefinition"),
                     @YamlProperty(name = "path", type = "string", description = "Path of the rest service, such as /foo", displayName = "Path"),
                     @YamlProperty(name = "post", type = "array:org.apache.camel.model.rest.PostDefinition"),
@@ -14114,6 +14176,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setEnableNoContentResponse(val);
                     break;
                 }
+                case "openApi": {
+                    org.apache.camel.model.rest.OpenApiDefinition val = asType(node, org.apache.camel.model.rest.OpenApiDefinition.class);
+                    target.setOpenApi(val);
+                    break;
+                }
                 case "path": {
                     String val = asText(node);
                     target.setPath(val);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index bf7c90a66be..371d2857f8f 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -270,6 +270,9 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "on-fallback": return new ModelDeserializers.OnFallbackDefinitionDeserializer();
             case "onFallback": return new ModelDeserializers.OnFallbackDefinitionDeserializer();
             case "org.apache.camel.model.OnFallbackDefinition": return new ModelDeserializers.OnFallbackDefinitionDeserializer();
+            case "open-api": return new ModelDeserializers.OpenApiDefinitionDeserializer();
+            case "openApi": return new ModelDeserializers.OpenApiDefinitionDeserializer();
+            case "org.apache.camel.model.rest.OpenApiDefinition": return new ModelDeserializers.OpenApiDefinitionDeserializer();
             case "open-id-connect": return new ModelDeserializers.OpenIdConnectDefinitionDeserializer();
             case "openIdConnect": return new ModelDeserializers.OpenIdConnectDefinitionDeserializer();
             case "org.apache.camel.model.rest.OpenIdConnectDefinition": return new ModelDeserializers.OpenIdConnectDefinitionDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 96c44926b48..00d55240b25 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -14668,6 +14668,34 @@
         },
         "required" : [ "key" ]
       },
+      "org.apache.camel.model.rest.OpenApiDefinition" : {
+        "title" : "Open Api",
+        "description" : "To use OpenApi as contract-first with Camel Rest DSL.",
+        "type" : "object",
+        "additionalProperties" : false,
+        "properties" : {
+          "description" : {
+            "type" : "string",
+            "title" : "Description",
+            "description" : "Sets the description of this node"
+          },
+          "disabled" : {
+            "type" : "boolean",
+            "title" : "Disabled",
+            "description" : "Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime."
+          },
+          "id" : {
+            "type" : "string",
+            "title" : "Id",
+            "description" : "Sets the id of this node"
+          },
+          "specification" : {
+            "type" : "string",
+            "title" : "Specification"
+          }
+        },
+        "required" : [ "specification" ]
+      },
       "org.apache.camel.model.rest.OpenIdConnectDefinition" : {
         "title" : "Open Id Connect",
         "description" : "Rest security OpenID Connect definition",
@@ -15518,6 +15546,11 @@
             "title" : "Id",
             "description" : "Sets the id of this node"
           },
+          "openApi" : {
+            "title" : "Open Api",
+            "description" : "To use an existing OpenAPI specification as contract-first for Camel Rest DSL.",
+            "$ref" : "#/items/definitions/org.apache.camel.model.rest.OpenApiDefinition"
+          },
           "patch" : {
             "type" : "array",
             "items" : {