A few weeks ago, I posted about AL support for REST Web Services. And at the end I promised to convert the previous posted web service examples to AL code. The first three are now available on GitHub. Feel free to clone, fork and play with it.
The code consists of a set of base objects and a set of objects per web service example. The base objects are reused by all web service examples. In the base objects there are a number of objects:
- Table RESTWebServiceArguments
- Codeunit RESTWebServiceCode
- Codeunit JSONMethods
- Pageextension BusinessManagerRoleCenter
RESTWebServiceArguments table
The RESTWebServiceArguments table is used to implement the Argument Table pattern. With this pattern, we have less dependency between functions and a change in the parameters doesn’t have a ripple effect.
The table holds fields like REST method, URL, UserName and Password. And it has a Blob field to store the complex type HttpContent. Besides the fields, there are functions to set and get HttpContent for the request and the response.
The HttpContent for the request is saved into a global variable, while the resulting HttpContent (from the response) is stored into the Blob field. The reason is that the response content cannot be hold into memory with a global variable. This is not a AL restriction, it also appears in .Net. I will spare you the details, I have tried out different ways before I came up with this one.
RESTWebServiceCode codeunit
This codeunit is at the heart of the web services. It accepts the argument table and builds up a complete HttpRequestMessage to be sent to the web service.
When you compare this to the first AL web service example, you will see a big difference. In that example the code to call a web service was fairly straightforward: HttpClient.Get(URL,HttpResponseMessage). The HttpClient as of course also functions for Post, Delete, etc.
In this codeunit we use the method HttpClient.Send(HttpRequestMessage,HttpResponseMessage). The difference is that the HttpRequestMessage is completely prepared with all necessary parameters, like URL, HTTP method, headers (e.g. credentials) and content (for post methods).
After the Send method, we get back a HttpResponseMessage that is stored into the parameters table.
JSONMethods codeunit
This codeunit has two functions to read a Json value from a JsonObject. It is just some code to avoid having to write these lines of code over and over again.
BusinessManagerRoleCenter pageextension
Because we currently cannot add new items to the search result (e.g. Menusuite, although Microsoft is apparently thinking of a different solution according to some GitHub issues) I decided to put the web service examples to the Business Manager Role Center.
Web Service Verify E-mail Address
This web service was introducted in this article. The AL code is pretty simple, using the base objects of course. Have a look at codeunit VerifyEmailAddress to see how it works. The functionality is applied to the E-mail field of the Contact table using a Table extension object.
Web Service Generate Barcode Images
This web service was introduced in this article. I have redesigned the objects for better readability. The most interesting part is probably in function SaveResult in codeunit GenerateBarcode, where the resulting image is stored into the Media field. The HttpContent object contains binary data instead of text, so we use an InStream object to read the data of the response.
Web Service Sending SMS with BulkSMS
This web sevice was introduced in this article. I have again redesigned the objects for better readability. The code is pretty much the same as before. There was an important difference, though.
The request content for the BulkSMS send sms web service must be called by using the POST method. To post something over HTTP, you use a request content. However, with AL code it turned to be a little bit tricky.
In the version for C/AL code I used a StringContent object to create content with the correct media type. What am I talkin about? Look at this C/AL code snippet:
The media type is ‘application/x-www-form-urlencoded’. This is a specific type of posting data over HTTP. Think of it as a form that you fill out on an internet page and when you post it the data is put into a large querystring, like field1=value&field2=value, etc. This is not the default value for the media type. The default is ‘multipart/form-data’.
Why is this important? Well, the AL object HttpContent uses ‘multipart/form-data’ as default setting without an option to change it when you set the content. That resulted in error messages because the web service expected a different content type.
After some test, I found out that it is possible to change the content type header of the HttpContent object. By first removing the existing content type header and then add the correct one. You can see that in this code in the InitArguments function of the BulkSMSSendMessage codeunit.
Some comments
The code was not created in a breeze. Although there are not many objects in it, typing it all in with VS Code is somewhat time consuming. Time will tell if this is going to affect the planning of development time when we fully switch to AL code development.
You may have seen my previous post about Base64 encoding. Although I have this code, I decided to not use it and stay with the Base64 functions in the TempBlob table (used in codeunit RESTWebServiceCode). The reason is that the functions in the TempBlob table are faster compared to the AL code. Another reason for Microsoft to embed as much .Net functionality in AL code as possible. We have seen XML support in the July update and for the August update we expect String functions.
The code is only compatible with the July update, and hopefully with higher versions. No guarantees though, it is all beta software and things can change or break in next updates.
Pingback: AL Web Service Examples - Kauffmann @ Dynamics NAV - Dynamics NAV Users - DUG
Hi, for some reason i want to set accept-type for httpclient default headers. (Not for content headers).
How i can do in AL?
In dot net we use header without validation.
https://docs.microsoft.com/en-us/previous-versions/hh204926(v=vs.108)
The command for that is
HttpClient.DefaultRequestHeaders.Add('Accept','<mime type>/<mime subtype>').
Thanks fo reply.
Sorry it should be content-type.
As per below api requirements, i have to add both accept and content type to header.
When i add content type getting error misused header. That’s dot net we use without validation header.
https://apiservices.iras.gov.sg/iras/devportal/api/check-gst-register
The content type is set as a header on the content itself.
RequestContent.GetHeaders(RequestHeaders);
RequestHeaders.Remove('Content-Type');
RequestHeaders.Add('Content-Type', '<mime type>/<mime subtype>');
In this code variables are declared as:
RequestContent: HttpContent;
RequestHeaders: HttpHeaders;
Ton of thanks. It helped.
Hi,
I want to connect a Dynamics 365 CRM webservice, and then I need include in the header the authorization (would be great if only user and password). Do you know how use this API? I checked with Postman but using a Token, but if it’s an automatic service, I can’t use the prompt to ask for the user and name.
Thanks for your help.
Best regards,
Roberto
Hi,
I want to connect some basic Weather webservice, with basic GET method.
This is the definition of the webservice:
https://api.weatherbit.io/v2.0/forecast/daily?city=Raleigh,NC&key=API_KEY
How to add parameters(city, key) into HttpRequest? I’ve tried with Header.Add but didn’t work, also with HttpContent.
Thanks in advance!
Hi John,
I believe the answer is already in your question. 😉
The city and key parameters are query parameters, you only have to add them to the url. It’s not needed to add them in the headers.
Hope that helps!
AJ
Hello,
Very helpful blog! Since Tempblob is removed in the latest in the latest update, what is its replacement?
You should use the TempBlob codeunit instead. For more information read here: https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/BLOB%20Storage/README.md. Scroll down to TempBlob codeunit.
Hey, thanks this is very helpful but I still need to know how to implement a button in NAV to trigger the request. I also want to send some data of the active page as arguments. Can you give me a hint. ^^
Thanks in advance.
Maybe this helps? https://docs.microsoft.com/en-us/dynamics-nav/how-to–add-actions-to-a-page