calling http rest API from another API - spring-integration

I have API 1 which is defined by int-http:inbound-gateway and has service activator to perform some business logic and sends output on output channel same as reply channel of the inbound gateway(simple flow)
I also have API 2 which is defined in different xml file which also has int-http:inbound-gateway and int-http:outbound-gateway which performs on its own.
Now I want to call API 2 from API 1 but I don’t want to send message of the output channel of first API 1 to API 2, API 1 output channel response if for the end user to consume!
If I use request channel of the API 2 as output channel of API 1, I am thinking I will lose the output of the API 1.
Would you please help how this can be achieved?
Edit :
API 1(there is no need of outbound gateway as this API is doing db operations)
<int-http:inbound-gateway
request-channel="aRequestInputChannel"
reply-channel="aOutputChannel"
supported-methods="POST"
path="/perform"
mapped-request-headers="*"
request-payload-type="com.test.spring.integration.LPRequestPayload">
<int-http:request-mapping consumes="application/json" />
</int-http:inbound-gateway>
<int:service-activator input-channel="aRequestInputChannel" ref="IBAdapterController" method="attachData" output-channel="unRequestChannel"/>
API 2:
<int-http:inbound-gateway
request-channel="unRequestChannel"
reply-channel="unResponseChannel"
supported-methods="POST"
path="/test/unOp"
request-payload-type="com.test.spring.integration.LPRequestPayload"
mapped-request-headers="userId, userName, languageCode, HTTP_REQUEST_HEADERS" >
<int-http:request-mapping consumes="application/json,application/xml" />
<int-http:header name="userId" expression="#requestParams[userId]"/>
</int-http:inbound-gateway>
<int:service-activator input-channel="unRequestChannel" output-channel="unOutputChannel" ref="unAdapterController" method="getUnOpDetails" />
so here if I use output-channel="unRequestChannel" of first api as request channel of API 2,
I am loosing original payload as I am sending http response entity from the controller of the first api. I will need to send LPRequestPayload from first api which is not the requirement. as I am performing some db operation if first api, I need to send its response to the end user.
API 2 is like some mandatory operation that needs to be done after db operation is done.

You need to provide more info about your configuration and use-case.
It is not clear if you are going to call API instead of just replying from the service activator or in addition.
You may also learn that there is no need in the reply-channel in the inbound gateways and output-channel in the last in the flow endpoint. An inbound gateway always populates a replyChannel header and an endpoint (e.g. service activator) without an output-channel is going to produce its reply message exactly into that replyChannel from headers. So, it it might be possible that your requirements are met very easy:
inbound gateway 1 > request channel 1 -> service activator -> request channel 2
inbound gateway 2 > request channel 2 -> outbound gateway 2
With this configuration it doesn't matter if you have that inbound gateway 2 or not, the outbound gateway 2 is always going to reply to the replyChannel header from a request message. Therefore in your case when you initiate request from the inbound gateway 1, the outbound gateway 2 is going to reply back to that one. If you request via inbound gateway 2, then reply will come back exactly into this request initiator. The Reply Address pattern with its power.

Related

Poll a Durable Function inside an Azure API Management request

Is it possible to do a short polling internally in an APIM request then respond with sync response?
The flow goes like this:
1. APIM receives a request
2. APIM triggers a durable function orchestration.
3. APIM waits and polls the durable function response (through a policy?)
4. APIM responds with the actual result
To the API Consumer, it will be a single request.
Is this a common pattern? Or is it better to just provide the 202 Response polling URL to the API consumer? I'm expecting the request to take only around a few seconds to under a minute.
Is there a more standard way of doing this that I haven't considered yet?
It is subjective to how you want your API to be presented to the consumers.
If you want the front end users to poll the API then 202 Accepted response with a polling url in location header is the way.
If you want to disguise your API as a synchronous API , you will have to implement the polling pattern itself inside the APIM policy. For this refer following post
Use API-M To Mask Async APIs When Moving Implementation to Logic Apps, even though it pertains to logic app, you can implement the same pattern for any async API
excerpt from the link:
<outbound>
<base />
<retry condition="#(((IResponse)context.Variables["var"]).StatusCode == 202)" count="10" interval="30">
<send-request mode="new" response-variable-name="var" ignore-error="false">
<set-url>#(context.Response.Headers["location"][0])</set-url>
<set-method>GET</set-method>
</send-request>
</retry>
<return-response response-variable-name="var" />
</outbound>
As I pointed out earlier, it really depends upon how you want your API to be presented to your consumers. Both patterns are valid.

