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

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Answered

Serialize Json string to send API request

(5) ShareShare
ReportReport
Posted on by 351
Hi,
 
I am trying to create JSON request body to send API request from D365FO. 
Below is the code I have tried to write by creating a container .Not sure if I can do it through container.
In some places I see that it needs a contract class to serialize as well as deserialize the json request and response.
 
Please help me create a contract class for serializing all the values into json string to form the request body.
 
            str order_id = projInvoiceJour.proposalid;
            str order_amount = num2Str(projInvoiceJour.invoiceamount,0,0,0,0);
            str order_currency = projInvoiceJour.currencyid;
            str order_expiry_time = date2Str(projInvoiceJour.duedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4);
            str customerId = projInvoiceJour.InvoiceAccount;
            str customerPhone = dirPartyContactInfoView.Locator;
            str terminalId = parameters.CFTerminalID;
            str terminalPhone = parameters.CFTerminalPhone;
            str invoiceId = projInvoiceJour.projinvoiceid;
            str invoiceDate = date2Str(projInvoiceJour.invoicedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4);
            str gstin = taxReg.registrationNumber;
            str gst = num2Str(abs(taxTransCGST.taxAmountCur) + abs(taxTransSGST.taxAmountCur),0,0,0,0);
            str cgst = num2Str(abs(taxTransCGST.taxAmountCur),0,0,0,0);
            str sgst = num2Str(abs(taxTransSGST.taxAmountCur),0,0,0,0);
            str invoice_name = projInvoiceJour.DeliveryName;


            jsonContainer = [
    ['order_id', order_id],
   ['order_amount', order_amount],
   ['order_currency', order_currency],
   ['customer_details', [
        ['customer_id', customerId],
   ['customer_phone', customerPhone]
            ]],
    ['terminal', [
        ['cf_terminal_id', terminalId],
   ['terminal_type', 'SPOS'],
   ['terminal_phone_no', terminalPhone]
            ]],
    ['order_expiry_time', order_expiry_time],
   ['order_tags', [
        ['invoice_number', invoiceId],
   ['invoice_date', invoiceDate],
   ['gstin', gstin],
      ['gst', gst],
        ['cgst', cgst],
        ['sgst', sgst],
       ['invoice_name', invoice_name]

            ]]
];

str  orderJson = FormJsonSerializer::serializeClass(ContractClass);

 encoding = System.Text.Encoding::get_UTF8();
 stringContent = new System.Net.Http.StringContent(orderJson, encoding, "application/json");

 headers = httpClient.DefaultRequestHeaders;

 headers.Add('x-api-version', apiVersion);
 headers.Add('x-client-id', clientId);
 headers.Add('x-client-secret', clientSecret);
 headers.Add('x-idempotency-key', idempotencyKey);
 headers.Add('x-request-id', requestId);
 
 
Do I have to create parm methods for all the fields ? How will the different nodes be defined in contract class (By nodes I mean - data, customer details,terminal, order_tags) ?
 
Please help.
 
