Redirect using Assign Message policy

Hi @anilsagar ,

Flow:
Client > ASGW > Target 1> (Redirect Assign Message Policy) > Target 2

We have a request which first should be sent to target 1 and in response to it we will receive Status Code:303 and header with URL of the second target (Target2).

We are using Assign Message policy to redirect to target 2

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-Redirect">
    <DisplayName>RedirectOffers</DisplayName>
    <Properties/>
    <Set>
        <StatusCode>303</StatusCode>
        <Headers>
            <Header name="Location">{target.response.url}>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="true" transport="http" type="request"/>
</AssignMessage>

We have added the below code in TargetEndPoint PostFlow response

 

 

<PostFlow name="PostFlow">
        <Request/>
        <Response>
            <Step>
                <Name>AM-Redirect</Name>
            </Step>
        </Response>
    </PostFlow>

 


We are able to successfully redirect and get status code: 200 but not able to receive the response body.
Could you please help?

Solved Solved
1 13 1,464
1 ACCEPTED SOLUTION

I believe that explanation covered how to use Apigee to SEND a 302 response back to the requesting client.

"To issue a redirect from Apigee Edge, you can use the AssignMessage policy. ...

The wording is a little odd, but "issue a redirect" implies "send a 30x back to the requester."   It does not mean that the AssignMessage policy FOLLOWS a redirect. As I said above, the AssignMessage policy does not follow redirects. 

The AssignMessage policy can be used to modify the current request or response message, or some other message. You can set verbs, status codes, payloads, headers, queryparams, and so on.  Effectively AssignMessage allows you to alter an in-memory representation of a thing, inside the API Proxy.  The policy performs no communication. 

View solution in original post

13 REPLIES 13

@joel_gauci@dchiesa1, @carlosrsantos Can you please help?

Sorry I had missed this question one month ago. I am not clear on what the problem is.

We are able to successfully redirect and get status code: 200 but not able to receive the response body.

I am not clear on "we are able to ...get status code: 200" means. Which thing is "we" in this case? Which system is receiving the 200 ? Which thing is not receiving the response body?

Can you share a sequence diagram? Or maybe a more clear description of which system is calling which other system, where the 303 is returned, and where the 200 is returned, and what you expect to happen that you are not seeing?

Hi @dchiesa1 ,

Flow:
Client > ASGW > Target 1 > (Redirect Assign Message Policy) > Target 2

When I hit target 1, target 1 redirects our request to target 2.

Response from Target1:

Status code: 303 with Location Header: https://example.com?queryParams.

If we use curl -L target1URL I can follow the redirect and get the response from the target2. (-L: is used to follow the redirects)

Response from Target2:

Status code: 200 and response payload

If I use curl target1URL we get status code: 303 and the location header from target1. In this case we don’t follow the redirect.

I am just trying to follow the redirect in Apigee by following the solution provided in this page https://www.googlecloudcommunity.com/gc/Apigee/Trying-to-redirect-to-the-new-url-from-the-target-ser...

As I hit the first target, I get response status code: 303 (redirect) with location header which holds the value of target2. Location header looks like this https://example.com?queryParams

Using the location header I am trying to redirect to target2 using AssignMessage Policy.  When AM-Redirect is executed my final response status code is still 303 instead of 200 with no payload. 

 Can you please tell where I am doing it wrong?

 

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-Redirect">
    <DisplayName>AM-Redirect</DisplayName>
    <Properties/>
    <Remove>
        <Payload/>
    </Remove>
    <Set>
        <StatusCode>303</StatusCode>
        <Headers>
            <Header name="Authorization">Bearer {Token}</Header>
            <Header name="Location">{target.response.header.location}</Header>
            <Header name="Access-Control-Allow-Origin">*</Header>
            <Header name="Access-Control-Allow-Methods">OPTIONS</Header>
            <Header name="Access-Control-Allow-Headers">Accept, Content-Type</Header>
            <Header name="Access-Control-Allow-Credentials">true</Header>
        </Headers>
        <ReasonPhrase>{response.reason.phrase}</ReasonPhrase>
        <Payload>{response.content)</Payload>
        <Path/>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="true" transport="http" type="response"/>
</AssignMessage>

 

I have added the below code in TargetEndPoint PostFlow response

 

