Custom Connectors: Azure, Policies & Code
Take custom connectors further. Build connectors backed by Azure Functions, use policy templates to transform data at runtime, and write custom code to reshape API responses.
Advanced connector patterns
Think of these advanced patterns like a food processing plant.
A basic connector is like a delivery truck β it picks up raw ingredients (API data) and delivers them to the kitchen (Power Platform). But sometimes you need processing: sorting apples by size (policy templates), peeling potatoes before delivery (code transforms), or cooking a specific recipe (Azure Function).
This module covers three βprocessingβ techniques: Azure Functions as connector backends, policy templates that modify data in transit, and custom code that transforms API responses before they reach your app or flow.
Azure Function as connector backend
When an external API does not exist or needs a processing layer, build an Azure Function and wrap it in a custom connector.
The pattern
Canvas App / Flow β Custom Connector β Azure Function β External System(s)
When to use this pattern
- The logic is too complex for a direct API call (aggregation, multi-step processing)
- You need to call multiple external APIs and combine results
- The external API format does not match what Power Platform needs
- You need server-side caching or rate limiting
Creating the connector from an Azure Function
- Build the Azure Function with HTTP trigger
- Export the OpenAPI definition from the Function App (Azure portal β API Definition)
- Import the definition into Power Platform as a custom connector
- Configure authentication (Function key or OAuth via Entra ID β managed identity for connectors is in preview)
Scenario: Marcus builds a price comparison connector
Marcus needs a connector that compares shipping prices across three carriers. No single API provides this β each carrier has its own API.
Solution: An Azure Function that:
- Accepts package details (weight, dimensions, destination)
- Calls all three carrier APIs in parallel
- Compares prices and returns a sorted list
- Caches results for 5 minutes to reduce API calls
The custom connector wraps this Function with a single action: CompareShippingPrices. Makers see one clean action instead of three separate API calls.
Policy templates
Policy templates modify connector behavior at runtime WITHOUT changing the OpenAPI definition or writing code. They intercept requests and responses.
| Policy | What It Does | Example Use |
|---|---|---|
| SetHeader | Add or modify HTTP headers | Add X-API-Version: 2.0 to every request |
| SetQueryParameter | Add query parameters | Append format=json to all requests |
| SetProperty | Modify request/response body properties | Rename a field from cust_name to customerName |
| Convert | Transform data types | Convert Unix timestamp to ISO 8601 date |
| RouteRequest | Redirect requests to a different URL | Route test traffic to a staging API |
Policy template example
To add a required header to every API call:
<set-header name="X-API-Version" existsAction="override">
<value>2.0</value>
</set-header>
To convert a response field:
<set-body>
@{
var response = context.Response.Body.As<JObject>();
response["createdDate"] = DateTimeOffset.FromUnixTimeSeconds(
(long)response["created_timestamp"]
).ToString("o");
return response.ToString();
}
</set-body>
Custom code transforms
For complex transformations that policy templates cannot handle, you can write C# code directly in the connector definition.
When to use code vs policies
| Scenario | Use Policy Templates | Use Custom Code |
|---|---|---|
| Add a header | Yes | Overkill |
| Rename a field | Yes (SetProperty) | Overkill |
| Convert date format | Yes (Convert) | Overkill |
| Flatten nested JSON | No | Yes |
| Filter array elements | No | Yes |
| Aggregate multiple values | No | Yes |
| Complex conditional logic | No | Yes |
Code transform example
public class Script : ScriptBase
{
public override async Task<HttpResponseMessage> ExecuteAsync()
{
// Read the original response
var response = await this.Context.SendAsync(
this.Context.Request, this.CancellationToken);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var data = JObject.Parse(content);
// Transform: flatten nested address object
var address = data["address"] as JObject;
if (address != null)
{
data["street"] = address["line1"];
data["city"] = address["city"];
data["postcode"] = address["postalCode"];
data.Remove("address");
}
response.Content = CreateJsonContent(data.ToString());
}
return response;
}
}
Extending the OpenAPI definition
After importing an initial definition, you often need to extend it:
- Add x-ms-summary β friendly display names for actions and parameters
- Add x-ms-visibility β control which fields show by default (
important,advanced,internal) - Add x-ms-trigger β mark an operation as a Power Automate trigger
- Add x-ms-dynamic-values β populate dropdowns dynamically from another API call
- Modify response schemas β match the actual API response (imports are not always perfect)
An external API returns dates as Unix timestamps (e.g., 1714521600). Power Automate users need to see these as human-readable dates. What is the simplest approach?
π¬ Video coming soon
Next up: Dataverse APIs: Web API & Organisation Service β performing operations with OData, bulk requests, and OAuth authentication.