gnodet-bot commented on code in PR #26203:
URL: https://github.com/apache/camel/pull/26203#discussion_r4120646627
##########
components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java:
##########
@@ -100,6 +114,22 @@ public boolean process(Exchange exchange, AsyncCallback
callback) {
RestConsumerContextPathMatcher.ConsumerPath<Operation> m
= RestConsumerContextPathMatcher.matchBestPath(verb, path,
paths);
if (m instanceof RestOpenApiConsumerPath rcp) {
+ // when server request validation is enabled, the HTTP layer
rejects requests whose Content-Type
+ // or Accept header does not match the consumes/produces of the
operation with 415/406. However,
+ // depending on the runtime, such requests may still be routed to
Camel (via an unconstrained
+ // catch-all route or a matchOnUriPrefix endpoint), so the
rejected requests must be answered
+ // here instead of being processed as if they were valid
+ if (serverRequestValidation) {
Review Comment:
⚠️ **Scope too broad — behaviour change for existing users.** (Confirming
@davsclaus's finding.)
This guard fires whenever `serverRequestValidation` is true on the
platform-http component — which is the **default**. So in the default
`platform` mode (no catch-all, no `unmatchedRequestHandling=camel`), Camel now
rejects requests with wrong Content-Type/Accept that previously passed through
to the route. That's a silent breaking change for every rest-openapi consumer.
Additionally, `RestUtil.isValidOrAcceptedContentType` strips at the first
`;` *globally* before splitting on `,`, so `Accept: application/xml;q=0.9,
application/json` becomes `application/xml` → 406 even though
`application/json` is acceptable. Wildcard types like `application/*` or `*/*`
also never match.
Gate this on the catch-all being active:
```suggestion
if (serverRequestValidation &&
unmatchedRequestCatchAllRegistered) {
```
And the `RestUtil` parsing needs per-part parameter stripping (separate fix,
but a test for q-valued Accept would lock the expectation in).
##########
components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc:
##########
@@ -202,6 +202,126 @@ If any of the validation checks fail, then a
`RestOpenApiValidationException` is
has a `getValidationErrors` method that returns the error messages from the
validator.
+== Unmatched requests
+
+By default, an incoming request that does not match any operation in the
OpenAPI specification is answered by the
+HTTP layer of the runtime, with HTTP 404, and a request that matches a path
but not the HTTP method is answered
+with HTTP 405 and an `Allow` header listing the allowed methods.
+
+A request that matches an operation but whose `Content-Type` or `Accept`
header does not match the `consumes` or
+`produces` of the operation is answered by the HTTP layer, with HTTP 415 or
406 (see the `serverRequestValidation`
+option of the platform-http component, enabled by default). When
`unmatchedRequestHandling` is set to `camel`,
+some runtimes also route these requests to Camel, so the unmatched request
handler answers them with the same
+415 or 406 status code.
+
+To let Camel answer these requests instead, set the `unmatchedRequestHandling`
option to `camel` on the
+rest-openapi consumer endpoint or via the rest DSL `openApi` section. The
rest-openapi component then registers a
+catch-all for the API base path on the HTTP layer so requests that match no
operation are routed to Camel, where
+they are answered by the unmatched request handler.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("rest-openapi:petstore-v3.json?missingOperation=ignore&unmatchedRequestHandling=camel")
+ .to("direct:businessLogic");
+
+// ... or using the rest DSL
+
+rest().openApi()
+ .specification("petstore-v3.json")
+ .missingOperation("ignore")
+ .unmatchedRequestHandling("camel");
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: rest-openapi:petstore-v3.json
+ parameters:
+ missingOperation: ignore
+ unmatchedRequestHandling: camel
+ steps:
+ - to:
+ uri: direct:businessLogic
+
+# ... or using the rest DSL
+
+- rest:
+ openApi:
+ specification: petstore-v3.json
+ missingOperation: ignore
+ unmatchedRequestHandling: camel
+----
+====
+
+The option is supported by the built-in `platform-http` consumer component:
Camel Main when using
+xref:platform-http-component.adoc[Platform HTTP], and Spring Boot when using
the platform-http starter
+(`camel-platform-http-starter`). Other consumer components are not tested and
can decide to handle, ignore or
+reject the parameter.
+
+On Camel Main and Quarkus, the catch-all route is evaluated last on the HTTP
server, so it never shadows the
+operation routes of other APIs served by the same server, even when their base
paths are nested under this API.
+
+[NOTE]
+====
+With nested base paths (for example `/api` and `/api/v3`), the order of the
catch-all follows the order in
+which the consumers start: `PUT /api/v3/pet/123` may get a 404 from `/api`
instead of 405 with an `Allow`
+header from `/api/v3`. To work around this, avoid nesting the base paths of
several APIs in `camel`
+mode, or inspect the request in a custom `RestOpenApiUnmatchedRequestHandler`
and determine the proper response.
+====
+
+On Spring Boot, the catch-all is served by a Spring MVC handler mapping that
is evaluated before the
+application's own controller mappings and the static resources. With a base
path of `/`, in `camel` mode
+every request unmatched by the API will be answered by the unmatched request
handler. Controllers and static
+resources will be shadowed. When the application also serves MVC contet it is
prefered to use a base path other
+than `/` (for example by setting `servers` in the OpenAPI specification or
`contextPath` in the rest
Review Comment:
📝 **Four typos in two lines.** `contet` → `content`, `prefered` →
`preferred`. Also the next paragraph has `set register your own` → `register
your own` and `a order` → `an order`.
Remember to regenerate the catalog mirror copy
(`catalog/camel-catalog/.../docs/rest-openapi-component.adoc`) afterwards.
```suggestion
resources will be shadowed. When the application also serves MVC content, it
is preferred to use a base path other
than `/` (for example by setting `servers` in the OpenAPI specification or
`contextPath` in the rest
```
##########
components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc:
##########
@@ -202,6 +202,126 @@ If any of the validation checks fail, then a
`RestOpenApiValidationException` is
has a `getValidationErrors` method that returns the error messages from the
validator.
+== Unmatched requests
+
+By default, an incoming request that does not match any operation in the
OpenAPI specification is answered by the
+HTTP layer of the runtime, with HTTP 404, and a request that matches a path
but not the HTTP method is answered
+with HTTP 405 and an `Allow` header listing the allowed methods.
+
+A request that matches an operation but whose `Content-Type` or `Accept`
header does not match the `consumes` or
+`produces` of the operation is answered by the HTTP layer, with HTTP 415 or
406 (see the `serverRequestValidation`
+option of the platform-http component, enabled by default). When
`unmatchedRequestHandling` is set to `camel`,
+some runtimes also route these requests to Camel, so the unmatched request
handler answers them with the same
+415 or 406 status code.
+
+To let Camel answer these requests instead, set the `unmatchedRequestHandling`
option to `camel` on the
+rest-openapi consumer endpoint or via the rest DSL `openApi` section. The
rest-openapi component then registers a
+catch-all for the API base path on the HTTP layer so requests that match no
operation are routed to Camel, where
+they are answered by the unmatched request handler.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("rest-openapi:petstore-v3.json?missingOperation=ignore&unmatchedRequestHandling=camel")
+ .to("direct:businessLogic");
+
+// ... or using the rest DSL
+
+rest().openApi()
+ .specification("petstore-v3.json")
+ .missingOperation("ignore")
+ .unmatchedRequestHandling("camel");
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: rest-openapi:petstore-v3.json
+ parameters:
+ missingOperation: ignore
+ unmatchedRequestHandling: camel
+ steps:
+ - to:
+ uri: direct:businessLogic
+
+# ... or using the rest DSL
+
+- rest:
+ openApi:
+ specification: petstore-v3.json
+ missingOperation: ignore
+ unmatchedRequestHandling: camel
+----
+====
+
+The option is supported by the built-in `platform-http` consumer component:
Camel Main when using
+xref:platform-http-component.adoc[Platform HTTP], and Spring Boot when using
the platform-http starter
+(`camel-platform-http-starter`). Other consumer components are not tested and
can decide to handle, ignore or
+reject the parameter.
+
+On Camel Main and Quarkus, the catch-all route is evaluated last on the HTTP
server, so it never shadows the
+operation routes of other APIs served by the same server, even when their base
paths are nested under this API.
+
+[NOTE]
+====
+With nested base paths (for example `/api` and `/api/v3`), the order of the
catch-all follows the order in
+which the consumers start: `PUT /api/v3/pet/123` may get a 404 from `/api`
instead of 405 with an `Allow`
+header from `/api/v3`. To work around this, avoid nesting the base paths of
several APIs in `camel`
+mode, or inspect the request in a custom `RestOpenApiUnmatchedRequestHandler`
and determine the proper response.
+====
+
+On Spring Boot, the catch-all is served by a Spring MVC handler mapping that
is evaluated before the
+application's own controller mappings and the static resources. With a base
path of `/`, in `camel` mode
+every request unmatched by the API will be answered by the unmatched request
handler. Controllers and static
+resources will be shadowed. When the application also serves MVC contet it is
prefered to use a base path other
+than `/` (for example by setting `servers` in the OpenAPI specification or
`contextPath` in the rest
+configuration), so the catch-all only claims requests under that path.
+
+If the API and Spring MVC controllers must keep responding to their own paths
at a base path of `/`, you can
+set register your own `RequestMappingHandlerMapping` bean with a order set to
`-50`. This will still not work for
+serving static resources.
Review Comment:
```suggestion
register your own `RequestMappingHandlerMapping` bean with an order set to
`-50`. This will still not work for
serving static resources.
```
--
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]