<PostFlow name="PostFlow">
        <Request/>
        <Response>
            <Step>
                <Name>AM-Redirect</Name>
            </Step>
        </Response>
</PostFlow>

 

 

Hi @dchiesa1 ,

Please let me know if you need more information.

Thank you.

Hi Rohit

ok thanks for that explanation. I understand that in your API proxy, when the proxy receives a 303 status code, you are executing an AssignMessage policy in the Target Response PostFlow. In that assignMessage policy you set the statuscode and assign a few headers. Because the AssignTo element is blank, this AssignMessage will affect the "message" variable. Because the policy is attached to in the Target Response PostFlow, "message" will be the response message. So with this policy you are overwriting some things in the response message.

After that policy executes, I expect that Apigee will transmit the response message back to the originating client. That will happen, unless you have something in the ProxyEndpoint logic to modify the response message further. I guess this explains what you are observing. According to my understanding, Apigee and your API proxy are working as documented.

I think you are expecting that by executing an AssignMessage policy, the Apigee API Proxy will follow the redirect implicitly. That is not the case. Executing AssignMessage does not cause an outbound request to be sent. There is no configuration of the AssignMessage policy that you can apply that will cause AssignMessage to "follow a redirect." Also, there is no setting on the Apigee TargetEndpoint that is analogous to the -L option on the curl command. If you would like Apigee to invoke the URL specified in the Location header in the target response, you need to configure specific, explicit logic to do that. That logic might be a ServiceCallout or a JavaScript policy which uses the httpClient. Either of those things will send out an additional HTTP request. If you do this, then you'll want to wrap the policy in a Condition such that the ServiceCallout or JavaScript gets called only in the case that there is a Location header in the response. Possibly you may wish to check for 302, 303, 307 etc. as well. AssignMessage will not cause Apigee to invoke an external endpoint. all it does is assign to the internal variable that holds the message content.

If you use ServiceCallout then the configuration should be something like this:

 

 

<ServiceCallout name='SC-Follow-Redirect'>
  <Request variable='myrequestvariable'>
    <Set>
     <Headers>
        ...whatever is appropriate here, if anything...
     </Headers>
     <!-- redirect should always be GET -->
     <Verb>GET</Verb>
     <Path>{sc_urlPath}</Path>
    </Set>
  </Request>
  <Response>secondResponse</Response>
  <HTTPTargetConnection>
    <SSLInfo>
        <Enabled>true</Enabled>
        <IgnoreValidationErrors>true</IgnoreValidationErrors>
    </SSLInfo>
    <Properties>
      <Property name='success.codes'>2xx, 3xx, 4xx, 5xx</Property>
    </Properties>
    <URL>https://this-value-will-be-replaced.com</URL>
  </HTTPTargetConnection>
</ServiceCallout>

 

 

Note the URL and Path elements there. You want that to take a value, determined by the value of the Location header in the response from the first call. You cannot use a variable there. You cannot use a message template. There IS a way to set a URL dynamically for the ServiceCallout. It is described in this post.

Basically, use a JavaScript policy configured like this BEFORE the ServiceCallout policy:

 

 

<Javascript name='JS-Assign-Dynamic-URL-for-ServiceCallout' timeLimit='200' >
  <Properties>
    <Property name='variableContainingSourceUrl'>response.header.Location</Property>
    <Property name='scPolicyName'>SC-Follow-Redirect</Property>
  </Properties>
  <ResourceURL>jsc://assign-Dynamic-URL-for-ServiceCallout.js</ResourceURL>
</Javascript>

 

 

And the JS code is like this:

 

 

var urlvalue = context.getVariable(properties.variableContainingSourceUrl);
var re = new RegExp('^(https?://[^/]+)(/.*)$');
var match = re.exec(urlvalue);
if (match) {
  context.setVariable('servicecallout.' + properties.scPolicyName + '.target.url', match[1]);
  context.setVariable('sc_urlPath', match[2]);
}

 

 

After that ServiceCallout executes you will have the "response" message which contains the original response with the 303 status. And you will have "secondResponse" (configured in that ServiceCallout policy) which contains the response from the 2nd request. If you want the original client to get the response from the second request, you need to copy it over. This can be done with AssignMessage, like so:

 

 

