question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Problem with Serialization of request body

See original GitHub issue

Hello team,

We have been using Xero for long time and we were consuming xero-apis in a traditional way using node-fetch.

We are trying to move our API calls to Xero-Node wrappers. But we are facing serialization issues in all services, invoices, credit notes etc.

Example - credit note:

Code we are using:

const createXeroCreditNote = async (invoiceID) => {
  const tokenSet = await getTokenSet();
  await xero.setTokenSet(tokenSet.token_set);
  const unitdp = 4;

  let invoice;
  try {
    const response = await xero.accountingApi.getInvoice(tokenSet.tenant_id, invoiceID, unitdp);
    invoice = response.body.invoices[0];
  } catch (err) {
    const error = JSON.stringify(err.response.body, null, 2);
    throw new ErrorHandler(500, `Getting invoice to void error: ${err} => ${error}`);
  }

  logger.info(`Creating credit note for invoice of ${invoice.reference}`);
  const contact = {
    contactID: invoice.contact.contactID,
  };

  const lineItems = invoice.lineItems.map(lineItem => ({
    description: lineItem.description,
    quantity: lineItem.quantity,
    unitAmount: lineItem.unitAmount,
    accountCode: lineItem.accountCode,
    itemCode: lineItem.itemCode,
  }));

  const creditNotes = {
    creditNotes: [{
      type: CreditNote.TypeEnum.ACCRECCREDIT,
      contact: contact,
      date: moment(),
      lineItems,
    }]
  };

  try {
    const response = await xero.accountingApi.createCreditNotes(tokenSet.tenant_id, creditNotes, true, unitdp);
    logger.info('Credit note successfully created - %o', response.body || response.response.statusCode);
    return response.body.creditNotes[0];
  } catch (err) {
    const error = JSON.stringify(err, null, 2);
    console.log(error);
    throw new ErrorHandler(500, `createXeroCreditNote error: ${err} => ${error}`);
  }
};

Error I get

