Extract variable from Response Cookie using XML

I need to extract the SESSION id from the Set-Cookie. I want to use the XML method for variable extraction. This is the RAW text from the response that I need to extract the SESSION id:

HTTP/1.1 302 Found
Date: Mon, 04 Jun 2018 23:28:41 GMT
Content-Length: 0
Connection: close
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: SAMEORIGIN
Set-Cookie: SESSION=28912d6b-4d75-42bf-8bc6-8f19f56cd7b0; Path=/linkos/; Secure; HttpOnly
Location: somewhere.com

This is the flow we are trying to produce:

/scantoprint (virtual proxy endpoint)

We need to collect 5 things, place them in the formData of the virtual endpoint:

  • {Username}
  • {Password}
  • {Printer SN}
  • {LabelCode}
  • {Data}
  1. After receiving this request
  2. Parse out all 5 into some session variables
  3. Use the Username and Password
  4. Place them in the body of the /{PPME_API_Access_proxy}/login
  5. Send the POST
  6. Retrieve the Response
  7. Capture the {Session id} from the cookie
  8. Add it to the API header
  9. Populate the FormData with {Data) and {LabelCode}
  10. Insert the printer {Printer SN} into the path of the second target /{PPME_API_Access_proxy}/devices/{Printer SN}/sendRawData
  11. Send the POST to print the barcode label.

Individually, using Postman, it works using our PPME proxy endpoints. We use both printer endpoints, and manually copy the session id from one cookie to the header of the other. However we need to be able to do this in APIGEE as a proof of concept

Solved Solved
1 7 2,560
1 ACCEPTED SOLUTION

Hi @Dino Gregorich

Welcome to the community !! I am assuming you are referring to the Extract Variable policy. If yes, then the policy code can be something like this

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Cookie">
    <DisplayName>Extract-Cookie</DisplayName>
    <Properties/>
    <Header name="Set-Cookie">
        <Pattern ignoreCase="false">SESSION={cookie};*</Pattern>
    </Header>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Source clearPayload="false">response</Source>
    <VariablePrefix>respPrefix</VariablePrefix>
</ExtractVariables>

Once this is executed, the session ID should be available in a variable called "respPrefix.cookie"

Let me know if this works

View solution in original post

7 REPLIES 7

Hi @Dino Gregorich

Welcome to the community !! I am assuming you are referring to the Extract Variable policy. If yes, then the policy code can be something like this

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Cookie">
    <DisplayName>Extract-Cookie</DisplayName>
    <Properties/>
    <Header name="Set-Cookie">
        <Pattern ignoreCase="false">SESSION={cookie};*</Pattern>
    </Header>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Source clearPayload="false">response</Source>
    <VariablePrefix>respPrefix</VariablePrefix>
</ExtractVariables>

Once this is executed, the session ID should be available in a variable called "respPrefix.cookie"

Let me know if this works

The code you provided worked! Thank you for making it more clear.

However, it does not work where I need it. It only executes when I put it in the ALL Post flow. I need it after a login endpoint, and I tried to put it in the Response section of the login end point, but it never executes (ran a trace). I need it to login, grab the session id from the cookie, create a new request to another endpoint, pass the session id into the request header cookie and then execute. Any ideas why it will not run where I need it? Thank you.

If you want a single request into Apigee Edge to perform that workflow - login, grab session id, create another request, then (not sure what else) - you will need to use the ServiceCallout or JavaScript or something else to make additional outbound HTTP calls.

You said the policy doesn't run when you put it in the response flow of the login endpoint. that's sort of important, you'll need to sort that out. Probably there is a misunderstanding or bad assumption somewhere.

Can you show us

  • a screenshot of the trace UI, for the login flow (maybe with the "skipped" policy showing)
  • the XML for the flow, in which you include this ExtractVariables policy

apigee-extract-variable.zip

Nice to meet another Dino! I probably have it all wrong. But we have not had a class nor training yet. Attached is a zip of the 4 screenshots, the ones that worked and the ones that did not (GUI and XML).

If we can figure this out, it will probably serve as our base example for the many others we may need to build.

This is the flow we are trying to produce:

/scantoprint (virtual proxy endpoint)

We need to collect 5 things, place them in the formData of the virtual endpoint:

  • {Username}
  • {Password}
  • {Printer SN}
  • {LabelCode}
  • {Data}
  1. After receiving this request
  2. Parse out all 5 into some session variables
  3. Use the Username and Password
  4. Place them in the body of the /{PPME_API_Access_proxy}/login
  5. Send the POST
  6. Retrieve the Response
  7. Capture the {Session id} from the cookie
  8. Add it to the API header
  9. Populate the FormData with {Data) and {LabelCode}
  10. Insert the printer {Printer SN} into the path of the second target /{PPME_API_Access_proxy}/devices/{Printer SN}/sendRawData
  11. Send the POST to print the barcode label.

Individually, using Postman, it works using our PPME proxy endpoints. We use both printer endpoints, and manually copy the session id from one cookie to the header of the other. However we need to be able to do this in APIGEE as a proof of concept

Hi, but if we have a dynamic name for the cookie, how can we fix it?

I've the cookie header name scoped to environment, for example in production is "SMSESSION".

