Creating Send Request Policy in Azure APIM

Jul 06, 2025 | 5 min read | 58 Views

Not sure about sending friend requests, but Azure APIM supports Send Request Policy that helps to make API calls while your request being processed at APIM level. In this article, we will explore how in this world APIM Send Request Policy works and how to create one.

There can be need to make API request while the traffic flows (inbound or outbound) through APIM, this can be handled through the legendary Send Request Policy. For an instance there can be scenario where we want to hit some endpoints to monitor traffic, or we need to authenticate/authorize incoming requests or we need to trigger some additional functionality when the request completes at the outbound level. The policy contains properties and allows to add tags to formulate the request headers and payload along with authentication if needed.

APIM policies are pretty helpful overall, one such policy we have explored in previous article, which helps to perform JWT Authentication of request, read more from here Creating Validate Jwt Policy In Azure Apim.

In this article, we will go through the code snippets and supporting steps to understand how to create and apply send-request policy. We will head in this direction:

  • Create Send Request Policy
  • Properties and Tags
  • Consuming Response Variable
  • More Examples
  • Creating Policy Fragment

Create Send Request Policy

Follow below steps to add policy to your API endpoint:

  • Select the API endpoint or All Operations or All APIs.
  • Click on the "Policy Editor" button present in the "Inbound processing" section.
  • Add the policy code below the "<base />" tag within "<inbound>" section.

Below shows the template of the "send-request" policy:

<send-request response-variable-name="apiResponse">
  <set-url>YOUR_REQUEST_URL</set-url>
  <set-method>YOUR_REQUEST_METHOD</set-method>
  <set-header>YOUR_REQUEST_HEADER</set-header>
  <set-body>YOUR_REQUEST_BODY</set-body>
</send-request>

Here, we have a template of "send-request" policy with some placeholder values like YOUR_REQUEST_URL, YOUR_REQUEST_METHOD, these can be replaced with actual values.

Properties and Tags

Let us break down the policy and understand the what-is-what, for this below shows the send-request policy with some fake real values:

<send-request response-variable-name="apiResponse">
  <set-url>https://jsonplaceholder.typicode.com/users</set-url>
  <set-method>POST</set-method>
  <set-header name="Content-Type" exists-action="override">
    <value>application/json</value>
  </set-header>
  <set-body>@{
    string username = "jackwood";
    string email = "jackwood@mail.com";
    return new JObject(
      new JProperty("username", username),
      new JProperty("email", email)
    ).ToString();
  }
  </set-body>
</send-request>

Here, we are using the JSONPlaceholder user API endpoint and triggering the POST method, just for the sake of example. We can make any type of method for the request.

Properties

  • response-variable-name:
    • The response variable name provided by the policy once the request is completed successfully.
    • A custom variable name can be given, make sure to use the exact same variable across.
    • The variable can be accessed using the context.Variable collection.
    • In the example, the name of the variable is "apiResponse".
  • mode [optional]: New/Copy, either a request with new headers or a request with header copied form the current one.
  • timeout [optional]: The timeout value in seconds, timeout for send-request failure.
  • ignore-error [optional]: In case of an error, if this is set to true, the response variable will be null and the error will be ignored, default is false.

Tags

  • set-url: Sets the request URL.
  • set-method: Sets the request method.
  • set-header: Sets the header name and value. We can add any number of set-header tags.
  • set-body: Sets the payload (body) of the request. If Content-Type is application/json then we return the JObject, we can use the Policy Expression to create the body object.

Consuming Response Variable

Time to consume the response variable from and let us see how we can even control our flow if needed. For this will continue with the previous example code only:

<inbound>
  <send-request response-variable-name="apiResponse">
    <set-url>https://jsonplaceholder.typicode.com/users</set-url>
    <set-method>POST</set-method>
    <set-header name="Content-Type" exists-action="override">
      <value>application/json</value>
    </set-header>
    <set-body>@{
      string username = (string)context.Variables.GetValueOrDefault("username");
      string email = (string)context.Variables.GetValueOrDefault("email");
      return new JObject(
      new JProperty("username", username),
      new JProperty("email", email)
      ).ToString();
    }
    </set-body>
  </send-request>

  <choose>
    <!-- !200: return -->
    <when condition='@(((IResponse)context.Variables["apiResponse"]).StatusCode != 200)'>
      <return-response>
        <set-status code='@(((IResponse)context.Variables["apiResponse"]).StatusCode)' reason='@(((IResponse)context.Variables["apiResponse"]).StatusReason)' />
        <set-header name="Content-Type" exists-action="override">
          <value>application/json</value>
        </set-header>
        <set-body>@(JsonConvert.SerializeObject(((IResponse)context.Variables["apiResponse"]).Body.As<JObject>()))</set-body>
      </return-response>
    </when>

    <!-- 200: next -->
    <when condition='@((((IResponse)context.Variables["apiResponse"]).StatusCode == 200))'>
      <set-header name="CO-Id" exists-action="override">
        <value>@{ 
            var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
            var id = (string)body["id"]; 
            return id ?? ""; 
        }</value>
      </set-header>
      <set-header name="CO-Name" exists-action="override">        <value>@{ 
          var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
          var name = (string)body["name"]; 
          return name ?? "";        }</value>
      </set-header>
    </when>
  </choose>

</inbound>

Here, we have used the user request, but this time we have taken the username and email values from some context variable instead of hard coded values, to simulate more real time policies. Once the request completes, we are considering the response variable "apiResponse" and further evaluating the response. The "apiResponse" is an IResponse object and the body is of IMessage type.