<AssignMessage name='AM-Copy-Response'>
  <AssignTo createNew="false" transport="http" type="response">response</AssignTo>
  <!-- first, remove everything in the destination response message -->
  <Remove/>
  <!-- then, "copy everything" -->
  <Copy source="secondResponse"/>
</AssignMessage>

 

 

Wrapping all that up, the flow should look like this in the TargetEndpoint response flow:

 

 

<PostFlow name='postflow'>
    <Response>
      <Step>
        <Condition>NOT (response.header.location = null)</Condition>
        <Name>JS-Assign-Dynamic-URL-for-ServiceCallout</Name>
      </Step>
      <Step>
        <Condition>NOT (response.header.location = null)</Condition>
        <Name>SC-Follow-Redirect</Name>
      </Step>
      <Step>
        <Condition>NOT (response.header.location = null)</Condition>
        <Name>AM-Copy-Response</Name>
      </Step>
    </Response>
</PostFlow>

 

 

Hi @dchiesa1 ,

Thank you, for the detailed answer!

I have already implemented ServiceCallout policy as a work around solution.

Because of this the flow is  Client > ASGW > Target 1 > ASGW(ServiceCallout) > Target2. This is increasing the number of network hops resulting in increase of response time.

I was just trying to follow the solution provide in this  page. When I am using the AssignMessage policy as mentioned above. In the trace, I can see response received from target 1 is 303 and location header. After AssignMessage policy is executed the Status code is 200 with no response body. So the client is receiving 200 with no response body.

ok I understand you are concerned about network hops. I don't understand the flow you're showing.  Normally a redirect is like this: 

screenshot-20220805-084414.png

And I think what you want is the client app (or maybe browser) to invoke an Apigee endpoint, which invokes some upstream system, which returns 30x, and then you want Apigee to invoke the 2nd location. like so: 

screenshot-20220805-085104.png

That is what I showed you how to do in my prior reply.  You need to use ServiceCallout within Apigee to follow the redirect.  And then after ServiceCallout, copy the response from SC to the response Apigee will send to the client. 

I understand you are concerned about network hops, but any 30x response code will require an additional request, from SOME ACTOR.  It can be either the originating app, or it can be Apigee, but to follow a redirect there must be an additional request.

Hi @dchiesa1 ,

Thank you, for explaining about the redirects. 

"To issue a redirect from Apigee Edge, you can use the AssignMessage policy. Within the policy, set the Location header, and set the StatusCode to be 302 or 301 (as you prefer). You probably should remove the Payload, if there is one. You may also want to set CORS headers. This policy should run on the response flow." - This is written in https://www.googlecloudcommunity.com/gc/Apigee/Trying-to-redirect-to-the-new-url-from-the-target-ser... 

Can't we use the AissgnMessage policy to follow the redirect?

Hi @dchiesa1 ,

Sorry, for being little pushy here. Does this mean the solution provided Here is wrong? 

I believe that explanation covered how to use Apigee to SEND a 302 response back to the requesting client.

"To issue a redirect from Apigee Edge, you can use the AssignMessage policy. ...

The wording is a little odd, but "issue a redirect" implies "send a 30x back to the requester."   It does not mean that the AssignMessage policy FOLLOWS a redirect. As I said above, the AssignMessage policy does not follow redirects. 

The AssignMessage policy can be used to modify the current request or response message, or some other message. You can set verbs, status codes, payloads, headers, queryparams, and so on.  Effectively AssignMessage allows you to alter an in-memory representation of a thing, inside the API Proxy.  The policy performs no communication. 

Thank you, @dchiesa1!

Hi I am facing same issue the redirect doesn't seem to be working as expected. 

@dchiesa1  is this redirect supported in Apigee? 

Yours seems like a new question. You should ask it in a new question rather than posing it as a response to a different question.

 I think you are asking about redirects and your observation is not consistent with your expectation. But I don't know what you are trying, what configuration you are using, and how Apigee is involved.

I'd like to help. I will help, if you do these things: 

  • ask a new question
  • when you ask, provide details about (1) how you have configured Apigee (policies, endpoints, flows), (2) what you are observing and how you are observing it, (3) what you expect to observe, and (4) if it is not immediately clear, how those two things (actual vs expected observations) differ.