Calling an external rest API from D365FO using x++ with proper error handling
Syed Amir Ali
Microsoft Certified Dynamics 365 Finance & Operations Specialist | MCT | Techno-Functional Supply Chain Consultant
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.
ERP Techno Functional Consultant |Dynamics 365 FO| Business intelligence| Business Process| at BINGHALIB GROUP OF COMPANIES
2 个月Congratulations