Andrew Chart
Andrew Chart

Reputation: 653

How Can I Reuse the Response Context Variable in Azure API Management Policy?

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:

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:

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

Upvotes: 4

Views: 9248

Answers (1)

Mandar Dharmadhikari
Mandar Dharmadhikari

Reputation: 1119

The reason you are getting the error is because of the way you are reading the response body. when you read the body as

JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>();

you are basically disposing of the body from the context variable. Hence the next time you read the variable body, it throws the infamous Object reference error. To work with reading the bodies in Azure API management, you need to use the preservecontent property in your code. SO you will read the body as shown below

JObject identity = ((IResponse)context.Variables["auth"]).Body.As<JObject>(preserveContent: true);

When you do this, the original body is preserved and only a copy of the body is injected in the evaluation. You can find in depth documentation about this at "Set Body- APIM policy"

Upvotes: 10

Related Questions