I want to do something like this, but it can t resolve variable:

<Pattern ignoreCase="false">{null1}{MYVAR-COOKIE-NAME}={session_cookie}</Pattern>

ask a new question please

ok I see what you're doing, maybe where it's going wrong. Thanks for the screenshots.

The Flow in the Apigee Edge proxy endpoint is a key concept. Let's make sure you're clear on how it works. The image that depicts how flows work is:

The image that depicts the flows is:

6966-proxy-endpoints.png

As you can see there are 4 combinations. In the order in which they execute, they are:

  1. proxy request
  2. target request
  3. target response
  4. proxy response

But it's not quite as simple as that. In Apigee Edge the proxy and the target each have a preflow, zero or more "conditional flows", and a "postflow". They execute in that order. Therefore each of the above 4 combinations is really 3, giving 12 attachment points in total. The order is like this:

  1. proxy request
    1. preflow
    2. conditional flow
    3. postflow
  2. target request
    1. preflow
    2. conditional flow
    3. postflow
  3. target response
    1. preflow
    2. conditional
    3. postflow
  4. proxy response
    1. preflow
    2. conditional
    3. postflow

In your XML, which looks like this:

6983-2-conditional-flows.png

...you have two flows. At most ONE of those flows will execute.

The first flow, the "/login" flow, will execute if the condition evaluates to true given the inbound (inbound to Apigee Edge) request. Basically if the inbound is a POST to /login, then... that flow executes; the other flow will not. If the inbound request is a POST and the path matches "/devices/*/sendRawData", then the 2nd flow will execute, and not the first. If neither of those conditions evaluates to true, then neither flow executes.

I think what you want is a condition something like this:

<Flows>
  <Flow name='f1'>
    <Condition>(proxy.pathsuffix MatchesPath "/scantoprint") and (request.verb = "POST")</Condition>
    <Request>... </Request>
    <Response>...</Response>
  </Flow>
 ...
</Flows>

Basically that says "the inbound request ought to be a POST and the path is /scantoprint" . THAT is the interface you want to expose to the callers. That acts as the facade for the steps you outlined in your post.

And under the Request element , you want to post out to the login element. You would do this with a ServiceCallout policy configured like so:

<ServiceCallout name='SC-1'>
  <Request>
    <Set>
     <Headers>
       <Header name='content-type'>application/x-www-form-urlencoded</Header>
     </Headers>
     <FormParams>
       <FormParam name='username'>{request.form.username}</FormParam>
       <FormParam name='password'>{request.form.password}</FormParam>
     </FormParams>
     <Verb>POST</Verb>
    </Set>
  </Request>
  <Response>loginResponse</Response>
  <HTTPTargetConnection>
    <SSLInfo>
        <Enabled>true</Enabled>
    </SSLInfo>
    <Properties>
      <Property name='success.codes'>2xx, 3xx, 4xx, 5xx</Property>
    </Properties>
    <URL>https://myserver/PPME_API_Access_proxy/login</URL>
  </HTTPTargetConnection>
</ServiceCallout><br>

What's going on there? That thing is saying "take the username and password from the inbound request form parameters, and create a NEW outbound request to a login endpoint. Save the response into a message variable called loginResponse.

To execute that ServiceCallout, You would need to configure your flow like this:

<Flows>
  <Flow name='f1'>
    <Condition>(proxy.pathsuffix MatchesPath "/scantoprint") and (request.verb = "POST")</Condition>
    <Request>
      <Step>
        <Name>SC-1</Name>
      </Step>
      ...
    </Request>
    <Response>...</Response>
  </Flow>
 ...
</Flows>

Then your extraction is:

<ExtractVariables name="Extract-Cookie">
    <DisplayName>Extract-Cookie</DisplayName>
    <Header name="Set-Cookie">
        <Pattern ignoreCase="false">SESSION={cookie};*</Pattern>
    </Header>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Source>loginResponse</Source>
    <VariablePrefix>login</VariablePrefix>
</ExtractVariables>

Notice the source is loginResponse, which is the thing returned from that ServiceCallout. And this policy fits in right after SC-1 in the flow:

<Flows>
  <Flow name='f1'>
    <Condition>(proxy.pathsuffix MatchesPath "/scantoprint") and (request.verb = "POST")</Condition>
    <Request>
      <Step>
        <Name>SC-1</Name>
      </Step>
      <Step>
        <Name>Extract-Cookie</Name>
      </Step>
      ...
    </Request>
    <Response>...</Response>
  </Flow>
 ...
</Flows>

ok, now what you want to do is dynamically construct the URL for the "target". In Apigee Edge you can do this by setting the target.url context variable. You can do that with JavaScript policy, like this:

var printerSN = context.getVariable('request.formparam.printersn');
context.setVariable('target.url', 
   'https://PPME_server/devices/' + printerSN + '/sendRawData');  

But you need to take care when setting it - that variable gets reset at the inception of the target flow. So that JS policy needs to run in the target. This looks like this:

<TargetEndpoint name="sendraw">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
           <Step>
             <Name>JS-SetTargetUrl</Name>
           </Step>
        </Request>
        <Response/>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows/>
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://will-be-overwrtitten.com/</URL>
    </HTTPTargetConnection>
</TargetEndpoint>