web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Dynamics 365 Community / Blogs / Jesús Almaraz blog / Adding features to Business...

Adding features to Business Central with a local Node server

Jalmaraz Profile Picture Jalmaraz 669

Introduction: replace Dotnet with API servers

The main ideas of this post:
1. If we can, we would rather use Rest API than DOTNET components. But this is only an opinion, I find API calls in AL are very easy with AL HttpClient variable.
2. The best place for Rest APIs is the cloud, but it is not the only place for them. You can install an API Rest service in your local server and it is very easy.
This could be the scenario: make a new feature without DOTNET components and avoiding external cloud sites dependencies. I would rather use an external service in Azure or IBM Cloud, but some old-school customers don´t like to have their features out of their systems, in the cloud. I don´t like DOTNET use, even if On-Prem installations allows us them because I think that DOTNET use is complex to handle from NAV (in my opinion). It seems that Microsoft recommends us to replace DOTNET with Azure Functions. I already wrote a post about this
With this scenario, a new feature without DOTNET and without Cloud resources, we are going to use a very simple solution, create a local server with Node.js, deploying the API in the client PC or in the local server. This solution with a simple Node server publishing is not available from SAAS service, only from On-Prem BC. If we try to call this API from SAAS, call will fail, because this local site will not be visible from outside.

Use case

We need a Boolean expression evaluator. The input will be an string expression like that (1+9 = 10) OR (1+9 < 0), and the output is the Boolean evaluation of the input string, true of false. The purposes of all this is perform an account alert system that evaluates G/L accounts balance conditions to make alerts and send messages. By example we can define a condition with G/L accounts delimited with brackets this way ([5700001] + [5720001]< [4010001]). I am not an accountant, so I don´t know if this example make sense. This condition is true when sum of balance of 5700001 (cash) and 5720001 (bank account) accounts are less than 4010001 (short term vendor debt). In AL code we must replace the account with bracket by its balance, and evaluate the resultant Boolean string.
The first part, string substitution, is easy, but the bool evaluation is more difficult so previously in C/AL I used the Scripting DOTNET library.
Due I don´t want to use in this example DOTNET and external cloud services the Boolean evaluation is the part we will implement with a Node local API server.

Developing Node local server

Node is a framework to execute server-side JavaScript code. Microsoft bought it on March 2020, well more accurately Microsoft bought NPM, Node Package Management. Node gives us all the features of JavaScript with a lot of additional packages  to make possible JavaScript server-side development.
Node is easy to install from its site https://nodejs.org/en/download/current/ and you can work with it and develop with Visual Studio Code as you work with AL language. If you want a quick start to node.js there is this a free e-book:
Node allows us to make an API server with a few code lines. The JS script code is only this:
const http = require('http');
const server = http.createServer((requestresponse=> {       
       let boolexpr = '';
       request.on('data'function(data) {
              for (var i = 0i < data.lengthi++) {
                     boolexpr += String.fromCharCode(data[i]);
                   }                                 
              response.writeHead(200, {'Content-Type': 'text/plain'});   
              console.log('Input ' + boolexpr + '=' + IsTrue(boolexpr));
              response.end(IsTrue(boolexpr))});       
            })       
server.listen(8080);
console.log('Service up');
 
function IsTrue(inputexpr='textdef'){
To create the server we use a Node package, http, using Createserver and listen methods to start a service. The service that accept a POST call with the bool expression (example 1+9  < 0) and returns the bool evaluation with a function called IsTrue that returns true or false.
function IsTrue(inputexpr = 'textdef') {
  try {
    var inputexprModified = SQLToJSBooleanNotation(inputexpr);
    inputexprModified = AlmostSafe(inputexprModified);
    if (eval(AlmostSafe(inputexprModified))) {
      return ('true')
    } else {
      return ('false')
    }
  }
  catch (error) { return (error) };
}
A little digression about JavaScript programming. Yes, I know Eval statement using is an anti-pattern (Eval is evil) but I decided use it removing all alphabetic characters from original input string before Eval processing, calling the AlmostSafe function.

Run local server

There are lots of ways to make our local PC become a API server, and most of them are better than that I going to do, but according with the simple crafting spirit of this post I will start up the server with a Node shell execution:
call "C:\Program Files\nodejs\nodevars.bat"
pause
node "C:\Users\Jesus\Documents\Proyecto js\ServicioPrueba\ServidorHttp.js"
pause

Business Central AL API consumption

This is the API call from NAV, nothing to comment about this code, here we have the well-known use of HttpClient object to call an external API:
    local procedure EvaluateExprServer(UrlDestino: Text; BodyText: Text);
    var
        ClientExprHttpClient;
        RequestExprHttpRequestMessage;
        Header: HttpHeaders;
        Response: HttpResponseMessage;
        ReqBodyHttpContent;
        TextoResponseText;
    begin
        RequestExpr.SetRequestUri(UrlDestino);
        RequestExpr.Method('POST');
        ReqBody.WriteFrom(BodyText);
        ReqBody.GetHeaders(Header);
        Header.Remove('Content-Type');
        Header.Add('Content-Type''application/json');
        RequestExpr.Content(ReqBody);
        ClientExpr.send(RequestExpr, Response);
        Response.Content.ReadAs(TextoResponse);
        Message(TextoResponse);
    end;

What about SAAS?

A local API server only works in an On-Prem NAV System, with SAAS we need another way to provide external features to NAV. The obvious choice is Azure Functions, but is not the only provider, IBM Cloud Functions is a worth alternative. IBM services free accounts for developers have extremely generous conditions, without expiration and without credit card with a lot of available features.
For testing purposes, I love some servers like https://repl.it/. They also give us a lot a free features: templates, GIT integration, app deployment, and is very enjoyable the ease to develop an Express server. Express is a Node.js module to develop REST APIs.

Comments

*This post is locked for comments