Thanks,
Priya
I have the same question (0)
  • Verified answer
    Layan Jwei Profile Picture
    8,122 Super User 2025 Season 2 on at
    Hi,

    yes you need a contract class with parm methods, the way you build the contract class depends on how the json looks like.

    For example, if the json is like this:
        {
            "dataArea":"USMF",
            "accountNumber": "C000001",
            "currency": "GBP",
            "salesLines":   
            [
                {
                    "itemId":"item1",
                    "itemName": "item1name"
                },
                {
                    "itemId":"item2",
                    "itemName": "item2name"
                }
            ]
        }        

    then u need two contract classes like this:
    [DataContractAttribute]
    class SalesOrderReqContract
    {
        DataAreaId                          dataArea;   
        CustAccount                         accountNum;  
        CustCurrencyCode                    currency;  
        List                                salesOrderLines; 
    
    
        [DataMemberAttribute('dataAreaId')]
        public DataAreaId parmDataArea(DataAreaId _dataArea = dataArea)
        {
            dataArea = _dataArea;
            return dataArea;
        }
    
    
        [DataMemberAttribute('accountNumber')]
        public CustAccount parmAccountNum(CustAccount _accountNum = accountNum)
        {
            accountNum = _accountNum;
            return accountNum;
        }
    
    
        [DataMemberAttribute('currency')]
        public CustCurrencyCode parmCurrency(CustCurrencyCode _currency = currency)
        {
            currency = _currency;
            return currency;
        }
    
    
        [DataMemberAttribute('salesLines'),
        AifCollectionTypeAttribute('_salesOrderLines',Types::Class,classStr(SalesLineReqContract)),
        AifCollectionTypeAttribute('return',Types::Class,classStr(SalesLineReqContract))]
        public List parmSalesLines(List _salesOrderLines = salesOrderLines)
        {
            salesOrderLines = _salesOrderLines;
            return salesOrderLines;
        }
    }
    [DataContractAttribute]
    class SalesLineLineReqContract
    {
        ItemIdSmall             itemId;     
        ItemFreeTxt             itemName; 
    
    
        [DataMemberAttribute('itemId')]
        public ItemIdSmall parmItemId(ItemIdSmall _itemId = itemId)
        {
            itemId = _itemId;
            return itemId;
        }
    
        [DataMemberAttribute('itemName')]
        public ItemFreeTxt parmItemName(ItemFreeTxt _itemName = itemName)
        {
            itemName = _itemName;
            return itemName;
        }
    
    }


    so in your case you will need to fill all fields for the contract class, like this

    contract.parmAccoountNumber('000001');


    i didn't understand the container part, i hope i was able to help, if u need more info then please explain further.


    Thanks,
    Layan Jweihan
    Please mark this answer as "Verified" if it solved your issue. In order to help others who will face a similar issue in the future.


     
  • Layan Jwei Profile Picture
    8,122 Super User 2025 Season 2 on at
    Hi,
     
    Is your question answered? If yes then please verify the answer if it helped
  • PriyaDutta Profile Picture
    351 on at
    Hi Layan,
     
    Yes Thank you very much . I have created contract classes using your advise.
     
     
  • Layan Jwei Profile Picture
    8,122 Super User 2025 Season 2 on at
    I'm glad it helped Priya. Thanks for coming back to us and verifying the answer.
  • PriyaDutta Profile Picture
    351 on at
    Hi Layan,
     
    Iam able to create the json string through contract classes. But the sequence of the string is coming alphabetically no matter how I call the parm methods.
    Can u please see my code below :
      HS_QRCodeGenerationCustDetailsContract custDetailsContract = new HS_QRCodeGenerationCustDetailsContract();
      HS_QRCodeGenerationTerminalDetContract terminalDetContract = new HS_QRCodeGenerationTerminalDetContract();
      HS_QRCodeGenerationDataContract dataContract = new HS_QRCodeGenerationDataContract();
      
      List                itemdataList        = new List(Types::Class);
      List                itemContractList        = new List(Types::Class);
      List                itemtermList        = new List(Types::Class);
      List                itemOrderList        = new List(Types::Class);
             
    
      dataContract.parmOrderID(projInvoiceJour.proposalid);
     
      dataContract.parmOrderAmt( num2Str(projInvoiceJour.invoiceamount,0,0,0,0));
     
      dataContract.parmOrderCurrency(projInvoiceJour.currencyid);
      
    
      
      custDetailsContract.parmCustID('cust123');
      custDetailsContract.parmCustPhone('2564');
     // itemContractList.addEnd(custDetailsContract);
    
      dataContract.parmCustDetailsContract(custDetailsContract);
      itemdataList.addEnd(dataContract);
    
      terminalDetContract.parmCfTerminalID(parameters.CFTerminalID);
      terminalDetContract.parmCfTerminalPhone( parameters.CFTerminalPhone);
      terminalDetContract.parmCfTerminalType( parameters.CFTerminalType);
      itemtermList.addEnd(terminalDetContract);
    
     // mainContract.parmOrderExpiryTime(date2Str(projInvoiceJour.duedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4));
     
      HS_QRCodeGenerationOrderTagsContract orderTagsContract = new HS_QRCodeGenerationOrderTagsContract();
      orderTagsContract.parmInvNum( projInvoiceJour.projinvoiceid);
      orderTagsContract.parmInvDate(date2Str(projInvoiceJour.invoicedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4));
      orderTagsContract.parmGSTIN(taxReg.registrationNumber);
      orderTagsContract.parmGST(num2Str(abs(taxTransCGST.taxAmountCur) + abs(taxTransSGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmCGST( num2Str(abs(taxTransCGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmSGST(num2Str(abs(taxTransSGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmInvName(projInvoiceJour.DeliveryName);
      itemOrderList.addEnd(orderTagsContract);
    
      HS_QRCodeGenerationMasterContract mainContract        = new HS_QRCodeGenerationMasterContract();
     
      mainContract.parmDataContract(dataContract);
      
      mainContract.parmTerminalDetaContract(terminalDetContract);
    
      mainContract.parmOrderExpiryTime(date2Str(projInvoiceJour.duedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4));
    
      mainContract.parmOrderTags(orderTagsContract);
      itemMainList.addEnd(mainContract);
     // mainContract.
    
          // Serialize the container into JSON
       //   FormJsonSerializer jsonSerializer = new FormJsonSerializer();
      orderJson =  FormJsonSerializer::serializeClass(itemMainList);
      Info(strfmt("string: %1",orderJson));
    JSON EXPECTED
    data '{
      "order_id": "INV-2024-144066",
      "order_amount": 193284,
      "order_currency": "INR",
      "customer_details": {
        "customer_id": "Cust-015628",
        "customer_phone": "9999999999"
      },
      "terminal": {
        "cf_terminal_id": 21732,
        "terminal_type": "SPOS",
        "terminal_phone_no": "8554956545"
      },
      "order_expiry_time": "2025-01-07T10:20:12+05:30",
      "order_tags": {
        "invoice_number": "BDO2425GUR003622",
        "invoice_date": "2024-12-12T00:00:00+05:30",
        "gstin": "06AANFB3386M1ZY",
        "gst": "29484.00",
        "cgst": "14742.00",
        "sgst": "14742.00",
        "invoice_name": "Unit 28 & 29, Level 18, The executive Center,"
      }
    }'
    
    JSON GENERATED:
     [{"Data":{"CustomerDetails":{},
    "order_amount":"1883",
    "order_currency":"USD",
    "order_id":"INV-2022-00174"},
    "order_expiry_time":"2022-09-01",
    "order_tags":{},
    "terminal":{}
    
    }}

    ​​​​​​​
    Thanks.
  • Martin Dráb Profile Picture
    237,990 Most Valuable Professional on at
    What is the problem? It produces JSON with the correct properties and data. If it merely doesn't look like you expected, then there is no real problem to address.
     
    If the software processing the file doesn't work with this order of properties, isn't it actually a bug there?
     
    If you really have no other choice than changing the order of properties, I don't think you can do it at this place. Newtonsoft.Json serialization has JsonPropertyAttribute.Order property for this purpose, but I don't see how you could use it from X++. (I may be missing something, though.) A viable solution may be transforming the response in Azure API Management or something like that.
  • PriyaDutta Profile Picture
    351 on at
    Hi Martin, 
    The problem is the json string I need to send for API request is not coming as expected. 
    Expected json request body looks like :
     
    whereas my json looks like arranged alphabetically somehow.

     
    Order id , order amount, order currency, then customer details. And end with orderTags.
     
     
  • PriyaDutta Profile Picture
    351 on at
    Hi,
     
    Looks like there is some issue with the contract classes returning null values in json even when in debugging I can see the parm methods getting the values .
      dataContract.parmOrderID(projInvoiceJour.proposalid);
               
      dataContract.parmOrderAmt( num2Str(projInvoiceJour.invoiceamount,0,0,0,0));
               
      dataContract.parmOrderCurrency(projInvoiceJour.currencyid);
                
      //custDetailsContract.init('cust123','2564');
    
      custDetailsContract.parmCustID('cust123');
      custDetailsContract.parmCustPhone('2564');
    
    
      //itemdataList.addEnd(dataContract);
    
      terminalDetContract.parmCfTerminalID(parameters.CFTerminalID);
      terminalDetContract.parmCfTerminalPhone( parameters.CFTerminalPhone);
      terminalDetContract.parmCfTerminalType( parameters.CFTerminalType);
              
      HS_QRCodeGenerationOrderTagsContract orderTagsContract = new HS_QRCodeGenerationOrderTagsContract();
      orderTagsContract.parmInvNum( projInvoiceJour.projinvoiceid);
      orderTagsContract.parmInvDate(date2Str(projInvoiceJour.invoicedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4));
      orderTagsContract.parmGSTIN(taxReg.registrationNumber);
      orderTagsContract.parmGST(num2Str(abs(taxTransCGST.taxAmountCur) + abs(taxTransSGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmCGST( num2Str(abs(taxTransCGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmSGST(num2Str(abs(taxTransSGST.taxAmountCur),0,0,0,0));
      orderTagsContract.parmInvName(projInvoiceJour.DeliveryName);
      
    
      HS_QRCodeGenerationMasterContract mainContract        = new HS_QRCodeGenerationMasterContract();
      dataContract.parmCustDetailsContract(custDetailsContract);
      mainContract.parmDataContract(dataContract);
      mainContract.parmTerminalDetaContract(terminalDetContract);
      
      mainContract.parmOrderExpiryTime(date2Str(projInvoiceJour.duedate, 321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2, DateSeparator::Hyphen,DateYear::Digits4));
     
      mainContract.parmOrderTags(orderTagsContract);
    
      orderJson =  FormJsonSerializer::serializeClass(mainContract);
    Am i correctly calling the objects and in sequence . Am i missing to insert some values in the contract ?
  • Martin Dráb Profile Picture
    237,990 Most Valuable Professional on at
    Could you read my response once more, please? I do understand that the sequence of elements isn't what you expected, but that in itself doesn't mean that there is a problem. 
     
    Regarding "there is some issue with the contract classes returning null values", please give us a more detailed description of this problem.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Abhilash Warrier Profile Picture

Abhilash Warrier 669 Super User 2025 Season 2

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 471 Super User 2025 Season 2

#3
Martin Dráb Profile Picture

Martin Dráb 423 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans