I'm writing a proof of concept utilising the Azure API Management solution.
I am trying to write an <inbound>
policy which does the following:
- Uses
<send-request>
to make a request to an authentication endpoint of an API. - The authentication API returns two keys which must be included as http headers to be able to make subsequent requests to other endpoints.
- I'm parsing the response from the authentication API as json using
JObject
- Then I'm trying to read the values from the two properties of the json object (they are strings)
- Then, I will make a subsequent request to a different API endpoint, with two http headers set. The value of the headers must be the two variables from the first (authentication) response.
This is what my policy looks like currently:
<inbound>
<base />
<!-- Authenticate with the API and get authentication tokens for subsequent calls -->
<send-request mode="new" response-variable-name="auth" timeout="20" ignore-error="true">
<set-url>https://www.service.com/api/authenticate</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>
@{
var credentials = new JObject();
credentials.Add(new JProperty("logonId", "{{API_LOGON_USERNAME}}"));
credentials.Add(new JProperty("logonPassword", "{{API_LOGON_PASSWORD}}"));
return credentials.ToString();
}
</set-body>
</send-request>
<!-- Make second query to a different endpoint, using the authentication tokens as http headers -->
<send-request mode="new" response-variable-name="data" timeout="20" ignore-error="true">
<set-url>https://www.service.com/api/data</set-url>
<set-method>GET</set-method>
<set-header name="TokenA" exists-action="override">
<value>
@{
JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>();
return identity.SelectToken("TokenA").ToString();
}
</value>
</set-header>
<set-header name="TokenB" exists-action="override">
<value>
@{
JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>();
return identity.SelectToken("TokenB").ToString();
}
</value>
</set-header>
</send-request>
<!-- Return response from the second API -->
<return-response response-variable-name="responseData">
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>
@{
JObject api_response = ((IResponse)context.Variables["data"]).Body.As<JObject>();
return api_response.ToString();
}
</set-body>
</return-response>
</inbound>
The issue I am having is around setting the value for the second header (Token B). It appears that I cannot re-use the context variable (IResponse)context.Variables["auth"]
.
When I review the trace, I see the following output for the first <set-header>
policy:
"message":"Expression was successfully evaluated.", "value":"xxxxxxxxxxxxxxxxxxxxx"
But for the second <set-header>
policy I get:
"message":"Expression evaluation failed.", "details":"Object reference not set to an instance of an object."
I can see that, after calling the method on the first policy, I am no longer able to reuse the context variable in the same way in the second <set-header>
policy.
I have tried:
- Setting the Token strings using
<set-variable>
. I believe there are a limited number of types that<set-variable>
can return, and I cannot return theIResponse
or theJObject
. If I attempt to convert to json then extract the string of each property (TokenA and TokenB) I get the same issue as above.
Could someone please help me with the syntax to allow me to copy the IResponse
object or the JObject
so that I can read it twice using .SelectToken()
? I'm sure I'm misunderstanding a fundamental concept, but I am far from a seasoned C# developer!
Thanks