Need to make a service callout, but don't want to lose original request variables, namely suffix

Not applicable

I have to make a service callout for retrieving an access token. My current approach is to use the AssignMessage policy, with createNew="true" but I believe this causes the original path suffix to be lost (since I don't want to preserve it and sent it to the oauth endpoint).

JavaScript might be an option, which I haven't explored, but focusing on policies... Is my only way to use an extract variable policy and then rewrite the target.url after I'm done with the token retrieval? Or is it possible to save the entire request object (maybe in proxyEndpoints.default.preFlow) and then put that stored request object back into context as the request, after the oauth flow completes?

Solved Solved
1 6 1,795
1 ACCEPTED SOLUTION

@Kd Ford You can create a message directly in the Service Callout policy by using variables and then assign the response to a variable.

This example calls out to Apigee BaaS to authenticate a user as part of an OAuth password grant flow. The response is an access_token from BaaS.

<ServiceCallout async="false" continueOnError="false" enabled="true" name="SC-Authenticate-User">
    <DisplayName>SC - Authenticate User</DisplayName>
    <Properties/>
    <Request clearPayload="false" variable="authenticate.request">
        <Set>
            <Headers>
                <Header name="Content-Type">application/x-www-form-urlencoded</Header>
            </Headers>
            <FormParams>
                <FormParam name="grant_type">{request.formparam.grant_type}</FormParam>
                <FormParam name="username">{request.formparam.username}</FormParam>
                <FormParam name="password">{request.formparam.password}</FormParam>
            </FormParams>
            <Verb>POST</Verb>
            <Path/>
        </Set>
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </Request>
    <Response>authenticate.response</Response>
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://api.usergrid.com/orgname/appname/token</URL>
    </HTTPTargetConnection>
</ServiceCallout>

You would then use an Extract Variable to parse the response. For example:

<ExtractVariables async="false" continueOnError="false" enabled="true" name="EV-Get-User-Info">
    <DisplayName>EV - Get User Info</DisplayName>
    <Properties/>
    <JSONPayload>
        <Variable name="userinfo_email">
            <JSONPath>$.user.email</JSONPath>
        </Variable>
        <Variable name="userinfo_username">
            <JSONPath>$.user.username</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">authenticate.response</Source>
    <VariablePrefix/>
</ExtractVariables>

View solution in original post

6 REPLIES 6

Not applicable

@Anil Sagar This is following from your previous helpful answer to me (around route rules best practices). Apigee by default copies the url suffix into the target endpoint request. I believe I have to lose that functionality by using a serviceCallout, so I'm looking for a clean way around that.

@Kd Ford You can create a message directly in the Service Callout policy by using variables and then assign the response to a variable.

This example calls out to Apigee BaaS to authenticate a user as part of an OAuth password grant flow. The response is an access_token from BaaS.

<ServiceCallout async="false" continueOnError="false" enabled="true" name="SC-Authenticate-User">
    <DisplayName>SC - Authenticate User</DisplayName>
    <Properties/>
    <Request clearPayload="false" variable="authenticate.request">
        <Set>
            <Headers>
                <Header name="Content-Type">application/x-www-form-urlencoded</Header>
            </Headers>
            <FormParams>
                <FormParam name="grant_type">{request.formparam.grant_type}</FormParam>
                <FormParam name="username">{request.formparam.username}</FormParam>
                <FormParam name="password">{request.formparam.password}</FormParam>
            </FormParams>
            <Verb>POST</Verb>
            <Path/>
        </Set>
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </Request>
    <Response>authenticate.response</Response>
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://api.usergrid.com/orgname/appname/token</URL>
    </HTTPTargetConnection>
</ServiceCallout>

You would then use an Extract Variable to parse the response. For example:

<ExtractVariables async="false" continueOnError="false" enabled="true" name="EV-Get-User-Info">
    <DisplayName>EV - Get User Info</DisplayName>
    <Properties/>
    <JSONPayload>
        <Variable name="userinfo_email">
            <JSONPath>$.user.email</JSONPath>
        </Variable>
        <Variable name="userinfo_username">
            <JSONPath>$.user.username</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">authenticate.response</Source>
    <VariablePrefix/>
</ExtractVariables>

Thank you Kurt,

So if I create the message directly in the service callout, the original request from the proxyendpoint will be retained for use in future flows/policies?

Yes, and even if you used Assign Message to create the request, it could be stored in a separate variable using the AssignTo element, such as:

<AssignMessage name="AM-Create-Authenticate-Request">
    <AssignTo createNew="true" type="request">authenticate.request</AssignTo>
    ...
</AssignMessage>

Then in the Service Callout would look like:

<ServiceCallout async="false" continueOnError="false" enabled="true" name="SC-Authenticate-User">
    <DisplayName>SC - Authenticate User</DisplayName>
    <Properties/>
    <Request clearPayload="false" variable="authenticate.request"/>
    <Response>authenticate.response</Response>
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://api.usergrid.com/orgname/appname/token</URL>
    </HTTPTargetConnection>
</ServiceCallout><br>

Check the docs for Service Callout and Assign Message, they have clear examples.

Fantastic! Thanks for that information Kurt. I wasn't aware of that but it's obvious that it could be stored in another variable now that you point it out.

Glad to help, if you're satisfied, don't forget to up-vote my answer, it helps others in the community.