Augmenting Business Central data with a RESTFul API

This week, I fell into the trap that all engineers are prone to; instead of spending 30 seconds manually entering a new country, I decided to solve my problem by developing a solution to import data from a country API. Check out the video:

https://youtu.be/zMFbvX3wy5A

In this video, Erik demonstrates how to augment Business Central’s country/region data by consuming a public RESTful API. Rather than manually adding a missing country to the country table, he takes the true engineer’s approach: building a tool that pulls the complete list of countries from an external web service and updates Business Central automatically. It’s a great example of how to call external APIs from AL code with minimal boilerplate.

The Problem: Missing Countries in Business Central

Erik discovered that a customer order from hougaard.com failed to process in Business Central because the customer’s country didn’t exist in the country/region table. The country table in BC has its roots in older systems (like Navision’s Cronus demo data), and it doesn’t include every country in the world — despite Business Central itself being available in over 150 countries on AppSource.

Instead of just adding the one missing country manually, Erik decided to find an authoritative source for country data and build a tool to sync the entire list.

The Data Source: REST Countries API

Erik found restcountries.com, a free RESTful API that provides comprehensive information about countries. The API endpoint he uses returns JSON data with fields including:

  • cca2 — The two-letter country code (e.g., “MD” for Moldova)
  • name.common — The common name of the country (e.g., “Moldova”)
  • ccn3 — The ISO numeric code
  • Additional data like time zones, official names, three-letter codes, and more

The API returns a JSON array of country objects, which makes it straightforward to iterate through and populate BC’s country/region table.

Building the Page Extension

Erik creates a page extension on the Country/Regions page (page 10) that adds an action button to trigger the update. The action calls the REST Countries API, parses the JSON response, and inserts or updates records in the country/region table.

The Complete AL Code

Here’s the page extension that adds the “Update Country List” action:

pageextension 50100 CountryRegionExt extends "Countries/Regions"
{
    actions
    {
        addlast(processing)
        {
            action(UpdateCountryList)
            {
                ApplicationArea = All;
                Caption = 'Update Country List';

                trigger OnAction()
                var
                    Client: HttpClient;
                    Response: HttpResponseMessage;
                    CountryArray: JsonArray;
                    CountryJSON: JsonObject;
                    NameJSON: JsonObject;
                    T: JsonToken;
                    ResponseText: Text;
                    CountryRec: Record "Country/Region";
                begin
                    Client.Get('https://restcountries.com/v3.1/all?fields=name,cca2,ccn3', Response);
                    if Response.IsSuccessStatusCode() then begin
                        Response.Content.ReadAs(ResponseText);
                        CountryArray.ReadFrom(ResponseText);
                        for each T in CountryArray do begin
                            CountryJSON := T.AsObject();
                            if not CountryRec.Get(CountryJSON.GetText('cca2')) then begin
                                CountryRec.Init();
                                CountryRec.Code := CopyStr(CountryJSON.GetText('cca2'), 1, 10);
                                CountryRec.Insert(true);
                            end;
                            NameJSON := CountryJSON.GetObject('name');
                            CountryRec.Validate(Name, CopyStr(NameJSON.GetText('common'), 1, 50));
                            CountryRec.Validate("ISO Numeric Code", CopyStr(CountryJSON.GetText('ccn3'), 1, 3));
                            CountryRec.Modify(true);
                        end;
                    end else
                        Error('API returned %1', Response.HttpStatusCode());
                end;
            }
        }
    }
}

How It Works: Step by Step

1. Making the HTTP Request

The HttpClient variable makes a GET request to the REST Countries API. The URL includes a fields parameter to request only the data we need: name, cca2, and ccn3.

Client.Get('https://restcountries.com/v3.1/all?fields=name,cca2,ccn3', Response);

2. Reading the Response

The response content must first be read into a Text variable, and then parsed into a JsonArray. Erik notes that he’s still waiting for the day Microsoft allows reading the response directly into a JSON object or array — that would be a welcome quality-of-life improvement.

Response.Content.ReadAs(ResponseText);
CountryArray.ReadFrom(ResponseText);

3. Iterating Through the JSON Array

Another area where Erik would love to see improvement: you can’t iterate a JsonArray directly into a JsonObject. You must iterate into a JsonToken first and then cast it:

for each T in CountryArray do begin
    CountryJSON := T.AsObject();

4. Inserting or Updating Records

For each country, the code checks if the record already exists. If not, it initializes and inserts a new one. Then it validates the name (from the nested name.common field) and the ISO numeric code, and modifies the record:

if not CountryRec.Get(CountryJSON.GetText('cca2')) then begin
    CountryRec.Init();
    CountryRec.Code := CopyStr(CountryJSON.GetText('cca2'), 1, 10);
    CountryRec.Insert(true);
end;
NameJSON := CountryJSON.GetObject('name');
CountryRec.Validate(Name, CopyStr(NameJSON.GetText('common'), 1, 50));
CountryRec.Validate("ISO Numeric Code", CopyStr(CountryJSON.GetText('ccn3'), 1, 3));
CountryRec.Modify(true);

Error Handling: The Pragmatic Approach

Erik takes a deliberately minimal approach to error handling. The only explicit check is on the HTTP status code — if the API returns a non-success status, an error message is displayed showing the status code (e.g., 404 if the URL is wrong).

His reasoning is pragmatic: if the JSON is malformed, the ReadFrom call will fail. If a field is missing, the GetText call will fail with a clear error message. For something a user runs once in a while, these built-in failures are informative enough without wrapping everything in additional error handling.

Erik demonstrates this by intentionally breaking the URL (getting a 404 error), and by removing a field name (getting a descriptive runtime error). In both cases, nothing is corrupted — the operation simply fails gracefully.

Debugging Tips

During the debugging session, Erik shares a useful tip: when inspecting large text variables in the VS Code debugger, the tooltip may truncate the content. Instead, open the Debug Console and type the variable name there to see the full content. This works for any large variable and is especially handy when working with JSON responses.

He also notes that the first time you make an external HTTP call from a Business Central sandbox, there may be a delay while the environment opens up the external connection — don’t mistake this for a slow API.

The Results

After running the action, the country/region table went from 139 entries (the Cronus default) to 251 countries — the complete list from the REST Countries API. The API also provides additional data that could be mapped to other fields, such as three-letter country codes, time zones, and official names.

Summary

In roughly 44 lines of AL code, Erik built a tool that pulls the complete list of world countries from a RESTful API and syncs them into Business Central’s country/region table. The key takeaways are:

  • HttpClient makes it straightforward to call external REST APIs from AL
  • JSON parsing in AL requires a few intermediate steps (Text → JsonArray, JsonToken → JsonObject) that could benefit from quality-of-life improvements
  • Minimal error handling can be perfectly acceptable for utility-style operations — the runtime will catch most issues with clear error messages
  • Public APIs like restcountries.com are great sources for augmenting reference data in Business Central
  • The Debug Console in VS Code is your friend when inspecting large response payloads

As Erik puts it: what defines a true engineer is spending hours building a tool instead of spending 10 minutes fixing the problem manually. But now that tool exists for every future missing country!