We are now checking if the "apiResponse" status code is not 200 OK then we are using return-response policy to return the response from the inbound level itself, this can be seen in below code:

<!-- !200: return -->
<when condition='@(((IResponse)context.Variables["apiResponse"]).StatusCode != 200)'>
  <return-response>
    <set-status code='@(((IResponse)context.Variables["apiResponse"]).StatusCode)' reason='@(((IResponse)context.Variables["apiResponse"]).StatusReason)' />
    <set-header name="Content-Type" exists-action="override">
      <value>application/json</value>
    </set-header>
    <set-body>@(JsonConvert.SerializeObject(((IResponse)context.Variables["apiResponse"]).Body.As<JObject>()))</set-body>
  </return-response>
</when>

Here, we are setting the response as what we have obtained from the "send-request" call, also we are keeping the same body.

Additionally, when the request results in 200 OK we are adding some custom headers as "CO-Id" and "CO-Name", these headers will be received at the downstream calls, this can be seen in below code:

<!-- 200: next -->
<when condition='@((((IResponse)context.Variables["apiResponse"]).StatusCode == 200))'>
  <set-header name="CO-Id" exists-action="override">
	<value>@{ 
		var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
		var id = (string)body["id"]; 
		return id ?? ""; 
	}</value>
  </set-header>
  <set-header name="CO-Name" exists-action="override">
	<value>@{ 
	  var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
	  var name = (string)body["name"]; 
	  return name ?? "";
	}</value>
  </set-header>
</when>

Here, setting the "preserveContent" property to "true" is very important, since we are using the "Body.As" method twice. If we dont use it, then the first time when you access the apiResponse data using "Body.As" method, it will bring the values, the next time the content will not be preserved, so we must need to add set this property to true. We can also create variable to hold the values of apiResponse post getting the value from "Body.As" method, but in this example, we are not doing so. Read more about "preserveContent" from here Azure API Management policy expressions.

More Examples

Will explore some more examples for send-request policy. These are some variants where we are calling a GET method or calling Graph API to fetch user data.

<send-request mode="new" response-variable-name="userApiResponse" timeout="10" ignore-error="true">
  <set-url>https://jsonplaceholder.typicode.com/users</set-url>
  <set-method>GET</set-method>
</send-request>

Here, we are making and API call to the users API which is a get all call to JSONPlaceHolder API. We have mentioned the mode, timeout and ignore-error properties as well.

<send-request mode="new" response-variable-name="graphApiResponse" timeout="20" ignore-error="true">
  <set-url>https://graph.microsoft.com/v1.0/users</set-url>
  <set-method>GET</set-method>
</send-request>

Here, we are making and API call to the users API which is a get all call to Graph API. We have mentioned the mode, timeout and ignore-error properties as well.

Creating Policy Fragment

If we want to use the same policy across the APIM, we can simply create Policy Fragment. We can have them defined once and used at many places. Below we have created a policy named "UserPolicyFragment.xml".

<fragment>
  <send-request response-variable-name="apiResponse">
    <set-url>https://jsonplaceholder.typicode.com/users</set-url>
    <set-method>POST</set-method>
    <set-header name="Content-Type" exists-action="override">
      <value>application/json</value>
    </set-header>
    <set-body>@{
      string username = (string)context.Variables.GetValueOrDefault("username");
      string email = (string)context.Variables.GetValueOrDefault("email");
      return new JObject(
      new JProperty("username", username),
      new JProperty("email", email)
      ).ToString();
      }
    </set-body>
  </send-request>
  <choose>
    <!-- !200: return -->
    <when condition='@(((IResponse)context.Variables["apiResponse"]).StatusCode != 200)'>
      <return-response>
        <set-status code='@(((IResponse)context.Variables["apiResponse"]).StatusCode)' reason='@(((IResponse)context.Variables["apiResponse"]).StatusReason)' />
        <set-header name="Content-Type" exists-action="override">
          <value>application/json</value>
        </set-header>
        <set-body>@(JsonConvert.SerializeObject(((IResponse)context.Variables["apiResponse"]).Body.As<JObject>()))</set-body>
      </return-response>
    </when>

    <!-- 200: next -->
    <when condition='@((((IResponse)context.Variables["apiResponse"]).StatusCode == 200))'>
      <set-header name="CO-Id" exists-action="override">
        <value>@{ 
          var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
          var id = (string)body["id"]; 
          return id ?? ""; }</value>
      </set-header>
      <set-header name="CO-Name" exists-action="override">
        <value>@{ 
          var body = ((IResponse)context.Variables["apiResponse"])?.Body?.As<JObject>(preserveContent: true); 
          var name = (string)body["name"]; 
          return name ?? ""; }</value>
      </set-header>
    </when>
  </choose>
</fragment>

We can now simply add this to API endpoint or All Operations or All APIs like shown below:

<policies>
  <inbound>
    <base />
    <include-fragment fragment-id="UserPolicyFragment" />
  </inbound>
  <backend>
    <base />
  </backend>
  <outbound>
    <base />
  </outbound>
  <on-error>
    <base />
  </on-error>
</policies>

You can find the above codes from the Gist created and attached to this article.

That's all folks.


Zaki Mohammed
Zaki Mohammed
Learner, developer, coder and an exceptional omelet lover. Knows how to flip arrays or omelet or arrays of omelet.