---
source_url: https://itmustbecode.com/how-to-call-a-dataverse-custom-api-from-a-canvas-app/
title: How to Call a Dataverse Custom API from a Canvas App
date: 2022-10-31T04:01:32+00:00
categories:
  - blog
tags:
  - canvas-apps
  - custom-api
  - custom-page
  - dataverse
  - power-automate
word_count: 1669
reading_time_minutes: 8
type: posts
---

Dataverse Custom APIs are a powerful extension model of the PowerPlatform. However, at the time of writing, there are no direct method to execute a Custom API inside the PowerApps Canvas App model.

In this post I will show how to call any Custom API from a Canvas App with the use of a generic **Power Automate** Flow and the new **ParseJSON** functionality.

{{< figure src="./image-25.png" alt="" caption="" >}}

> **UPDATE 17-FEB-2023**
>
> Dataverse Custom APIs can now be called **directly** from PowerFx in Canvas Apps and Custom Pages. ( _still in experimental phase_)
>
> [Call Dataverse actions directly in Power Fx \| Microsoft Power Apps](https://powerapps.microsoft.com/en-us/blog/call-dataverse-actions-directly-in-power-fx-experimental-preview/?WT.mc_id=DX-MVP-5004959)

## **Custom APIs in context**

First off, I have to admit that I am die-hard fan of Dataverse Custom APIs since their introduction. The main reason is that it gives developers a way to use the **same endpoint** that the platform uses for the core functionalities (CRUD on the data tables etc..) and extend it with **tailor-made** messages that encapsulates server-side business logic over REST API requests.

As a result, the Custom APIs are agnostic to the caller and the same logic can be consumed from different sources like Dataverse plugins, Power Automate flows, model driven forms javascript, PCF controls, external programs etc...

Sadly, one of the blind spot is the **direct** use of Custom APIs within a Canvas Apps (or from the new Custom Pages) model. Let's see how we can overcome this limitation in an indirect manner.

Learn more about Dataverse Custom APIs here:
👉[Create and use Custom APIs (Microsoft Dataverse) - Power Apps | Microsoft Learn](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/custom-api)

Don't forget to use my Custom API Manager tool for XrmToolBox for great authoring experience :
  👉Dataverse Custom API Manager  · XrmToolBox
## **Prerequisites**

Follow these steps to setup the stage.

### Enable ParseJson

The technique that I will show uses the Canvas Apps **ParseJSON** function that is still in preview, so the **activation** of the feature in the settings of the canvas app (or custom page) is required.

{{< figure src="./image-17.png" alt="" caption="" >}}


see the official documentation on the feature here
👉[ParseJSON function in Power Apps (experimental) - Power Platform | Microsoft Learn](https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-parsejson)


### Install the PowerApps.Action.Runner solution (optional)

You can follow along and create your own Power Automate flows. But I have created a solution that contains the 2 Power Automate Flows shown later on.

- PowerApps:BoundActionRunner
- PowerApps:UnboundActionRunner


Here's the link to the github repo for download :
👉[drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps (github.com)](https://github.com/drivardxrm/PowerApps.Action.Runner)


### Surface the Flows in the Canvas Apps

Once the Power Automate Flows are installed, they need to be added to the Canvas App being edited by enabling them in the PowerAutomate pane of the Canvas App editor.

{{< figure src="./image-24.png" alt="" caption="" >}}


More on using PowerAutomate flows in a Canvas Apps
👉[Use Power Automate pane - Power Apps | Microsoft Learn](https://learn.microsoft.com/en-us/power-apps/maker/canvas-apps/working-with-flows?WT.mc_id=DX-MVP-5004959)


### Have some Custom APIs at hand

You can use any Custom API from your environment, but for the purpose of the demo, I will showcase 2 Custom APIs that can be found in my generic Dataverse Custom API collection.


Here's the link to the github repo for download :
👉[drivardxrm/Dataverse-CustomApis: Collection of Dataverse Custom Apis (github.com)](https://github.com/drivardxrm/Dataverse-CustomApis)


For the **Unbound** Custom API example, I will use **driv\_GetTableInfo**. This API takes for input a Dataverse table name (LogicalName) and return a collection of valuable information (metadata) on the table.

{{< figure src="./image-44.png" alt="" caption="" >}}

For the **Bound** Custom API example, I will show a Custom API bound to the systemuser table **driv\_GetUserTimezone**. This API retrieves the Timezone of a given user from the user personal settings. It can be useful for datetime calculations.

{{< figure src="./image-45.png" alt="" caption="" >}}

## **Calling an unbound Custom API**

Let's start by presenting a Power Automate flow that can be used to call any unbound Custom APIs, **PowerApps:UnboundActionRunner**.

In fact the flow is quite simple and is merely a wrapper around the Custom API call. It consists of 3 parts, the **trigger**, the **action** and the **response**.

{{< figure src="./image-26.png" alt="" caption="" >}}

### The Trigger

The flow is of type **Instant/PowerApps** and this type of trigger is what enables the PowerAutomate flow to be surfaced in the Canvas Apps editor as we seen before.

{{< figure src="./image-27.png" alt="" caption="" >}}

The configuration of the trigger defines 2 input parameters that will be supplied by the calling Canvas App

- **ActionName** : this expects the unique name of the Custom API
- **InputJson** : this expects a string in JSON format that contains the request parameters (inputs) one wishes to pass to the Custom API.

{{< figure src="./image-28.png" alt="" caption="" >}}

### The Action

The action uses the **Perform an unbound action** that is part of the Power Automate Dataverse connector.

{{< figure src="./image-29.png" alt="" caption="" >}}

The Action Name selector exposes a list of all existing Custom API (and legacy Custom Actions) available in the environment, but in our case we'll just select **Enter custom value** and affect the **ActionName** value defined earlier in the trigger.

{{< figure src="./image-30.png" alt="" caption="" >}}

{{< figure src="./image-31.png" alt="" caption="" >}}

Now, since the **ActionName** is dynamic and will only be resolved at runtime, the Power Automate engine cannot determine the individual input parameters so it shows an input field called **Action Parameters** that expects a JSON construct representing the input parameters of the API.

{{< figure src="./image-32.png" alt="" caption="" >}}

For example to call the **GetTableInfo** API on the **account** Table, the Action Parameters would look something like this

```
{
  'LogicalName' : 'account'
}
```

The idea here is to set the **Action parameters** field with the **InputJson** received from the trigger. However, it's really important here to convert the InputJson text value using the **json()** function otherwise an error will be thrown at runtime.

{{< figure src="./image-35.png" alt="" caption="" >}}

{{< figure src="./image-34.png" alt="" caption="" >}}

### The Response

To pass the Custom API results back to the calling Canvas Apps, the flow makes use of the **Respond to PowerAppp or flow** action. Here, Simply set the value of **OutputJson** property to the **response** of the Custom API call made earlier.

```
outputs('Perform_an_unbound_action')?['body']
```

{{< figure src="./image-40.png" alt="" caption="" >}}

### Calling the flow from a Canvas App

Now to the main event, let's connect the dots and use the Flow inside a Canvas App (or Custom Page) to execute a Custom API.

The app shown takes a table name as input and at the click of the button, the **PowerApps:UnboundActionRunner** is used to execute the **GetTableInfo** Custom Api and output some metadata information on the form.

{{< figure src="./image-47.png" alt="" caption="" >}}

The **OnSelect** action of the button is used to set the value of the variable **TableInfoResults**. The value is the **OutputJson** resulting from the execution of PowerApps:UnboundActionRunner where the **ActionName**and **InputJson** of the Custom API are supplied. So on every click to the button the flow is executed, the Custom API is called and the expression is re-evaluated based on the value of the textbox.

```
Set(TableInfoResults,
    'PowerApps:UnboundActionRunner'.Run(
       "driv_GetTableInfo",
       "{'LogicalName' : '" & txtInputTable.Value & "'}"
    ).outputjson)
```

{{< figure src="./image-20.png" alt="" caption="" >}}

The new **ParseJSON()** function is applied on the TableInfoResults variable to display the API results on the form. This will deserialize de output of the API response and **expose** its properties. Here, it's important to **cast** the desired property to its correct object type (string = Text, number = Value etc..). (See the [ParseJSON official docs](https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-parsejson?WT.mc_id=DX-MVP-5004959))

{{< figure src="./image-21.png" alt="" caption="" >}}

{{< figure src="./image-22.png" alt="" caption="" >}}

As you can see below, the Custom API is being executed on each click of the button and the results are parsed and displayed on the form.

{{< figure src="./canvas_actionrunner3.gif" alt="" caption="" >}}

## **Calling a bound Custom API**

To call a bound Custom API we will use the **PowerApps:BoundActionRunner** from my solution. The idea is the same as the unbound api version so I will not repeat everything.

The main differences are at the **trigger** level as more input parameters are expected.

- **TableCollectionName**: Collection Name of the Table (normaly the plural name)
- **RecordId**: uniqueidentifier (GUID) of the bound record
- **ActionName** : this expects the unique name of the Custom API
- **InputJson** : this expects a string in JSON format that contains the request parameters (inputs) one wishes to pass to the Custom API.

There's also a minor difference in the way that the Action Name needs to be set on the Perform bound action step ( **Microsoft.Dynamics.CRM.{ActionName}**).

{{< figure src="./image-23.png" alt="" caption="" >}}

### Calling the flow from a Canvas App

For this demo, the button click will call the **GetTimezoneInfo** Custom API using the current user as the bound record.

{{< figure src="./image-49.png" alt="" caption="" >}}

Again, a variable is set (UserTimezoneResults) with the OutputJson received from the **PowerApps:BoundActionRunner** flow. The

```
Set(UserTimezoneResults,
   ('PowerApps:BoundActionRunner'.Run(
      "systemusers",
      First(Filter(Users,'PrimaryEmail'=User().Email)).User,
      "driv_GetUserTimezone",
      "")
  .outputjson))
```

{{< figure src="./image-48.png" alt="" caption="" >}}

The same principle as earlier is applied to Parse the response of the flow and display the results on the form.

{{< figure src="./image-50.png" alt="" caption="" >}}

{{< figure src="./image-52.png" alt="" caption="" >}}

As you can appreciate, whenever the button is clicked the Custom API will be executed accordingly.

{{< figure src="./canvas_actionrunner4.gif" alt="" caption="" >}}

### **Takeaway**

As cool as this is, I have to admit that I hope that this solution will have a short lifespan. It would be great if Custom APIs could be surfaced and executed **directly** inside Canvas Apps and Custom Pages.

In my opinion, the fact that we have to delegate the Custom API call to a PowerAutomate wrapper adds an unnecessary layer of complexity that can affect performance and maintainability.

Also, an important point to consider is the concurency on the flow and the API call limit. Since the flows are using a common connection to the Dataverse environment, this means that the same connection will be used for each execution. So if you have several apps used by hundreds of users all using the same flows and connections, you might run into problems down the road.

But hey, on the bright side of things let's celebrate that with this solution Custom APIs can be unleashed in the realm of Canvas Apps. I see a lot of use cases for this.

### **Links**
{{< linkcard url="https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-parsejson?WT.mc_id=DX-MVP-5004959" title="ParseJSON function in Power Apps (experimental) - Power Platform" summary="Reference information including syntax and examples for the ParseJSON function in Power Apps." image="/linkcards/f69ad1e3eed32c06.png" domain="learn.microsoft.com" new_tab="true" nofollow="true" >}}

{{< linkcard url="https://www.xrmtoolbox.com/plugins/XTB.CustomApiManager/" title="Dataverse Custom API Manager · XrmToolBox" summary="Management tool that provides 360° View of Dataverse Custom APIs. Provides CRUD operations on Custom API, Request Parameters (Inputs) and Response Properties (Outputs)." image="/linkcards/7963c972123cfedd.png" domain="www.xrmtoolbox.com" new_tab="true" nofollow="true" >}}


{{< linkcard url="https://github.com/drivardxrm/Dataverse-CustomApis" title="GitHub - drivardxrm/Dataverse-CustomApis: Collection of Dataverse Custom Apis" summary="Collection of Dataverse Custom Apis. Contribute to drivardxrm/Dataverse-CustomApis development by creating an account on GitHub." image="/linkcards/e9ffe6985986dfe4.png" domain="github.com" new_tab="true" nofollow="true" >}}


{{< linkcard url="https://github.com/drivardxrm/PowerApps.Action.Runner" title="GitHub - drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps" summary="Generic Power Automate Flows to run Dataverse Custom APIs an Actions in Canvas Apps - GitHub - drivardxrm/PowerApps.Action.Runner: Generic Power Automate Flows to run Dataverse Custom APIs an Actio..." image="/linkcards/4a9af6fbcf349db3.png" domain="github.com" new_tab="true" nofollow="true" >}}

Photo by [Pavan Trikutam](https://unsplash.com/es/@ptrikutam?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/call?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

