Service endpoints support querying data from external services through REST API. The data queried can be used to populate task input dropdowns.
Endpoint type can define datasources which are essentially external service’s REST API references.
For e.g. Azure RM endpoint type defines the following data source :
"dataSources": [
{
"name": "AzureRMWebAppSlotsId",
"endpointUrl": "https://management.azure.com/subscriptions/$(endpoint.subscriptionId)/resourceGroups/$(ResourceGroupName)/providers/Microsoft.Web/sites/$(WebAppName)/slots?api-version=2015-08-01",
"resultSelector": "jsonpath:$.value[*].id"
}
]
URL for the data source can include endpoint.* variables. These correspond to the inputs in the endpoint data. For e.g. subscriptionId is an additional input defined in the Azure RM endpoint type :
"inputDescriptors": [
{
"id": "subscriptionId",
"name": "i18n:Subscription Id",
"description": "i18n:Subscription Id from the <a href=\"https://go.microsoft.com/fwlink/?LinkID=312990\" target=\"_blank\">publish settings file</a>",
"inputMode": "textbox",
"isConfidential": false,
"validation": {
"isRequired": true,
"dataType": "guid",
"maxLength": 38
}
}
]
In addition to the endpoint inputs, endpoint.Url is also available as a variable.
URL can also include variables that correspond to other task inputs. Variable value resolves to the value of the corresponding task input. For e.g. ResourceGroupName is an input defined in the AzureRMWebAppDeployment task:
{
"name": "ResourceGroupName",
"type": "pickList",
"label": "Resource Group",
"defaultValue": "",
"required": true,
"properties": {
"EditableOptions": "True"
},
"helpMarkDown": "Enter or Select the Azure Resource Group that contains the AzureRM Web App specified above.",
"visibleRule": "DeployToSlotFlag = true"
}
In addition to defining the URL for the data source, a resultSelector can also be defined. The result selector tells the system how to extract the required data from the API response.
The resultSelector value must start with one of the following prefixes :
| Prefix | Description |
|---|---|
jsonpath: |
Used to extract data from JSON responses |
xpath: |
Used to extract data from XML responses |
none |
Returns no data |
plaintext |
Returns the full response as plain text |
Use jsonpath: when the API response is in JSON format.
Common syntax :
| Pattern | Description | Example |
|---|---|---|
$ |
Root object | jsonpath:$ |
.property |
Access a property | jsonpath:$.value |
..property |
Search recursively | jsonpath:$..name |
[*] |
All items in an array | jsonpath:$.value[*].id |
[n] |
Specific item in array | jsonpath:$.value[0] |
[n,m] |
Multiple items | jsonpath:$.value[0,1] |
[start:end] |
Range of items | jsonpath:$.value[0:3] |
[?()] |
Filter condition | jsonpath:$.value[?(@.properties.isEnabled == true)] |
Examples :
Gets all id values from the array :
"resultSelector": "jsonpath:$.value[*].id"
Gets all name fields from anywhere in the response :
"resultSelector": "jsonpath:$..name"
Gets only items where isEnabled is true :
"resultSelector": "jsonpath:$.value[?(@.properties.isEnabled == true)]"
Returns the full JSON response :
"resultSelector": "jsonpath:$"
Notes :
- Keep JSONPath expressions simple and easy to understand.
- If something doesn't work, check the API response structure.
- Some advanced JSONPath features may not be supported.
Common limitation :
Sometimes the API response uses property names as keys rather than returning an array. For e.g. the Variable Groups API returns variables in this format :
{
"variables": {
"MyVar1": { "value": "hello" },
"MyVar2": { "value": "world" }
}
}
In this case :
- You cannot directly extract the keys like
MyVar1,MyVar2usingresultSelector. - You can only extract the property values.
- Enter values manually, or use
resultTemplateto format the output.
Use xpath: when the API response is in XML format. Standard XPath syntax is supported.
Examples :
Selects all Name elements under Site :
"resultSelector": "xpath://Site/Name"
Selects multiple element types :
"resultSelector": "xpath://Blobs/Blob | //Blobs/BlobPrefix"
Notes :
- Standard XPath syntax is supported.
- You usually don't need to worry about XML namespaces — they are automatically handled.
none :
"resultSelector": "none"
Use when you don't need any data from the response (e.g., for write-only REST calls).
plaintext :
"resultSelector": "plaintext"
Returns the full response as plain text.
The API response should be less than 2 MB. If it is too large, the request will fail. Use filtering or pagination in your API calls to reduce the response size.
In order to refer to data sources defined by endpoint type in tasks, data source bindings are used. For e.g. AzureRmWebAppDeployment task defines data source binding referring to the above data source :
"dataSourceBindings": [
{
"target": "SlotName",
"endpointId": "$(ConnectedServiceName)",
"dataSourceName": "AzureRMWebAppSlotsId",
"parameters": {
"WebAppName": "$(WebAppName)",
"ResourceGroupName": "$(ResourceGroupName)"
},
"resultTemplate": "{\"Value\":\"{{{ #extractResource slots}}}\",\"DisplayValue\":\"{{{ #extractResource slots}}}\"}"
}
]
A dataSourceBinding has the following fields :
target indicates the task input that this data source binding will bind to. For e.g. AzureRmWebAppDeployment task takes the following task input that corresponds to the slot name drop down :
"inputs": [
{
"name": "SlotName",
"type": "pickList",
"label": "Slot",
"defaultValue": "",
"required": true,
"properties": {
"EditableOptions": "True"
},
"helpMarkDown": "Enter or Select an existing Slot other than the Production slot.",
"visibleRule": "DeployToSlotFlag = true"
}
]
endpointId contains the service endpoint ID to be used in the data source binding. It typically corresponds to the service endpoint task input defined in the task. For e.g. this is the input that corresponds to the service endpoint in case of AzureRmWebAppDeployment task :
"inputs": [
{
"name": "ConnectedServiceName",
"type": "connectedService:AzureRM",
"label": "AzureRM Subscription",
"defaultValue": "",
"required": true,
"helpMarkDown": "Select the Azure Resource Manager subscription for the deployment."
}
]
** Here the task defines endpoint input of type AzureRM.
If endpoint type supports multiple authentication schemes, we can even scope down the endpoint selection to specific authentication schemes. For e.g. this is the input that corresponds to the service endpoint in case of AzureRmWebAppDeployment task:
"inputs": [
{
"name": "ConnectedServiceName",
"type": "connectedService:Azure:Certificate,UsernamePassword",
"label": "Azure Subscription (Classic)",
"defaultValue": "",
"required": true,
"helpMarkDown": "Azure Classic subscription to target for deployment."
}
]
dataSourceName in the data source binding corresponds to the data source in the endpoint type. In case the endpoint type does not define data source that the task is interested in, then there is provision to define the details of data source inline as part of the data source binding.
Here is how the data source corresponding to AzureRMWebAppSlotsId looks like:
"dataSources": [
{
"name": "AzureRMWebAppSlotsId",
"endpointUrl": "https://management.azure.com/subscriptions/$(endpoint.subscriptionId)/resourceGroups/$(ResourceGroupName)/providers/Microsoft.Web/sites/$(WebAppName)/slots?api-version=2015-08-01",
"resultSelector": "jsonpath:$.value[*].id"
}
]
parameters represent the key/value pairs used when resolving the data source URL. In addition to endpoint.* variables, there could be variables used in the URL that correspond to the other task inputs. The name/value for these variables are provided by the parameters field in the data source binding.
For e.g. WebAppName & ResourceGroupName parameters correspond to the task inputs for AzureRmWebAppDeployment task:
"inputs": [
{
"name": "WebAppName",
"type": "pickList",
"label": "Web App Name",
"defaultValue": "",
"required": true,
"properties": {
"EditableOptions": "True"
},
"helpMarkDown": "Enter or Select the name of an existing AzureRM Web Application."
},
{
"name": "ResourceGroupName",
"type": "pickList",
"label": "Resource Group",
"defaultValue": "",
"required": true,
"properties": {
"EditableOptions": "True"
},
"helpMarkDown": "Enter or Select the Azure Resource Group that contains the AzureRM Web App specified above.",
"visibleRule": "DeployToSlotFlag = true"
}
]
resultTemplate defines a template that represents how the data has to be transformed before returning back. The template essentially is a Mustache template & can include Mustache handlers natively supported.
Here’s sample response from AzureRMWebAppSlotsId data source:
{
"value": [
{
"id": "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/webapprgpt/providers/Microsoft.Web/sites/nodewebapp123/slots/Slot1",
"name": "nodewebapp123/Slot1",
"type": "Microsoft.Web/sites/slots",
"location": "South Central US",
"tags": null,
"properties": {}
},
{
"id": "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/webapprgpt/providers/Microsoft.Web/sites/nodewebapp123/slots/Slot2",
"name": "nodewebapp123/Slot2",
"type": "Microsoft.Web/sites/slots",
"location": "South Central US",
"tags": null,
"properties": {}
}
],
"nextLink": null,
"id": null
}
Here’s the result after applying the data source binding corresponding to SlotName :
{
"count": 2,
"value": [
"{\"Value\":\"Slot1\",\"DisplayValue\":\"Slot1\"}",
"{\"Value\":\"Slot2\",\"DisplayValue\":\"Slot2\"}"
]
}
Note: In case your response is an arrary of strings like ['value1','value2'] you can use template like "{ Value : "{{defaultResultKey}}", DisplayValue : "{{defaultResultKey}}" }".defaultResultKey will take on values value1, value2 e.t.c
To avoid creating or updating a service endpoint with incorrect values for the inputs, we support a “Test” action in service endpoint UI. Upon choosing to “Test” an endpoint, we internally invoke query on a data source with a specific name – TestConnection. For e.g. Azure RM endpoint type defines the following TestConnection data source:
"dataSources": [
{
"name": "TestConnection",
"endpointUrl": "https://management.azure.com/subscriptions/$(endpoint.subscriptionId)/providers/Microsoft.Web/sites?api-version=2015-08-01",
"resultSelector": "jsonpath:$.value[*].name"
}
]
If this data source isn’t present in the endpoint type, then testing the connection isn’t supported.
resultSelector in TestConnection is optional and is not used to determine if the test succeeded or failed. When testing the connection using this datasource, we only check for the HTTP status code of the underlying REST API call. If HTTP status.code == OK then the test will succeed.
Datasources are defined within service endpoint type contribution. DataSourceBindings that refer to dataSources are defined in various tasks for e.g. In case a task needs to call into a REST API that is supported by the endpoint type but there is no dataSource defined for that REST API in the endpoint type contribution, then it is possible to define the URL to invoke inline within the dataSourceBinding.
For e.g. below is a dataSourceBinding for querying alert rules defined in Microsoft.Insights resource provider in Azure.
"dataSourceBindings": [
{
"target": "alertRules",
"endpointId": "$(connectedServiceNameARM)",
"endpointUrl": "{{{endpoint.url}}}subscriptions/{{{endpoint.subscriptionId}}}/resourcegroups/$(ResourceGroupName)/providers/microsoft.insights/alertrules?api-version=2016-03-01&$filter=targetResourceUri eq /subscriptions/{{{endpoint.subscriptionId}}}/resourceGroups/$(ResourceGroupName)/providers/$(ResourceType)/$(resourceName)",
"resultSelector": "jsonpath:$.value[?(@.properties.isEnabled == true)]",
"resultTemplate": "{ \"Value\" : \"{{{name}}}\", \"DisplayValue\":\"{{{name}}}\"}"
}
]