{
  "response": {
    "statusCode": 400,
    "body": {
      "ErrorNumber": 10,
      "Type": "ValidationException",
      "Message": "A validation exception occurred",
      "Elements": [
        {
          "CreditNoteID": "00000000-0000-0000-0000-000000000000",
          "ID": "00000000-0000-0000-0000-000000000000",
          "HasErrors": true,
          "Type": "ACCRECCREDIT",
          "Contact": {
            "ContactID": "54b2e385-9987-490f-b901-a47b6fd0f501",
            "Addresses": [],
            "Phones": [],
            "ContactGroups": [],
            "ContactPersons": [],
            "HasValidationErrors": false,
            "ValidationErrors": []
          },
          "DateString": "2021-09-22T03:02:24",
          "Date": "/Date(1632279744252)/",
          "Status": "DRAFT",
          "LineAmountTypes": "Exclusive",
          "LineItems": [
            {
              "ItemCode": "C01-C020003-030-1",
              "Description": "Circle CBD 20 Oil - 30ml",
              "UnitAmount": 119,
              "TaxType": "BASEXCLUDED",
              "TaxAmount": 0,
              "LineAmount": 238,
              "AccountCode": "200",
              "Tracking": [],
              "Quantity": 2,
              "AccountID": "acafc55b-57e9-4d19-b9a6-66d30d4b50b7",
              "ValidationErrors": []
            },
            {
              "ItemCode": "DIS-FEE",
              "Description": "Pharmacy Dispensing Fee",
              "UnitAmount": 35,
              "TaxType": "BASEXCLUDED",
              "TaxAmount": 0,
              "LineAmount": 35,
              "AccountCode": "200",
              "Tracking": [],
              "Quantity": 1,
              "AccountID": "acafc55b-57e9-4d19-b9a6-66d30d4b50b7",
              "ValidationErrors": []
            },
            {
              "Tracking": [],
              "ValidationErrors": []
            },
            {
              "Tracking": [],
              "ValidationErrors": []
            }
          ],
          "SubTotal": 273,
          "TotalTax": 0,
          "Total": 273,
          "CurrencyCode": "AUD",
          "ValidationErrors": [
            {
              "Message": "The description field is mandatory for each line item."
            },
            {
              "Message": "The description field is mandatory for each line item."
            }
          ]
        },
        {
          "CreditNoteID": "00000000-0000-0000-0000-000000000000",
          "ID": "00000000-0000-0000-0000-000000000000",
          "HasErrors": true,
          "DateString": "2021-09-22T00:00:00",
          "Date": "/Date(1632268800000+0000)/",
          "Status": "DRAFT",
          "LineAmountTypes": "Exclusive",
          "LineItems": [],
          "SubTotal": 0,
          "TotalTax": 0,
          "Total": 0,
          "CurrencyCode": "AUD",
          "ValidationErrors": [
            {
              "Message": "One or more line items must be specified"
            },
            {
              "Message": "Type is required."
            },
            {
              "Message": "A Contact must be specified for this type of transaction"
            }
          ]
        }
      ]
    },
    "headers": {
      "content-type": "application/json; charset=utf-8",
      "content-length": "2898",
      "server": "nginx",
      "xero-correlation-id": "6b7a5ebe-2690-4a1b-89fc-a1827c3ebfa4",
      "x-appminlimit-remaining": "9996",
      "x-minlimit-remaining": "57",
      "x-daylimit-remaining": "4796",
      "expires": "Wed, 22 Sep 2021 03:02:24 GMT",
      "cache-control": "max-age=0, no-cache, no-store",
      "pragma": "no-cache",
      "date": "Wed, 22 Sep 2021 03:02:24 GMT",
      "connection": "close",
      "x-client-tls-ver": "tls1.3"
    },
    "request": {
      "uri": {
        "protocol": "https:",
        "slashes": true,
        "auth": null,
        "host": "api.xero.com",
        "port": null,
        "hostname": "api.xero.com",
        "hash": null,
        "search": "?summarizeErrors=true&unitdp=4",
        "query": "summarizeErrors=true&unitdp=4",
        "pathname": "/api.xro/2.0/CreditNotes",
        "path": "/api.xro/2.0/CreditNotes?summarizeErrors=true&unitdp=4",
        "href": "https://api.xero.com/api.xro/2.0/CreditNotes?summarizeErrors=true&unitdp=4"
      },
      "method": "PUT",
      "headers": {
        "user-agent": "xero-node-4.15.0",
        "xero-tenant-id": "9033f7ba-e92f-4510-bbda-01d4dfa299e9",
        "Authorization": "Bearer  ",
        "accept": "application/json",
        "content-type": "application/json",
        "content-length": 397
      }
    }
  },
  "body": {}
}

Please check the response I have posted in error.

There are SERIALIZATION issues 2 here.

  1. You can there are 2 credit notes in the response, but in the code you can see I have added only one CN and there is no way it can be 2 CN from code. I don’t how it became 2 in the response.

  2. You can see the validation error from first credit note which is the one I’m passing to xero. it says "Message": "The description field is mandatory for each line item.". Even in the response data that xero returns has the description value. How it is possible to produce this error idk.

Please help me with these issues I’m stuck here.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
dev-wellicommented, Sep 22, 2021

@sksankarraj Can you contact Xero API Support at api@xero.com with the details of your integration:

  • ClientID of your app
  • Timestamps (and timezone) of the calls that generated the error

We can then check the application’s logs to investigate.

As I think this is not an SDK issue, I’ll close this issue for now.

0reactions
RettBehrenscommented, Sep 24, 2021

I am unable to replicate the issue using Xero-Node v4.15.0.

With each release that adds new methods we add those methods to our kitchen sink sample app and test those calls to verify functionality. https://github.com/XeroAPI/xero-node-oauth2-app

In the past 30 days Xero-Node users have made: POST: 4,963,388 API calls PUT: 2,159,183 API calls

I’ve tested using two of our sample apps:

Node and Express without TypeScript https://github.com/XeroAPI/xero-node-serializer-test

Node and Express with TypeScript https://github.com/XeroAPI/xero-node-oauth2-ts-starter

