Dataverse Custom API – Global and Entity (Binding Type) example


We can define the Custom API’s binding type as Global, Entity, or Entity Collection. In this post, we can see how a Global and Entity binding type Custom API can be defined, write a corresponding plugin, and then invoke/test through Postman.

We can create Custom API through Plugin Registration Tool, Power Apps, Code, Solution files, and or can use XrmToolBox Plugin – Custom API Manager.

Below we have defined a Custom API name custom_GlobalAPI, with binding type as Global and one Request (input) parameter and Response (output) Property of type string.

Below is how we define the plugin type for it and can access the input and output parameters through context.

To test it we can use the XrmToolBox Custom API Tester plugin as shown below

And from Postman, once we have the access token, we can call the Custom API as shown below.

Now for a Bound Custom API, we have the following definition. It is bound to the Contact table and has one input parameter and one output parameter similar to our Global Custom API.

Below is how we define the plugin type for it, and can access the input and output parameters similar to Global Custom API.

However, in the case of binding type Entity, we will have the Request parameter named Target of type Entity Reference for the bound entity added automatically.

We can test it using the Custom API Tester plugin, however as it is bound type, we need to select/specify the contact record (the table it is bound to), before we can execute it.

To call it from Postman, we need to use the fully qualified name i.e. Microsoft.Dynamics.CRM.[unique name of the Custom API] unlike Global one.

 public class APIPluginGlobal : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService orgService = factory.CreateOrganizationService(context.UserId);

            try
            {
                tracingService.Trace("start plugin execution: {0}", this.GetType().FullName);

                // check for the message name i.e. Unique Name of the Custom API
                if (context.MessageName.Equals("custom_GlobalAPI", StringComparison.OrdinalIgnoreCase))
                {
                    // check for the request parameter in the inputparamters of the context 
                    if (context.InputParameters.Contains("inputParam"))
                    {
                        // get the value of the input parameter
                        string inputValue = context.InputParameters["inputParam"].ToString();
                        // set the value of response property through outputparameters 
                        context.OutputParameters["outputParam"] = "Got following value as Input : " + inputValue;
                    }
                }

                tracingService.Trace("end plugin execution: {0}", this.GetType().FullName);
            }
            catch (System.ServiceModel.FaultException<OrganizationServiceFault> ex)
            {
                tracingService.Trace(ex.Detail.Message);
                throw;
            }
            catch (Exception ex)
            {
                tracingService.Trace(ex.ToString());
                throw;
            }
        }
    }
public class APIPluginBound : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService orgService = factory.CreateOrganizationService(context.UserId);

            try
            {
                tracingService.Trace("start plugin execution: {0}", this.GetType().FullName);

                // unique name of the custom api
                if (context.MessageName.Equals("custom_BoundAPI", StringComparison.OrdinalIgnoreCase))
                {
                    // Target property of type Entity Reference
                    if (context.InputParameters.Contains("Target") &&
                        context.InputParameters["Target"] is EntityReference)
                    {
                        var contact = (EntityReference)context.InputParameters["Target"];
                        // access the input request parameter
                        if (context.InputParameters.Contains("inputParam"))
                        {
                            string inputValue = context.InputParameters["inputParam"].ToString();
                            // set the output parameter value
                            context.OutputParameters["outputParam"] = "Got following as Input Parameter : " + inputValue
                                + " for record : " + contact.Id.ToString();
                        }
                    }
                }

                tracingService.Trace("end plugin execution: {0}", this.GetType().FullName);
            }
            catch (System.ServiceModel.FaultException<OrganizationServiceFault> ex)
            {
                tracingService.Trace(ex.Detail.Message);
                throw;
            }
            catch (Exception ex)
            {
                tracingService.Trace(ex.ToString());
                throw;
            }
        }
    }

Hope it helps..

Advertisements

Dataverse Custom API – Key Articles / Tool


Thanks to David Rivard for the wonderful articles and XrmToolBox Plugin Custom API Manager on Custom API

Custom API Test (XrmToolBox plugin) by Jonas Rapp

https://www.xrmtoolbox.com/plugins/Rappen.XrmToolBox.CustomAPITester/

Also check the other interesting articles on Custom API –

https://xrmdynamicscrm.wordpress.com/tag/dynamics-crm-custom-api/

https://www.pragmatic-development.io/blog/implement-business-logic-with-dataverse-custom-api/

Advertisements

How to – Create a custom API of type function in Dynamics 365 / Microsoft Dataverse


Continuing our previous posts,

Create Custom API Message
https://nishantrana.me/2021/01/13/use-custom-api-to-create-custom-messages-in-dynamics-365/

Allowed Custom Processing Step Type Property –

https://nishantrana.me/2021/01/20/allowed-custom-processing-step-type-allowedcustomprocessingsteptype-property-of-custom-api-in-dynamics-365-microsoft-dataverse/

Here we will create a custom API of type function by setting Is Function property as true.

  • The function requires HTTP GET method.
  • The function must include at least one Custom API Response Property defined.
  • The function cannot use Entity or Entity Collection Request Parameter, i.e. Binding Type can only be Global in case of Function.

Let us define a Custom API Response Property and associate it with the custom function defined.

Here we have defined a custom API response property of type Boolean.

The other data type supported are

Below is the plug-in that we will associate with the Custom API message, here we are setting the value of the response parameter.

Associated the plugin to the custom API message

Let us trigger our function using the Postman.

Invoking Custom APIs

https://docs.microsoft.com/en-us/powerapps/developer/data-platform/custom-api#invoking-custom-apis

Plugin trace log –

More information on Custom API

Hope it helps..

Advertisements

Custom API Request Parameter entity in Dynamics 365 / Microsoft Dataverse


Continuing our previous posts on Custom API

Here we will look at the CustomAPIRequestParameter entity.

  • This entity can be used to define input parameters to the Custom API.
  • It is not a mandatory entity for Custom API i.e. we can define a custom API without any input/request or output/response parameter.
  • In the case of multiple parameters, ordering is not important as they are identified using the name.
  • One parameter can be associated with only one Custom API.
  • We can have multiple parameters with the same Unique Name as long as they are associated with different Custom API.

Say e.g. below is our Custom API

And this is our Custom API Request Parameter associated with the above API of type String

The different data type for the request parameter

Below is our plugin registered for the custom message.

We are checking for the input parameter and writing it in the trace log.

Let us call our custom API

And let us check the plugin trace logs.

We can see the message being called successfully.

Get more details –

Create and use Custom APIs

Hope it helps..

Allowed Custom Processing Step Type (AllowedCustomProcessingStepType) property of Custom API in Dynamics 365 / Microsoft Dataverse


Continuing our previous posts, let us check the AllowedCustomProcessingStepType attribute in this blog post

https://nishantrana.me/2021/01/13/use-custom-api-to-create-custom-messages-in-dynamics-365/

https://nishantrana.me/2021/01/14/execute-privilege-name-executeprivilegename-property-of-custom-api-in-dynamics-365-microsoft-dataverse/

Allowed Custom Processing Step Type attribute of custom API allows us to control whether other plugins can be registered or not against the custom message

  • 0 – None – No custom processing steps are allowed.
  • 1 – Async Only– Only Async processing steps are allowed.
  • 2 – Both Async and Sync custom processing steps are allowed

Let us create a custom API with the value of “Allowed Custom Processing Step Type” as None.

If we check inside the Plugin Registration tool, we will not find the above message that we registered i.e. my_sampleAPI there.

Let us create another custom API and specify “Allowed Custom Processing Step Type” as Async Only.

As expected we can find the message available there.

As it is Async Only, if we try to register the step with Synchronous mode, we will get the below error.

Custom SdkMessageProcessingStep is not allowed on the specified message and entity.

As expected it allows us to register the step in asynchronous mode.

Get more details –

Create and use Custom APIs

Hope it helps..

Execute Privilege Name (ExecutePrivilegeName) property of Custom API in Dynamics 365 / Microsoft Dataverse


In the previous post, we created a simple custom API  https://nishantrana.me/2021/01/13/use-custom-api-to-create-custom-messages-in-dynamics-365/

Let us look at its different properties starting with ExecutePrivilegeName

Execute Privilege Name attribute of custom API allows us to specify the name of the privilege that allows execution of the custom API.

Let us update the custom API and specify the privilege name.

For simplification, we have used prvCreateIncident here i.e. Create Case / Incident Privilege.

To get the Privilege name

https://%5Borgname%5D.api.crm.dynamics.com/api/data/v9.1/privileges?$select=name


To test, we updated the security of the Application User to Sales Manager role which doesn’t have the create incident privilege.

Calling the custom API this time as expected gave us the below error

{“error”:{“code”:”0x80040220″,”message”:”Principal user (Id=0f377e29-5545-eb11-a813-000d3a9bf733, type=8, roleCount=1, privilegeCount=727, accessMode=4), is missing prvCreateIncident privilege (Id=6cf9442b-e690-4cad-8b0a-e60464960b93) on OTC=112 for entity ‘incident’. context.Caller=0f377e29-5545-eb11-a813-000d3a9bf733″}}


If we specify an incorrect privilege name we would get the below error and will not be able to save the record.


Hope it helps..


 

Advertisements