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 7ec5d50566b CAMEL-20979: if no operationId is specified, generate an 
id (#15257)
7ec5d50566b is described below

commit 7ec5d50566b5afeb3377726b9866de82be46af81
Author: klease <38634989+kle...@users.noreply.github.com>
AuthorDate: Wed Aug 21 20:07:52 2024 +0200

    CAMEL-20979: if no operationId is specified, generate an id (#15257)
    
    * CAMEL-20979: if no operationId is specified, generate an id
    base on the path and the http method. This allows the user
    to add a route if the OpenAPI specification is not modifiable.
    
    * Lower log level and remove commented code.
---
 .../DefaultRestOpenapiProcessorStrategy.java       | 23 ++++++-
 .../openapi/RestOpenapiProcessorStrategyTest.java  | 76 ++++++++++++++++++++++
 .../src/test/resources/missing-opid.yaml           | 59 +++++++++++++++++
 3 files changed, 156 insertions(+), 2 deletions(-)

diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
index 7d62f6a169c..c931dc20102 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
@@ -25,6 +25,7 @@ import java.util.stream.Collectors;
 
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.PathItem.HttpMethod;
 import io.swagger.v3.oas.models.examples.Example;
 import io.swagger.v3.oas.models.media.Content;
 import io.swagger.v3.oas.models.media.MediaType;
@@ -64,6 +65,8 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
 
     private static final String BODY_VERBS = "DELETE,PUT,POST,PATCH";
 
+    private static final String GEN_OPID = "GENOPID_";
+
     private CamelContext camelContext;
     private ProducerCache producerCache;
     private String component = "direct";
@@ -75,8 +78,9 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
     public void validateOpenApi(OpenAPI openAPI, PlatformHttpConsumerAware 
platformHttpConsumer) throws Exception {
         List<String> ids = new ArrayList<>();
         for (var e : openAPI.getPaths().entrySet()) {
-            for (var o : e.getValue().readOperations()) {
-                String id = o.getOperationId();
+            for (var o : e.getValue().readOperationsMap().entrySet()) {
+                Operation op = o.getValue();
+                String id = op.getOperationId() != null ? op.getOperationId() 
: generateOperationId(e.getKey(), o.getKey());
                 ids.add(component + "://" + id);
             }
         }
@@ -145,6 +149,21 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
         }
     }
 
+    /**
+     * If the operation has no operationId specified, generate one based on 
the path and the operation method.
+     *
+     * @param  path       The path for this operation, such as /users.
+     * @param  httpMethod The operation to perform
+     * @return            A generated operation id based on the path and the 
operation. Slashes and braces in the path
+     *                    are replaced with placeholder characters.
+     */
+    private String generateOperationId(String path, HttpMethod httpMethod) {
+        final String sanitizedPath = path.replace('/', '.').replaceAll("[{}]", 
"_");
+        final String opId = GEN_OPID + httpMethod.name() + sanitizedPath;
+        LOG.debug("Generated operationId {} for path {} and method {}", opId, 
path, httpMethod.name());
+        return opId;
+    }
+
     @Override
     public boolean processApiSpecification(String specificationUri, Exchange 
exchange, AsyncCallback callback) {
         try {
diff --git 
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategyTest.java
 
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategyTest.java
new file mode 100644
index 00000000000..7c906b41106
--- /dev/null
+++ 
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategyTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.rest.openapi;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.platform.http.PlatformHttpComponent;
+import org.apache.camel.component.platform.http.spi.PlatformHttpConsumerAware;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+class RestOpenapiProcessorStrategyTest extends ManagedCamelTestSupport {
+
+    private CamelContext camelContext;
+
+    @BeforeEach
+    public void createMocks() throws Exception {
+        initializeContextForComponent("rest-openapi");
+    }
+
+    @Test
+    void testMissingOperationId() throws Exception {
+        RestOpenapiProcessorStrategy restOpenapiProcessorStrategy = new 
DefaultRestOpenapiProcessorStrategy();
+        ((DefaultRestOpenapiProcessorStrategy) 
restOpenapiProcessorStrategy).setCamelContext(camelContext);
+        restOpenapiProcessorStrategy.setMissingOperation("fail");
+        Exception ex = assertThrows(IllegalArgumentException.class,
+                () -> 
restOpenapiProcessorStrategy.validateOpenApi(getOpenApi(), 
mock(PlatformHttpConsumerAware.class)));
+        assertTrue(ex.getMessage().contains("direct:GENOPID_GET.users"));
+        assertTrue(ex.getMessage().contains("direct:GENOPID_GET.user._id_"));
+
+    }
+
+    private OpenAPI getOpenApi() {
+        return RestOpenApiEndpoint.loadSpecificationFrom(camelContext, 
"missing-opid.yaml");
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:getUsers").to("mock:getUsers");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext(String componentName) {
+
+        camelContext = new DefaultCamelContext();
+        PlatformHttpComponent httpCmpn = mock(PlatformHttpComponent.class);
+        camelContext.addComponent("platform-http", httpCmpn);
+        return camelContext;
+    }
+
+}
diff --git a/components/camel-rest-openapi/src/test/resources/missing-opid.yaml 
b/components/camel-rest-openapi/src/test/resources/missing-opid.yaml
new file mode 100644
index 00000000000..7fe589eb7f2
--- /dev/null
+++ b/components/camel-rest-openapi/src/test/resources/missing-opid.yaml
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+openapi: 3.0.0
+info:
+  title: Sample API
+  description: Optional multiline or single-line description in 
[CommonMark](http://commonmark.org/help/) or HTML.
+  version: 0.1.9
+servers:
+  - url: http://api.example.com/v1
+    description: Optional server description, e.g. Main (production) server
+  - url: http://staging-api.example.com
+    description: Optional server description, e.g. Internal staging server for 
testing
+paths:
+  /users:
+    get:
+      summary: Returns a list of users.
+      description: Optional extended description in CommonMark or HTML.
+      responses:
+        '200':    # status code
+          description: A JSON array of user names
+          content:
+            application/json:
+              schema: 
+                type: array
+                items: 
+                  type: string
+
+  /user/{id}:
+    get:
+      summary: Return a user by id
+      parameters:
+        - name: id
+          in: path
+          description: ID of user to return
+          required: true
+          type: integer
+          format: int64
+      responses:
+        '200':    # status code
+        description: A JSON array of user names
+        content:
+          application/json:
+             schema: 
+               type: string
\ No newline at end of file

Reply via email to