Croway commented on code in PR #27960:
URL: https://github.com/apache/camel/pull/27960#discussion_r4302646413


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java:
##########
@@ -407,6 +309,110 @@ private List<OperationStub> collectOperationStubs(OpenAPI 
openAPI) {
         return stubs;
     }
 
+    /**
+     * One mock file per path of the spec. For an operation without a route, 
camel-rest-openapi serves the first
+     * resource of mockIncludePattern (default classpath:camel-mock/**) whose 
location without extension ends with the
+     * request path, whatever the method: a path parameter is matched by its 
value, so {@code /pets/{petId}} takes one
+     * file per value, and the listed file carries the sample value {@code 1}, 
such as {@code camel-mock/pets/1.json}.
+     */
+    private List<MockFileInfo> collectMockFiles(OpenAPI openAPI) {
+        List<MockFileInfo> files = new ArrayList<>();
+        if (openAPI.getPaths() == null) {
+            return files;
+        }
+        for (Map.Entry<String, PathItem> pathEntry : 
openAPI.getPaths().entrySet()) {
+            String path = pathEntry.getKey();
+            Map<PathItem.HttpMethod, Operation> operations = 
pathEntry.getValue().readOperationsMap();
+            if (operations == null || operations.isEmpty()) {
+                continue;
+            }
+
+            List<String> operationIds = new ArrayList<>();
+            Map<String, String> withoutFile = new LinkedHashMap<>();
+            String responseType = null;
+            String example = null;
+            for (Map.Entry<PathItem.HttpMethod, Operation> opEntry : 
operations.entrySet()) {
+                String method = opEntry.getKey().name();
+                Operation op = opEntry.getValue();
+                operationIds.add(operationId(path, opEntry.getKey(), op));
+
+                if (op.getResponses() != null) {
+                    Map.Entry<String, ApiResponse> success = 
findFirstSuccessResponse(op.getResponses());
+                    if (responseType == null && success != null && 
success.getValue().getContent() != null
+                            && !success.getValue().getContent().isEmpty()) {
+                        responseType = 
success.getValue().getContent().keySet().iterator().next();
+                    }
+                }
+                if (BODY_VERBS.contains(method)) {
+                    withoutFile.put(method, "echoes the request body with HTTP 
200");
+                    continue;
+                }
+                ApiResponse ok = op.getResponses() != null ? 
op.getResponses().get("200") : null;
+                String opExample = firstExample(ok);
+                if (opExample != null) {
+                    withoutFile.put(method, "answers the example of its '200' 
response with HTTP 200 when the request's"

Review Comment:
   Done in 4e4c2b0a4461: the per-path note now reads "answers the example of 
its '200' response with HTTP 200 for a matching Content-Type or Accept (see 
modeExplanation), otherwise HTTP 204"; the full rule stays in `modeExplanation` 
only.
   
   _Claude Code on behalf of Croway_



##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/OpenApiTools.java:
##########
@@ -407,6 +309,110 @@ private List<OperationStub> collectOperationStubs(OpenAPI 
openAPI) {
         return stubs;
     }
 
+    /**
+     * One mock file per path of the spec. For an operation without a route, 
camel-rest-openapi serves the first
+     * resource of mockIncludePattern (default classpath:camel-mock/**) whose 
location without extension ends with the
+     * request path, whatever the method: a path parameter is matched by its 
value, so {@code /pets/{petId}} takes one
+     * file per value, and the listed file carries the sample value {@code 1}, 
such as {@code camel-mock/pets/1.json}.
+     */
+    private List<MockFileInfo> collectMockFiles(OpenAPI openAPI) {
+        List<MockFileInfo> files = new ArrayList<>();
+        if (openAPI.getPaths() == null) {
+            return files;
+        }
+        for (Map.Entry<String, PathItem> pathEntry : 
openAPI.getPaths().entrySet()) {
+            String path = pathEntry.getKey();
+            Map<PathItem.HttpMethod, Operation> operations = 
pathEntry.getValue().readOperationsMap();
+            if (operations == null || operations.isEmpty()) {
+                continue;
+            }
+
+            List<String> operationIds = new ArrayList<>();
+            Map<String, String> withoutFile = new LinkedHashMap<>();
+            String responseType = null;
+            String example = null;
+            for (Map.Entry<PathItem.HttpMethod, Operation> opEntry : 
operations.entrySet()) {
+                String method = opEntry.getKey().name();
+                Operation op = opEntry.getValue();
+                operationIds.add(operationId(path, opEntry.getKey(), op));
+
+                if (op.getResponses() != null) {
+                    Map.Entry<String, ApiResponse> success = 
findFirstSuccessResponse(op.getResponses());
+                    if (responseType == null && success != null && 
success.getValue().getContent() != null
+                            && !success.getValue().getContent().isEmpty()) {
+                        responseType = 
success.getValue().getContent().keySet().iterator().next();
+                    }
+                }
+                if (BODY_VERBS.contains(method)) {
+                    withoutFile.put(method, "echoes the request body with HTTP 
200");
+                    continue;
+                }
+                ApiResponse ok = op.getResponses() != null ? 
op.getResponses().get("200") : null;
+                String opExample = firstExample(ok);
+                if (opExample != null) {
+                    withoutFile.put(method, "answers the example of its '200' 
response with HTTP 200 when the request's"
+                                            + " Content-Type or Accept header 
names a media type of that response"
+                                            + " (Accept */* takes 
application/json, then application/xml), otherwise"
+                                            + " HTTP 204 with an empty body");
+                    if (example == null) {
+                        example = opExample;
+                    }
+                } else {
+                    // no example in the '200' response, or no '200' response 
at all (CAMEL-25663): an empty answer
+                    withoutFile.put(method, "answers HTTP 204 with an empty 
body");
+                }
+            }
+
+            String ext = responseType != null && responseType.contains("xml") 
? ".xml" : ".json";
+            StringBuilder note = new StringBuilder("Served with HTTP 200 for 
any method of ").append(path)
+                    .append(" without a route.");
+            // the component matches the request path, not the template: a 
path parameter takes a sample value
+            String sample = path.replaceAll("\\{[^}]+}", 
SAMPLE_PATH_PARAMETER_VALUE);
+            if (path.contains("{")) {
+                note.append(" Camel matches the request path, so the file name 
carries the value the request uses:"
+                            + " camel-mock")
+                        .append(sample).append(ext).append(" answers 
").append(sample)
+                        .append(", add one file per value.");
+            }
+            note.append(" Without the file, ");
+            withoutFile.forEach((method, answer) -> 
note.append(method).append(' ').append(answer).append("; "));
+            note.setLength(note.length() - 2);
+            note.append('.');
+
+            // the component matches a resource whose location without 
extension ends with the request path without its
+            // leading slash; for the root path that is the empty string, so 
any mock file matches
+            String fileName = "/".equals(path) ? "camel-mock/index" + ext : 
"camel-mock" + sample + ext;
+            if ("/".equals(path)) {
+                note.append(" Camel matches the root path to any mock file 
(the first one found), so with more than"
+                            + " one file the one that answers / is not 
predictable.");
+            }
+            files.add(new MockFileInfo(fileName, path, operationIds, example, 
note.toString()));
+        }
+        return files;
+    }
+
+    /**
+     * The example camel-rest-openapi answers in mock mode for an operation 
without mock file: the example, or the first
+     * of the examples, of a media type of its "200" response.

Review Comment:
   Done in 4e4c2b0a4461: the javadoc says the example is a preview of the file 
content and that at runtime camel-rest-openapi takes the example of the media 
type matching the request. The related point from the review is in the same 
commit: the example is taken from the media type that names the extension when 
it has one, else from the first media type with an example, and the extension 
then follows that media type, so content and file name agree (test 
`scaffoldNamesTheMockFileAfterTheMediaTypeOfItsExample`: a `200` with 
`application/json` without example and `application/xml` with one gives 
`camel-mock/pets.xml` with the XML).
   
   _Claude Code on behalf of Croway_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to