Skip to content

Dataverse Custom API: Function (GET) vs Action (POST)

The new Dataverse Custom API feature (now in General Availability ๐Ÿš€) empowers developers with the ability to create their own custom messages to extends the capabilities of the Power Platform. These custom messages are then exposed by the Dataverse endpoints (WebApi and Organizationservice) like other out-of-the-box messages (Create, Update, etc..).

While the Custom API model shares a lot of similarities with the traditional Custom Action model that is available since Dynamics 2013, it also exposes a bunch of unique features that are worth taking a look at.

So to continue on my series of posts on Dataverse Custom API’s unique features, this one will explore the IsFunction flag that can be found on the Custom API Table. We will try to understand how this attribute affects the way end-users interact with Custom APIs.

Please, refer to Microsoft’s official documentation for the most up-to-date information.

Setting the IsFunction Attribute

When you create a new Dataverse Custom API record, you will notice that you are asked to set a boolean (yes/no) attribute called IsFunction. Setting this attribute will have a deep impact on how your custom message will be exposed and consumed so it’s very important to understand the intricacies associated with this choice.

The example below shows how to set the attribute using the Custom API Manager for XrmToolBox. Be careful, setting this attribute is only available at the creation and you cannot change it afterward.

Setting IsFunction Flag in Custom API Manager

As to WHY someone would set a Custom API as a function or not is really a philosophical choice (and a practical one as we will see later), the purpose and internals of your API stay more or less the same whether you set IsFunction to true or false :

  1. You have a collection of inputs (request parameters)
  2. You execute some code (the plugin bound to your Custom API record)
  3. You return a collection of outputs (response properties)
Simplistic representation of an API

To further illustrate some of the concepts, we will compare 2 unbound custom APIs that expose exactly the same functionality which is to retrieve an environment variable value given an input parameter called ‘Key‘. The only difference will be the IsFunction flag.

  • driv_GetEnvironmentVariable_FUNCTION
    • IsFunction = true โœ”๏ธ -> Function
  • driv_GetEnviromentVariable
    • IsFunction = false โŒ -> Action

๐Ÿ‘‰You can download and install an implementation of the GetEnviromentVariable in my collection of Dataverse Custom API available here

Function (GET) or Action (POST)

The fundamental difference of setting your API to be a function or an action is found in the way your message will be exposed and consumed using the Dataverse REST endpoint (Web API).

If IsFunction = true โœ”๏ธ, your message will be exposed using the GET HTTP verb, meaning that any inputs (request parameters) will need to be sent directly in the URL.

Example of a function API (GET) call

Whereas, if IsFunction = false โŒ, your message will be exposed using the POST HTTP verb. In that case, the inputs (request parameters) will be sent as a JSON payload in the body of the request.

Example of an Action API (POST) call

Notice that the outputs of the 2 calls are identical. You will receive a collection of response properties in JSON format, so no difference on that end.

The difference between GET and POST can look trivial for this simple example having only one input parameter of type string, but when you have several inputs with different types (ex. dates, entity references etc…) I find that the GET notation can become a bit messy. For me the JSON Body notation of the POST is much easier to understand.

OK! So why choose one over the other?

That is to say, if you are a ‘purist‘ and you want to RESpecT the REST conventions, if your API doesn’t make any change to the Database(verse) your message might be better expressed as a function (GET), and if your message implies any mutation to the data you might want to consider an action (POST).

But like I said earlier it’s a philosophical choice and I will show you why I think that at this point in time, it’s much better to always define your Custom API as actions (POST) and leave the IsFunction attribute to false.

Calling Functions and Actions in Power Automate

I think that Power Automate is a place where the Custom API model shines the most. It can provide flow makers with robust (hopefully tested ๐Ÿ˜) and easy-to-use functions that encapsulate complex business logic.

One major plus ๐ŸŒŸ for actions APIs (POST), is that they can be called in Power Automate using the โ€˜Perform Actionโ€™ step of the Common Data service (current environment) connector. Unfortunately (at the time of writing) Functions APIs (GET) are not surfaced using this connector.

Common Data Service – Perform Action Step

Using the Perform Action step, any Actions APIs (POST) existing in your environment will be surfaced in the Action Name dropdown. Upon selection, input parameters will be dynamically listed and available for edition.

Selecting a Custom API and setting the Request Parameters

Also, all individual outputs of your API will be directly and easily accessible in the Dynamic content tab for subsequent use. The connector automatically parses the JSON output for you, ain’t that amazing๐Ÿ‘.

Perform Action – Execution outputs
Perform action – outputs available in dynamic content

So, for that reason alone, I tend to set the IsFunction flag to ‘false‘ on my Custom APIs just so they can be used easily and without a fuss in Power Automate.

If you really want to call a function API in Power Automate (or if you want to use one of the many out-of-the-box functions ๐Ÿ‘‰ see the list here), you can always use the HTTP with Azure AD connector and send the same kind of request seen earlier in the PostMan example for the function API (GET). The API code will be executed and the results (response properties) in JSON will be available in the Body section of the Outputs.

HTTP with Azure AD step
Calling a function with HTTP for Azure AD – Input
Calling a function with HTTP for Azure AD – Output

Although, this approach is far less portable and more complicated to use to than using the Perform Action step. Here is why :

  • If you want to install your Flow in different environments, You will need to provide the base URL dynamically (by using an environment variable for example) or change it manually on each environment (who wants to do that? ๐Ÿคทโ€โ™‚๏ธ )
  • You need to know the name and input parameters of your message, no help from the platform here to surface the available messages and parameters. (Not very Citizen Developer friendly)
  • Outputs will not be directly available in the dynamics content panel, you will have to parse the JSON output if you want to access the values directly.
  • Should I say more… I think you get the idea.

Calling Functions and Actions from Plugins

Interestingly there are no difference in the code that would be needed to call a function (GET) or an action (POST) Custom API inside another plugin (or any C# program) using Microsoft.Xrm.Sdk objects from Microsoft.CrmSdk.CoreAssemblies Nuget package.

In this case, we are closer to the metal, and using the good’ol Organizationservice endpoint. The 2 APIs can be called exactly the same way using the generic OrganizationRequest object. The inputs will be set in the ‘Parameters‘ collection and any outputs can be retrieved in the ‘Results‘ collection of the OrganizationResponse object received from the execution of the request.

Calling a Custom API function (GET) from a plugin
Calling a Custom API action (POST) from a plugin

So if you design a Custom API and you know for a fact that it will only be called in that manner, there is no harm defining it as a function (GET), but why limit yourself? I would still prefer to use a POST API just in case.

Conclusion

So to wrap this up, it’s important to understand the effects of the IsFunction attribute on Dataverse Custom APIs, mainly affecting how APIs are called on the wire (WebApi REST endpoint) with GET or POST HTTP Verbs.

Also in a Power Automate context, the Perform Action step of the Common Data Service (current environment) connector is a fantastic vehicle for calling POST Custom APIs. Providing API discoverability as well as a wrapper around the inputs and outputs of custom messages.

Happy API‘ing!

Links

Published inBlog

One Comment

  1. Thanks David for this awesome and very informative blog post.

Leave a Reply

Your email address will not be published. Required fields are marked *