payload from http inbound store and retrieved at 3rd subsequent call in http outbound gateway

Context : I have inbound gateway which receives http request over json, which then goes to internal gateway, filtered and transformed , and sent to chain of http outbound gateway calls ( 4 calls ) and after 4 calls are complete, response is sent back to inbound gateway to send a response to client.
External System ( client ) calls > http Inbound gateway --> IFlow ( internal gateway #messaging gateway ) --> filters- transforms - > http outbound gateway --> External system ( api to retrieve data ).
between transform and http outbound gateway - there are 4 http calls over rest i.e. i call 4 external endpoints to get right data and send back to Client.
inbound gateway transforms json to model object at IFlow. lets say model object is CallModel.
At this point, i want to store this model object because later, i transforms the headers and payload for specific endpoints and if any extra header is there in request, external system throw error ( 409 and etc), therefore i cannot keep values in headers for calling http outbound gateway.
Is it possible to store CallModel or values from it, and not to propogate them for 3 successive http outbound gateway calls , and then at 4th call, i get CallModel and use values from it for 4th calls.
I thought about using a cache or creating a class to store, but perhaps there is a cleaner way.

Response Message passing between multiple Outbound gateway calls over Rest Api

I have one inbound gateway which receives messages over Rest. All messages recieved enter to Internal Gateway . Below is the inbound gateway xml file.
<bean name="testConfig" class="test.TestApiConfiguration"/>
<context:annotation-config/>
<int-http:inbound-gateway request-channel="requestChannel" supported-methods="POST" path="/data" reply-channel="replyChannel"
request-payload-type="com.test.model.CallFlow" header-mapper="cc20InBoundHeaders" error-channel="errorChannel" reply-timeout="9000">
<int-http:request-mapping produces="application/json" consumes="application/json"/>
</int-http:inbound-gateway>
<bean id="cc20InBoundHeaders" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
<property name="inboundHeaderNames" value="*"/>
</bean>
<bean id="cc20OutBoundHeaders" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
<property name="outboundHeaderNames" value="Content-Type, HTTP_REQUEST_HEADERS"/>
<property name="userDefinedHeaderPrefix" value="" />
</bean>
So, inbound gateway messages arrive as Json correctly and then an Internal Gateway accepts them and messages are passed into channels are per the configuration.
#MessagingGateway(name="callFlowGateway", requestChannel = "callFlowRequestChannel")
public interface ICallFlow {
/**
* Process CallFlow Request
* #param message SI Message covering APiCall payload and relevant headers for service
*/
#Gateway
void processCallFlowRequest(Message<CallFlow> message);
}
Till here, it works as expected. Messages flow to Filter and then router. in Router, if type of one json property is "drink" service, then drink channel is invoked and relevant outbound gateways are called to request an external API endpoints over REST.
But before calling each of the rest endpoints of that external API, you need to have a valid session id token to access other endpoints. It returns a session id in its payload to call other endpoints Beside that, it takes application/x-www-form-urlencoded as content Type in header.
I created a transformer to create request for authentication service.
#MessageEndpoint
public class AuthenticateTransformer {
#Transformer(inputChannel = "splitterChannel", outputChannel = "authenticateRequestChannel")
public Message<?> transform(CallFlow callFlow) {
Map<String, Object> messagePayload = new HashMap<String, Object>();
messagePayload.put("user", "test");
messagePayload.put("password", "test");
return MessageBuilder.withPayload(messagePayload).setHeader("Content-Type", "application/x-www-form-urlencoded").build();
}
}
So, ideally , a call comes to inbound gateway-
Json is converted to an internal object. Based on one property value in JSON, i call different external rest endpoints using http outbound gateway.
Since the call for authentication to get session id is not in Json that is received, i have to create an order in the flow.
I need to invoke an http outbound gateway for authentication to get that session id. How can i invoke this outbound from inbound gateway because that should be executed before every call to other endpoint.
After i get that session id , then i want other endpoints over Rest, at this phase, i want ICallFlow gateway to be called , so that based on value in json, and that session id from step 1, i can call other rest endpoints and get response back.
So, i am stuck in passing that session id token from First call to the second call ? plus i want ICallFlow only be invoked after first authentication request is complete , and pass that session into other subsequent requests. I read that header enricher can do that, where i can put payload into headers, but somehow its not working. Also, i am not sure how to create above flow in the right order.
Any help would be highly appreciated.
You that's too much information in a single thread and it somehow confusing and misleading.
What I can suggest you is something like ContentEnricher: https://docs.spring.io/spring-integration/docs/5.0.1.RELEASE/reference/html/messaging-transformation-chapter.html#payload-enricher
So, you will call that auth service via request-channel sub-flow, get a session id back and will be able to populate it into headers or that ICallFlow payload if that is possible.
you should be careful using MessageBuilder in the #Transformer use-case. That one doesn't merge request headers afterwards and you won't be able to bring a response to the <int-http:inbound-gateway> in the beginning, just because the replyChannel header will be lost.
The way to carry request headers is like accept a Message in the transform() method and call copyHeaders() on the MessageBuilder.

Extracting a Principal User in Spring Integration HTTP Inbound adapter

In my Spring Integration project (with Spring Security API using Basic Authorization), I am trying to access the Principal object in order to read the Username.
This is the structure of the inbound gateway:
<int-http:inbound-gateway request-channel="gatewayRequests"
reply-channel="gatewayResponses"
supported-methods="POST"
path="/api/v1/myservice"
request-payload-type="java.lang.String" reply-timeout="100">
<int-http:request-mapping consumes="application/xml" produces="application/xml"/>
<int-http:header name="principal" expression="T(org.springframework.security.core.context.SecurityContextHolder).context.authentication.principal"/>
</int-http:inbound-gateway>
I got the aforementioned expression from the reply in this:
Spring Integration and http inbound adapter, how do I extract a principal user?
Despite successful authentication, I don't see the principal - is my syntax correct in expecting the result of the expression to be mapped to a message header?
Instead of the mapping to the header, if I were to use the following, how do I access the Principal value in the code layer (assuming it gets added into the payload)?
<payload-
expression="T(org.springframework.security.core.context.SecurityContextHolder).
context.authentication.principal">
Can anyone kindly help me?
Sincerely,
Bharath
There is already a header like:
.setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL,
servletRequest.getUserPrincipal())
in the message sent to the gatewayRequests.
Why that doesn't work for you?
OTOH that expression must work too. If you don't have that one, then you can't assume that you are authenticated correctly...

Spring Integration WS Response Soap Headers

I have the below use case.
Request is received by the ws-inbound gateway of service1.
Service1 Passes the request to another ws-outbound gateway service2
Service2 ws inbound gateway has an interceptor configured, which adds a custom soap header to the response
the response from service 2 is passed to the output channel of service 1 (Final response).
I am able to see that soap header is added by printing the soap envelope in interceptor (service2), but it is not present in the final response. Any pointers to solve this issue will be helpful
The <int-ws:outbound-gateway> uses DefaultSoapHeaderMapper by default.
And its logic to populate source.getSoapAction(); and source.getSoapHeader();. But for that purpose you should configure mapped-reply-headers for your desired headers on the <int-ws:outbound-gateway>.

Resources