Calling an external rest API from D365FO using x++ with proper error handling

Calling an external rest API from D365FO using x++ with proper error handling

Welcome to another Dynamics 365 Finance and Operations (D365FO) Tech Talk blog! In this post, I will share a piece of code that allows you to retrieve the error JSON body instead of just the error status codes like 400 or 401. Many X++ developers still face challenges with proper error handling when working with third-party API integrations. This blog aims to help you address this issue effectively.

Let’s consider an example from the POSTMAN API tool screenshot below.


Imagine you’re calling a refund order API that takes an Order ID as input and processes a refund for it. In the API response, as shown in the screenshot, there are two key elements: the API response status (e.g., 400 Bad Request) and the JSON body that provides detailed information about the failure in JSON format.

As a Dynamics 365 Technical Consultant or Developer, you’re likely familiar with the challenge here—retrieving the JSON response body instead of just the response status.

How can you achieve this?

For POST-type API calling you can use the code below:

public void call_the_POST_API()
{
    System.Net.HttpWebRequest request;
    System.Net.WebResponse response;
    System.IO.Stream responseStream, requestStream;
    System.IO.StreamReader streamReader;
    System.Text.Encoding utf8;
    System.Byte[] bytes;
    System.Exception ex;
    Notes token, requestJson, responseJson, errorMessage;
    
    System.Net.WebException webException;
    URL endpointURL;
     
    System.Net.WebHeaderCollection httpHeader = new System.Net.WebHeaderCollection();
    endpointURL = this.get_EndpointURL();   // Get the API URL 
    new InteropPermission(InteropKind::ClrInterop).assert();
    request = System.Net.WebRequest::Create(endpointURL); // Set the API URL 
    utf8 = System.Text.Encoding::get_UTF8();

    Amir_ReturnOrderContract returnOrderContract = new Amir_ReturnOrderContract();
    returnOrderContract = this.get_Contract();   // Getting the API Request parameters 
    requestJson = FormJsonSerializer::serializeClass(returnOrderContract);
       
    bytes = utf8.GetBytes(requestJson);
    httpHeader = this.get_Header();
    request.set_Method(this.get_Method()); // POST method
    request.set_Headers(httpHeader);  // Get API header 
    request.ContentType = 'application/json';
    request.set_ContentLength(bytes.get_Length());
    requestStream = request.GetRequestStream();
    requestStream.Write(bytes, 0, bytes.get_Length());

    try
    {
        response = request.GetResponse();
        responseStream = response.GetResponseStream();
        streamReader = new System.IO.StreamReader(responseStream);
        responseJson = streamReader.ReadToEnd();

        info(strFmt('Success respesonse %1', responseJson));
    }
    catch (webException)
    {
        // Handle WebException for error response
        if (webException.get_Response() != null)
        {
            System.Net.HttpWebResponse httpWebResponse;
            Notes responseString;

            // Get error response stream
            httpWebResponse = webException.get_Response() as System.Net.HttpWebResponse;
            responseStream = httpWebResponse.GetResponseStream();
            streamReader = new System.IO.StreamReader(responseStream);
            responseString = streamReader.ReadToEnd();

            // Log the error response body (usually in JSON format)
            error(strFmt("Error Response (JSON): %1", responseString));

            // Close resources
            streamReader.Close();
            responseStream.Close();
            httpWebResponse.Close();
        }
        else
        {
            // Log the exception message if no response
            error(strFmt("WebException occurred: %1", webException.get_Message()));
        }
    }
}
        

For GET-type API calling you can use the code below:

 public void call_the_GET_API()
 {
     System.Net.HttpWebRequest request;
     System.Net.WebResponse response;
     System.IO.Stream responseStream, requestStream;
     System.IO.StreamReader streamReader;
     System.Text.Encoding utf8;
     System.Byte[] bytes;
     System.Exception ex;
     Notes token, requestJson, responseJson, errorMessage;
     URL endpointURL;
     SysInfoLogEnumerator infoLogEnum;
     SysInfologMessageStruct infoMessageStruct;
     
     Amir_SuccessStatusResponse   getStatusResponse;
     System.Net.WebException webException;
 
     try
     {
             System.Net.WebHeaderCollection httpHeader = new System.Net.WebHeaderCollection();
             endpointURL = this.get_EndpointURL(); // Getting API URL 
             new InteropPermission(InteropKind::ClrInterop).assert();
             request = System.Net.WebRequest::Create(endpointURL);
             utf8 = System.Text.Encoding::get_UTF8();

             httpHeader = this.get_Header(); // GET THE HEADER 
             request.set_Method(this.get_Method()); // GET API METHOD 
             request.set_Headers(httpHeader); // SET THE HEADER 
             request.ContentType = 'application/json';
    
             response = request.GetResponse();
             responseStream = response.GetResponseStream();
             streamReader = new System.IO.StreamReader(responseStream);
             responseJson = streamReader.ReadToEnd();

             info(strFmt('Success API Response is %1', responseJson));

             getStatusResponse = new Amir_SuccessStatusResponse();
             getStatusResponse = FormJsonSerializer::deserializeObject(classNum(Amir_SuccessStatusResponse), responseJson);
           
         
     }
     catch(webException)
     {
         Amir_ErrorStatusResponse errorStatusResponse = new Amir_ErrorStatusResponse();
         // Handle WebException for error response
         if (webException.get_Response() != null)
         {
             System.Net.HttpWebResponse httpWebResponse;
             Notes responseString;

             // Get error response stream
             httpWebResponse = webException.get_Response() as System.Net.HttpWebResponse;
             responseStream = httpWebResponse.GetResponseStream();
             streamReader = new System.IO.StreamReader(responseStream);
             responseString = streamReader.ReadToEnd();

             // Log the error response body (usually in JSON format)
             error(strFmt("Error Response (JSON): %1", responseString));

           
             errorStatusResponse = FormJsonSerializer::deserializeObject(classNum(Amir_ErrorStatusResponse), responseString);
           
           

         }
     }


 }        

Happy learning,

Syed Amir Ali.


Rehan Afzal

ERP Techno Functional Consultant |Dynamics 365 FO| Business intelligence| Business Process| at BINGHALIB GROUP OF COMPANIES

2 个月

Congratulations

要查看或添加评论,请登录

Syed Amir Ali的更多文章

社区洞察

其他会员也浏览了