christosgkoros opened a new pull request, #25390:
URL: https://github.com/apache/camel/pull/25390

   ## What this adds
   
   A new `camel-rest-postman` component that configures REST producers and 
contract-first REST consumers from a [Postman 
Collection](https://learning.postman.com/docs/collections/collections-overview/)
 instead of an OpenAPI specification. It is the Postman counterpart of 
`camel-rest-openapi`: it performs no HTTP itself and delegates to a component 
implementing `RestProducerFactory`.
   
   The motivation is that a large number of teams keep a Postman Collection as 
the only machine-readable description of their API, and today Camel has no way 
to consume that.
   
   The collection is loaded either from a Collection v2.1 JSON document 
(`classpath:`, `file:`, `http:`) or, by its uid, from the Postman cloud.
   
   ## Usage
   
   ```java
   // invoke one request
   from("direct:start")
       .to("rest-postman:petstore.json#getPetById");
   
   // run every request of a folder, or of the whole collection, like Postman's 
collection runner
   from("timer:smoke?period=60000")
       .to("rest-postman:petstore.json#pets");
   
   // serve the collection's requests, dispatching each to direct:<requestId>
   from("rest-postman:petstore.json")
       .to("direct:dummy");
   ```
   
   Multi-request runs return a `List<PostmanRunResult>` (status, body, headers, 
per-request failure), with `runFailFast` controlling whether the first failure 
aborts the run.
   
   ## Design notes
   
   **Addressing requests.** Postman items have a human name rather than an 
operation id, so the name is slugified (`Get Pet By Id` → `getPetById`), 
folder-qualified (`pets/getPetById`) when a name is not unique. `item.id` is 
accepted too, but note it is *optional* in the v2.1 schema and Postman's 
exporter strips it, so exported collections are normally addressed by slug and 
cloud-fetched ones by id. Both work.
   
   **Two credentials, deliberately named apart.** `postmanApiKey` authenticates 
against Postman in order to download a collection; it is never sent to the API 
the collection describes. The collection's own `auth` block authenticates 
against that API and is governed by `collectionAuth`, which defaults to 
`ignore` (with a startup warning naming the type found) because those values 
are usually unresolved `{{placeholders}}`, and silently attaching a credential 
found in a config file to outbound requests is surprising. An e2e test asserts 
the separation.
   
   **Security.** Redirects from `postmanApiUrl` are rejected rather than 
followed, since following one would replay the API key to the redirect target; 
`postmanApiUrl` must be HTTPS except for loopback; reads are bounded (8 MiB, 
5000 items, 64 folder levels); `apiContextPath` serves the collection with 
every `auth` block and every `type: secret` variable removed, unconditionally. 
Postman `event` scripts are never parsed or executed.
   
   **No new third-party dependency.** The collection is parsed with 
`camel-util-json`, already on the classpath via `camel-support`.
   
   ## Testing
   
   - 167 tests in `camel-rest-postman`
   - 8 contract-first consumer tests in `camel-platform-http-vertx`, following 
the precedent that `rest-openapi`'s consumer tests live there because 
`PlatformHttpComponent` is the only `RestOpenApiConsumerFactory` implementation
   - `mvn clean install -Psourcecheck` passes on both modified modules
   
   ## Two things I would especially like review on
   
   1. **Reusing the `RestOpenApiConsumerFactory` SPI** for a non-OpenAPI 
component. Its contract is entirely generic and `PlatformHttpComponent` is its 
only implementation; the alternative is a new SPI in `core/camel-api` plus a 
change to `camel-platform-http`. I took the smaller change deliberately, but 
the name is a wart and I am happy to switch if preferred.
   2. **`collectionAuth` defaulting to `ignore`** rather than `header`, per the 
reasoning above.
   
   ## Known gap
   
   For a path the collection *does* describe, a wrong-method request currently 
gets a 405 from the vert.x router before this component's processor runs, and 
the router leaves `Allow` empty. `rest-openapi` populates `Allow` in the 
equivalent case, so the difference is mine; the processor's own 404/405 
handling (with `Allow`) still applies to paths the router has no route for. I 
would appreciate a pointer here if the cause is obvious to someone who knows 
`platform-http` well.
   
   ## Notes
   
   No JIRA issue was created, as the contributing guide makes the reference 
conditional. Happy to open one if preferred. I have not yet raised this on 
`dev@`; I am opening the PR so there is something concrete to discuss and will 
start that thread.
   
   ---
   
   _This contribution was AI-assisted: written with [Claude 
Code](https://github.com/anthropics/claude-code) (Claude Opus) on behalf of 
@christosgkoros, who reviewed the design decisions. Commits carry a 
`Co-Authored-By` trailer._


-- 
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