serializer call:  {
  Invoices: [
    {
      Type: 'ACCREC',
      Contact: [Object],
      LineItems: [Array],
      Date: '2021-09-24',
      DueDate: '2021-09-25',
      LineAmountTypes: undefined,
      InvoiceNumber: undefined,
      Reference: undefined,
      BrandingThemeID: undefined,
      Url: undefined,
      CurrencyCode: undefined,
      CurrencyRate: undefined,
      Status: undefined,
      SentToContact: undefined,
      ExpectedPaymentDate: undefined,
      PlannedPaymentDate: undefined,
      CISDeduction: undefined,
      CISRate: undefined,
      SubTotal: undefined,
      TotalTax: undefined,
      Total: undefined,
      TotalDiscount: undefined,
      InvoiceID: undefined,
      RepeatingInvoiceID: undefined,
      HasAttachments: undefined,
      IsDiscounted: undefined,
      Payments: undefined,
      Prepayments: undefined,
      Overpayments: undefined,
      AmountDue: undefined,
      AmountPaid: undefined,
      FullyPaidOnDate: undefined,
      AmountCredited: undefined,
      UpdatedDateUTC: undefined,
      CreditNotes: undefined,
      Attachments: undefined,
      HasErrors: undefined,
      StatusAttributeString: undefined,
      ValidationErrors: undefined,
      Warnings: undefined
    }
  ]
}
localVarRequestOptions:  {
  method: 'PUT',
  qs: {},
  headers: {
    'user-agent': 'xero-node-4.15.0',
    'xero-tenant-id': '07f32319-daaf-4548-b589-d6f06f7b407f'
  },
  uri: 'https://api.xero.com/api.xro/2.0/Invoices',
  useQuerystring: false,
  json: true,
  body: { Invoices: [ [Object] ] }
}
invoices:  [
  Invoice {
    type: 'ACCREC',
    contact: Contact {
      contactID: 'adf801de-a142-4670-906f-0d46c5d7c693',
      contactNumber: undefined,
      accountNumber: undefined,
      contactStatus: 'ACTIVE',
      name: 'Gable Print',
      firstName: undefined,
      lastName: undefined,
      emailAddress: '',
      skypeUserName: undefined,
      contactPersons: [],
      bankAccountDetails: '',
      taxNumber: undefined,
      accountsReceivableTaxType: undefined,
      accountsPayableTaxType: undefined,
      addresses: [Array],
      phones: [Array],
      isSupplier: false,
      isCustomer: true,
      defaultCurrency: undefined,
      xeroNetworkKey: undefined,
      salesDefaultAccountCode: undefined,
      purchasesDefaultAccountCode: undefined,
      salesTrackingCategories: [],
      purchasesTrackingCategories: [],
      trackingCategoryName: undefined,
      trackingCategoryOption: undefined,
      paymentTerms: undefined,
      updatedDateUTC: 2021-09-13T18:03:42.080Z,
      contactGroups: [],
      website: undefined,
      brandingTheme: undefined,
      batchPayments: undefined,
      discount: undefined,
      balances: undefined,
      attachments: undefined,
      hasAttachments: undefined,
      validationErrors: undefined,
      hasValidationErrors: false,
      statusAttributeString: undefined
    },
    lineItems: [ [LineItem] ],
    date: 2021-09-24T00:00:00.000Z,
    dueDate: 2021-09-25T00:00:00.000Z,
    lineAmountTypes: 'Exclusive',
    invoiceNumber: 'INV-0055',
    reference: '',
    brandingThemeID: '5d4dd402-c851-497e-aae1-9ff265c0d15a',
    url: undefined,
    currencyCode: 'GBP',
    currencyRate: 1,
    status: 'DRAFT',
    sentToContact: false,
    expectedPaymentDate: undefined,
    plannedPaymentDate: undefined,
    cISDeduction: undefined,
    cISRate: undefined,
    subTotal: 10,
    totalTax: 0,
    total: 10,
    totalDiscount: undefined,
    invoiceID: 'a6a5f183-850a-4e65-84f1-819bc040be6d',
    repeatingInvoiceID: undefined,
    hasAttachments: undefined,
    isDiscounted: false,
    payments: undefined,
    prepayments: [],
    overpayments: [],
    amountDue: 10,
    amountPaid: 0,
    fullyPaidOnDate: undefined,
    amountCredited: undefined,
    updatedDateUTC: 2021-09-24T17:53:08.470Z,
    creditNotes: undefined,
    attachments: undefined,
    hasErrors: false,
    statusAttributeString: undefined,
    validationErrors: undefined,
    warnings: undefined
  }
]
serializer call:  {
  Contacts: [
    {
      ContactID: undefined,
      ContactNumber: undefined,
      AccountNumber: undefined,
      ContactStatus: undefined,
      Name: 'Bruce Banner',
      FirstName: undefined,
      LastName: undefined,
      EmailAddress: 'hulk@avengers.com',
      SkypeUserName: undefined,
      ContactPersons: undefined,
      BankAccountDetails: undefined,
      TaxNumber: undefined,
      AccountsReceivableTaxType: undefined,
      AccountsPayableTaxType: undefined,
      Addresses: undefined,
      Phones: [Array],
      IsSupplier: undefined,
      IsCustomer: undefined,
      DefaultCurrency: undefined,
      XeroNetworkKey: undefined,
      SalesDefaultAccountCode: undefined,
      PurchasesDefaultAccountCode: undefined,
      SalesTrackingCategories: undefined,
      PurchasesTrackingCategories: undefined,
      TrackingCategoryName: undefined,
      TrackingCategoryOption: undefined,
      PaymentTerms: undefined,
      UpdatedDateUTC: undefined,
      ContactGroups: undefined,
      Website: undefined,
      BrandingTheme: undefined,
      BatchPayments: undefined,
      Discount: undefined,
      Balances: undefined,
      Attachments: undefined,
      HasAttachments: undefined,
      ValidationErrors: undefined,
      HasValidationErrors: undefined,
      StatusAttributeString: undefined
    }
  ]
}
localVarRequestOptions:  {
  method: 'PUT',
  qs: {},
  headers: {
    'user-agent': 'xero-node-4.15.0',
    'xero-tenant-id': '07f32319-daaf-4548-b589-d6f06f7b407f'
  },
  uri: 'https://api.xero.com/api.xro/2.0/Contacts',
  useQuerystring: false,
  json: true,
  body: { Contacts: [ [Object] ] }
}
contacts:  [
  Contact {
    contactID: '4e0ad2b8-f80c-42e6-bd1f-0a910b342317',
    contactNumber: undefined,
    accountNumber: undefined,
    contactStatus: 'ACTIVE',
    name: 'Bruce Banner',
    firstName: undefined,
    lastName: undefined,
    emailAddress: 'hulk@avengers.com',
    skypeUserName: undefined,
    contactPersons: [],
    bankAccountDetails: '',
    taxNumber: undefined,
    accountsReceivableTaxType: undefined,
    accountsPayableTaxType: undefined,
    addresses: [ [Address], [Address] ],
    phones: [ [Phone], [Phone], [Phone], [Phone] ],
    isSupplier: false,
    isCustomer: false,
    defaultCurrency: undefined,
    xeroNetworkKey: undefined,
    salesDefaultAccountCode: undefined,
    purchasesDefaultAccountCode: undefined,
    salesTrackingCategories: [],
    purchasesTrackingCategories: [],
    trackingCategoryName: undefined,
    trackingCategoryOption: undefined,
    paymentTerms: undefined,
    updatedDateUTC: 2021-09-24T17:54:19.280Z,
    contactGroups: [],
    website: undefined,
    brandingTheme: undefined,
    batchPayments: undefined,
    discount: undefined,
    balances: undefined,
    attachments: undefined,
    hasAttachments: undefined,
    validationErrors: undefined,
    hasValidationErrors: false,
    statusAttributeString: undefined
  }
]

I understand your frustration and I’m keen to help get you unstuck. If you could, please try to replicate your issue using one of the two above sample repos and submit a PR to the repo

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jquery serialize & @RequestBody not working - Stack Overflow
My question is whenever I am using @RequestBody annotation within the below controller method, the ajax call never invokes this method but ...
Read more >
SerializationException when serializing request body object of ...
The problem by the looks of it is that within the JsonFeature it picks the serializer based on bodyInstance::class.serializer() which does not work...
Read more >
Serialization and Deserialization Issues in Spring REST
Serialization and Deserialization Issues in Spring REST ... from REST APIs and deserializes complex type parameters like @RequestBody .
Read more >
Reactive REST client: Request body not serialized to JSON for ...
The request body object should be serialized to JSON. Actual behavior. toString() gets called on the request body object. How to Reproduce?
Read more >
Jackson JSON Request and Response Mapping in Spring Boot
Prevent Failure on Unknown Property in JSON Request Body ... Converting the Java Object to JSON is known as Marshalling or Serialization.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found