1

I already know that the "official" way is sending all the entire JSON in a string with unbound actions, but per project specification I need the API to be able to read json arrays in json format.

To be clear with an example, this is the data to be sent to the API:

{
    "Batch": "IC0001",
    "Colors": [
        {
            "Color": "GENERAL",
            "Code": "112",
            "Description": "BERMELLON",
            "RGB": "255,0,0",
            "GroupWeb": "40"
        },
        {
            "Color": "GENERAL",
            "Code": "111",
            "Description": "ROJERAS",
            "RGB": "255,0,0",
            "GroupWeb": "40"
        }
    ]
}

I'm trying to read the JSON with the codeunit "JSON Management":

codeunit 60201 IntegracionPLM
{ 
    procedure ReadColorJSON(data: Text)
    var
        JSONManagement: Codeunit "JSON Management";
        ArrayJSONManagement: Codeunit "JSON Management";
        ObjectJSONManagement: Codeunit "JSON Management";
        i: Integer;
        JsonArrayText: Text;
        ColorJsonObject: Text;
        GrupoColoresText: Text;
        CodigoText: Text;
        DescripcionText: Text;
        ValorRGBText: Text;
        AgrupacionWebText: Text;
    begin
        JSONManagement.InitializeObject(Data);

        if JSONManagement.GetArrayPropertyValueAsStringByName('data', JsonArrayText) then begin
            ArrayJSONManagement.InitializeCollection(JsonArrayText);

            for i := 0 to ArrayJSONManagement.GetCollectionCount() - 1 do begin
                ArrayJSONManagement.GetObjectFromCollectionByIndex(ColorJsonObject, i);
                ObjectJSONManagement.InitializeObject(ColorJsonObject);

                ObjectJSONManagement.GetStringPropertyValueByName('GrupoColores', GrupoColoresText);
                ObjectJSONManagement.GetStringPropertyValueByName('Codigo', CodigoText);
                ObjectJSONManagement.GetStringPropertyValueByName('Descripcion', DescripcionText);
                ObjectJSONManagement.GetStringPropertyValueByName('ValorRGB', ValorRGBText);
                ObjectJSONManagement.GetStringPropertyValueByName('AgrupacionWeb', AgrupacionWebText);

                Message('GrupoColores: %1, Codigo: %2, Descripcion: %3, ValorRGB: %4, AgrupacionWeb: %5', 
                         GrupoColoresText, CodigoText, DescripcionText, ValorRGBText, AgrupacionWebText);
            end;
        end;
    end;
}

But I'm getting this error:

{
    "error": {
        "code": "BadRequest",
        "message": "One or more errors occurred. (One or more errors occurred. (An unexpected 'StartArray' node was found when reading from the JSON reader. A 'StartObject' node was expected.))  CorrelationId:  829669bb-ea16-4703-9ef1-e9431d47928e."
    }
}

The request is not going through. Not even reaching my code.

How can I read a json array from my Business Central web service?

5
  • So what is your problem exactly? To receive arbitrary json or to parse it? If you verified (with debugger or messages) that data parameter in ReadColorJson function contains what you need, then you only have to parse it properly. Json Management codeunit is kind of overloaded imho. Just use built-in json types like JsonObject and JsonArray. Commented Sep 10, 2024 at 4:52
  • Batch requests are to use when you want to insert several records using API pages. So it is not your case. Commented Sep 10, 2024 at 4:55
  • Hi @MakSim if you try to get Json data types as parameter that particular procedures won't be up in the web service. Is it possible to debug api calls? I can read a json array in a page action correctly but when publishing as a web service it doesn't work. Commented Sep 10, 2024 at 10:16
  • Don't put json types as parameters. Just use text as before, but pars that text inside procedure using JsonObject type. Commented Sep 11, 2024 at 13:19
  • Yes I can send this as a string and parse the json string: {"data": "{'str':'Hello world!','confirm':true}"} that option is working... I guess it will have a limit of 2048 chars Commented Sep 11, 2024 at 17:08

2 Answers 2

3

Solved by following this guide: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-develop-custom-api

Step 3 did the trick, creating a page with a part:

page 50100 "API Car Brand"
{
    PageType = API;

    APIVersion = 'v1.0';
    APIPublisher = 'bctech';
    APIGroup = 'demo';

    EntityCaption = 'Car Brand';
    EntitySetCaption = 'Car Brands';
    EntityName = 'carBrand';
    EntitySetName = 'carBrands';

    ODataKeyFields = SystemId;
    SourceTable = "Car Brand";

    Extensible = false;
    DelayedInsert = true;

    layout
    {
        area(content)
        {
            repeater(Group)
            {
                field(id; Rec.SystemId)
                {
                    Caption = 'Id';
                    Editable = false;
                }

                field(name; Rec.Name)
                {
                    Caption = 'Name';
                }
                field(description; Rec.Description)
                {
                    Caption = 'Description';
                }
                field(country; Rec.Country)
                {
                    Caption = 'Country';
                }
            }

            part(carModels; "API Car Model")
            {
                Caption = 'Car Models';
                EntityName = 'carModel';
                EntitySetName = 'carModels';
                SubPageLink = "Brand Id" = Field(SystemId);
            }
        }
    }
}

And it's part:

page 50101 "API Car Model"
{
    PageType = API;

    APIVersion = 'v1.0';
    APIPublisher = 'bctech';
    APIGroup = 'demo';

    EntityCaption = 'Car Model';
    EntitySetCaption = 'Car Models';
    EntityName = 'carModel';
    EntitySetName = 'carModels';

    ODataKeyFields = SystemId;
    SourceTable = "Car Model";

    Extensible = false;
    DelayedInsert = true;

    layout
    {
        area(content)
        {
            repeater(Group)
            {
                field(id; Rec.SystemId)
                {
                    Caption = 'Id';
                    Editable = false;
                }
                field(name; Rec.Name)
                {
                    Caption = 'Name';
                }
                field(description; Rec.Description)
                {
                    Caption = 'Description';
                }
                field(brandId; Rec."Brand Id")
                {
                    Caption = 'Brand Id';
                }
                field(power; Rec.Power)
                {
                    Caption = 'Power';
                }
                field(fuelType; Rec."Fuel Type")
                {
                    Caption = 'Fuel Type';
                }
            }
        }
    }
}

Then go to Postman or your tool of preference and test this:

POST https://api.businesscentral.dynamics.com/v2.0/<environmentName>/api/bctech/demo/v1.0/companies(<company id>))/carBrands
{
    "name": "CARBRAND2",
    "description": "Car Brand 2",
    "country": "Germany",
    "carModels": [{
                    "name": "MODELA",
                    "description": "Model A",
                    "power": 0,
                    "fuelType": "Electric"
                },
                {
                    "name": "MODELB",
                    "description": "Model B",
                    "power": 0,
                    "fuelType": "Electric"
                }]
}
Sign up to request clarification or add additional context in comments.

Comments

0

I think what you are looking for is an Unbound API action.

https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-creating-and-interacting-with-odatav4-unbound-action

4 Comments

Yes I'm doing that but if you try you will see the protocol returns an error when trying to send an array like [{"sampledata1": "hello"},{"sampledata2": "bye"}]
I think odata still requires you to wrap your json object into something. Into odata object maybe.
this method of unbound action will allow to send a json into a string, but you can't send the json directly like a regular request
Yep, limitations is the Microsoft's way

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.