Flow with multiple outbound HTTP calls

2019-07-25 08:52发布

问题:

We have a shopping cart domain model with line items. Externally, we have a single API to checkout the shopping cart. Internally though, we have 3 distinct HTTP services:

  1. Create shopping cart
  2. Add line item(s) - one HTTP call per line item
  3. Checkout

We'd like to express this in an integration flow, aborting if any of the steps fail or timeout. Here is some pseudo code for the flow:

 @Bean
public IntegrationFlow cartFlow() {
    return IntegrationFlows.from(channel())
            .transform(fromJson(ShoppingCart.class))
            .handle(Http.outboundGateway(.....) // How do we proceed here to create a shopping cart?
            .split(ShoppingCart.class, ShoppingCart::getLineItems)
            .handle(Http.outboundGateway(.....) // And here to add each line item?
            .aggregate()
            .handle(Http.outboundGateway(.....) // And here to checkout
            .get();
}

Adding the Http.outboundGateway calls isn't an issue. The question really is about preserving context (about the ShoppingCart after the HTTP method invocation). The services don't return any data beyond confirming that the call succeeded.

One option I understand is to create a custom bean which makes the HTTP calls and inject that into the pipeline. That approach doesn't feel very idiomatic to me.

Thanks!

回答1:

You use-case fully fit to the Content Enricher pattern, with which you have some payload, call some external service (via gateway on the request-channel), wait for the reply and add some content to the original payload.

For your use-case you might need several consequential .enrich() definitions.

Also see Spring Integration Content Enricher definition for more information.

EDIT

ContentEnricher sample:

@Bean
public IntegrationFlow enricherFlow() {
    return IntegrationFlows.from("enricherInput", true)
            .enrich(e -> e.requestChannel("enrichChannel")
                    .requestPayloadExpression("payload")
                    .shouldClonePayload(false)
                    .propertyExpression("name", "payload['name']")
                    .propertyFunction("date", m -> new Date())
                    .headerExpression("foo", "payload['name']")
            )
            .get();
}