Skip to content

CAMEL-24649: Add unmatched request handler to REST OpenAPI component - #26203

Draft
ullgren wants to merge 1 commit into
apache:mainfrom
ullgren:CAMEL-24649-add-unmatched-request-handler
Draft

CAMEL-24649: Add unmatched request handler to REST OpenAPI component#26203
ullgren wants to merge 1 commit into
apache:mainfrom
ullgren:CAMEL-24649-add-unmatched-request-handler

Conversation

@ullgren

@ullgren ullgren commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Description

Adding a unmatched request handler allowing for library users to customize the response that REST OpenAPI component sends back when the request does not match any operation in the OAS.

Target

  • I checked that the commit is targeting the correct branch (Camel 4 uses the main branch)

Tracking

  • If this is a large change, bug fix, or code improvement, I checked there is a JIRA issue filed for the change (usually before you start working on it).

Apache Camel coding standards and style

  • I checked that each commit in the pull request has a meaningful subject line and body.

  • I have run mvn clean install -DskipTests locally from root folder and I have committed all auto-generated changes.

AI-assisted contributions

  • If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., Co-authored-by trailers) and the PR description identifies the AI tool used.

@ullgren
ullgren marked this pull request as draft September 8, 2026 11:23

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Thanks for this Pontus — nice piece of work. The extension point follows the exact idiom the JIRA asked for (lookupUnmatchedRequestHandler() mirrors RestBindingAdviceFactory.lookupRestClientRequestValidator()), the default handler reproduces the previous behaviour verbatim so there is no regression for existing users, both doc copies are in sync, and the tests cover default and custom handlers for both status codes.

Verification performed

Check Result
mvn verify in components/camel-rest-openapi (build cache disabled) pass
Test totals 148 run, 0 failures / errors / skipped
New RestOpenApiUnmatchedRequestHandlerTest 5 tests pass
mvn formatter:format impsort:sort no diff produced
src/main/docs vs catalog/.../docs mirror byte-identical
xref:manual::registry.adoc target resolves

Prior-art check: the 404/405 block dates back to 447dcd3c4571 (CAMEL-20557, the original contract-first implementation), so this change does not revert any later intentional decision.

No blocking issues. Three inline notes below, plus these three that are not tied to a single line:

Should the interface live in camel-api rather than the component?

components/camel-rest-postman/src/main/java/org/apache/camel/component/rest/postman/RestPostmanProcessor.java#L117-L125 contains a byte-identical 404/405 block. The precedent the JIRA cites, RestClientRequestValidator, lives in core/camel-api under org.apache.camel.spi rather than in a component. Putting this interface there instead would let camel-rest-postman reuse it, rather than growing a second, incompatible handler SPI later. Component-local is defensible for a first cut — mainly flagging it so the choice is deliberate.

No @UriParam endpoint option

The sibling extension point on this same component, restOpenapiProcessorStrategy, is exposed as @UriParam(label = "consumer,advanced") on RestOpenApiEndpoint, which gives per-endpoint configuration plus catalog and tooling discoverability. The new handler is resolved once per CamelContext, so two rest-openapi endpoints in one context cannot use different handlers. RestClientRequestValidator is registry-only too, so this matches the model you were asked to follow — but the in-component precedent points the other way. Your call.

Commit body

Commit 91dd59f has a meaningful subject but an empty body, while the PR checklist ticks "each commit has a meaningful subject line and body". Minor, but easy to fill in on the next push.


Note: the PR is still a draft and CI has not run yet, so I have not identified reviewers — that step applies once it is marked ready for review.

Scope: this is a rules-and-conventions review against the project's .oss-ai-helper-rules/ and CLAUDE.md, backed by a real local build and test run. It is not a substitute for CodeRabbit, Sourcery, or SonarCloud static analysis.

Claude Code on behalf of davsclaus

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

private final String apiContextPath;
private final List<RestConsumerContextPathMatcher.ConsumerPath<Operation>> paths = new ArrayList<>();
private final RestOpenapiProcessorStrategy restOpenapiProcessorStrategy;
private RestOpenApiUnmatchedRequestHandler unmatchedRequestHandler;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defensive nit: this field is assigned only in afterPropertiesConfigured(), and RestOpenApiEndpoint.createConsumer() wires that callback conditionally:

if (consumer instanceof PlatformHttpConsumerAware phca) {
    phca.registerAfterConfigured(openApiProcessor);
}

Today PlatformHttpComponent is the only RestOpenApiConsumerFactory in the tree, so the callback always fires and this is unreachable in practice. But the previous inline code had no such dependency: where it would have degraded to a plain 404, this would NPE. Initialising the field at declaration removes the whole class of risk for free, and afterPropertiesConfigured() still overwrites it with the resolved handler.

Suggested change
private RestOpenApiUnmatchedRequestHandler unmatchedRequestHandler;
private RestOpenApiUnmatchedRequestHandler unmatchedRequestHandler = new DefaultRestOpenApiUnmatchedRequestHandler();

*/
public interface RestOpenApiUnmatchedRequestHandler {

String FACTORY = "rest-openapi-unmatched-request-handler-factory";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test gap: the factory-finder route this constant enables is public contract but has no test coverage — all five new tests go through the registry path. A small test registering a META-INF/services/org/apache/camel/rest-openapi-unmatched-request-handler-factory resource would lock the constant's value in.

Related, worth being aware of rather than a defect: CamelContextHelper.findSingleByType returns null when more than one handler is registered, so two beans of this type silently fall back to the default with no warning. That is consistent with how RestClientRequestValidator behaves, so no change needed in the code — but see my note on the docs.

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. In both cases the response body is empty.

To return a custom response, for example a JSON error body, register a bean in the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs nit: this documents only the registry route, but lookupUnmatchedRequestHandler() also supports the META-INF/services factory-finder route via RestOpenApiUnmatchedRequestHandler.FACTORY. It is also worth stating that exactly one such bean may be registered — findSingleByType returns null for two or more, silently falling back to the default handler.

One extra sentence here would cover both. (Remember to mirror any change into the catalog/camel-catalog/.../docs/ copy — you already have that right in this PR.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants