How to Integrate D365FO to Dataverse using API HTTPS Request?

How to integrate D365FO with Dataverse using API HTTP requests? 

Introduction: Integrating an external API service into Dynamics 365 Finance and Operations allows you to enhance functionality by connecting D365FO to third-party services, systems, or data sources. This can help automate workflows, fetch real-time data, or extend D365FO’s capabilities. 

Scenario:  In this blog, I have demonstrated how the code queries projects data from D365FO, processes and serializes the data, and then pushes it to an external service via an HTTP API request. 

High level resolution steps 

    • Create a simple batch job. 
    • Create helper class establishes an HTTP connection and sends a POST request with JSON data to an external API, returning the response message 
    • Implement the logic in a batch service class to retrieve project data. 
    • Serialize the data. 
    • Send the data to an external API. 
    • Execute the batch job from the user interface. 

    Step 1: Create a simple batch job; Refer to the link below to create it. 

    Video blog: Sys Operation framework batch job with parameter X++ – Saina Cloud Software Solutions 

    Step 2: Create helper class and execute the code below. 

    Code Snippet: 

    class SCCPostAPIHelper 
    
    { 
    
        #define.PatchAPIMethod('Patch') 
    
        #define.PutAPIMethod('PUT') 
    
        #define.ContentType('application/json') 
    
        #define.PostAPIMethod('POST') 
    
        #define.GetAPIMethod('GET') 
    
        #define.ContentTypeNone('application/none') 
    
        public static System.Net.HttpWebRequest connect(str _appURL) 
    
        { 
    
            System.Net.HttpWebRequest           request; 
    
            CLRObject                                             clrObj; 
    
            System.Exception                                ex; 
    
            System.Net.WebHeaderCollection  httpHeader; 
    
             
    
            try 
    
            { 
    
                httpHeader  = new System.Net.WebHeaderCollection(); 
    
                clrObj            = System.Net.WebRequest::Create(_appURL); 
    
                request         = clrObj; 
    
            } 
    
            catch 
    
            { 
    
                //exception 
    
                ex = CLRInterop::getLastException().GetBaseException(); 
    
                error(ex.get_Message()); 
    
            } 
    
     
    
            return request; 
    
        } 
    
     
    
        public str postAPIRequest(str _jsonString, str _appURL) 
    
        { 
    
            System.Net.HttpWebRequest    request  = SCCPostAPIHelper::connect(_appURL); 
    
            System.Net.HttpWebResponse  response; 
    
            System.IO.StreamWriter             streamWriter; 
    
            System.IO.StreamReader            streamRead; 
    
            str                                                    jsonString = _jsonString; 
    
     
    
            request.Method         = #PostAPIMethod; 
    
            request.ContentType = #ContentType; 
    
     
    
            streamWriter = new System.IO.StreamWriter(request.GetRequestStream()); 
    
            streamWriter.Write(jsonString); 
    
            streamWriter.Flush(); 
    
            streamWriter.Close(); 
    
     
    
            response                    = request.GetResponse(); 
    
            streamRead               = new System.IO.StreamReader(response.GetResponseStream()); 
    
            str outputMessage   = streamRead.ReadToEnd(); 
    
     
    
            return  outputMessage; 
    
        } 
    
     
    
    } 

    Code Explanation: 

    This code defines a helper class SCCPostAPIHelper to interact with external APIs. It includes methods to: 

    1. connect: Establishes an HTTP request to a specified URL. 
    1. postAPIRequest: Sends a POST request with JSON data to the external API and returns the response message. 

    It uses the System.Net.HttpWebRequest and related CLR objects to send data and handle the response. 

    Step 3: Create a List contract and use the below code. 

    [DataContractAttribute] 
    
    class SCCProjectListContract 
    
    { 
    
        List productMasterList; 
    
     
    
        [DataMemberAttribute('productMasterList'), AifCollectionType('_productMasterList', Types::Class, classStr(SCCProjectResponseContract)), AifCollectionType('return', Types::Class, classstr(SCCProjectResponseContract))] 
    
        public List parmProductMaster(List _productMasterList = productMasterList) 
    
        { 
    
            productMasterList = _productMasterList; 
    
     
    
            return productMasterList; 
    
        } 
    
     
    
        public void new() 
    
        { 
    
            productMasterList = new List(Types::Class); 
    
        } 
    
     
    
    } 

    Step 4: Create a Response contract and use the below code 

    [DataContractAttribute] 
    
    class SCCProjectResponseContract 
    
    { 
    
        ProjId                       projId; 
    
        ProjName                projName; 
    
        ProjInvoiceProjId   projContract; 
    
        ProjType                  projType; 
    
        ProjGroupId            projGroup; 
    
     
    
        [DataMemberAttribute("ProjectId")] 
    
        public ProjId parmProjId(ProjId _projId = projId) 
    
        { 
    
            projId = _projId; 
    
     
    
            return projId; 
    
        } 
    
     
    
        [DataMemberAttribute("ProjectName")] 
    
        public ProjName parmProjName(ProjName _projName = projName) 
    
        { 
    
            projName = _projName; 
    
      
    
            return projName; 
    
        } 
    
     
    
        [DataMemberAttribute("ProjectContract")] 
    
        public ProjInvoiceProjId parmProjectContract(ProjInvoiceProjId _projContract = projContract) 
    
        { 
    
            projContract = _projContract; 
    
      
    
            return projContract; 
    
        } 
    
     
    
        [DataMemberAttribute("ProjectType")] 
    
        public ProjType parmProjType(ProjType _projType = projType) 
    
        { 
    
            projType = _projType; 
    
      
    
            return projType; 
    
        } 
    
     
    
        [DataMemberAttribute("ProjectGroup")] 
    
        public ProjGroupId parmProjGroupId(InventSiteId _projGroup = projGroup) 
    
        { 
    
            projGroup = _projGroup; 
    
      
    
            return projGroup; 
    
        } 
    
     
    
    } 

    Step 5: Implement the business logic in a service class. To do that, build a new query to retrieve project data.  

    • For each project returned by the query, it creates a SCCProjectResponseContract and populates it with project details. 
    • Adds the populated contract to the projectList. 
    List                                                         projectList                     = new List(Types::Class); 
    
    SCCProjectListContract                      projectListContract      = new SCCProjectListContract(); 
    
    SCCProjectResponseContract           projectResponseContract; 
    
     
    
    Query                                  projQuery         = new Query(); 
    
    QueryBuildDataSource    qbdsProjTable  = projQuery.addDataSource(tableNum(ProjTable)); 
    
    QueryRun                           qrProj                 = new QueryRun(projQuery); 
    
     
    
    while(qrProj.next()) 
    
    { 
    
        ProjTable projTable = qrProj.get(tableNum(ProjTable)); 
    
     
    
        projectResponseContract = new SCCProjectResponseContract(); 
    
        projectResponseContract.parmProjId(projTable.ProjId); 
    
        projectResponseContract.parmProjName(projTable.Name); 
    
        projectResponseContract.parmProjectContract(projTable.ProjInvoiceProjId); 
    
        projectResponseContract.parmProjType(projTable.Type); 
    
        projectResponseContract.parmProjGroupId(projTable.ProjGroupId); 
    
        projectList.addEnd(projectResponseContract); 
    
    } 
    
    projectListContract.parmProductMaster(projectList); 

    Step 6: Serializes the projectListContract containing project data into a JSON string using FormJsonSerializer::serializeClass. 

    str  jsonString  = FormJsonSerializer::serializeClass(projectListContract); 

    Step 7: Sends the serialized JSON data via a POST request to an external service using postAPIHelper.postAPIRequest 

    SCCPostAPIHelper postAPIHelper = postAPIHelper.postAPIRequest(jsonString,’https://prod-94.westus.logic.azure.com:443/workflows/48fba8aabda0481db43cc12ff6884b0f/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=5OnfThew2rAN9DbmGaaHcnRKiPcWKBf0hpWv6JqhUgI’);

    Note: Get the link from an external application. In this example, I have created Power Automate flow with “When an HTTP request is received”. It will generate the link. To learn how to create Power Automate Flow, use the link below. 

    Service class full code screenshot: 

    Output: 

      Project data which we are going to push from dynamics side.

      When user can run the batch job in UI. Project data pushed to external application. 

      Data pushed from Dynamics side using power automate is displayed in the data verse.