Serizalization not working on smart collections

Hi team,

I’m facing a problem with a smart collection using the RecordSerializer.

I’m getting my data from an external API, I can print the result but the output from the serialize method is empty.

Here is my code with the url and credentials hidden (routes/merchants.js):

router.get('/merchants', async (request, response, next) => {
  const res = await axios.post('https://api.xxxxx.io/client/signin', { login: "xxxxx", password: "xxxxx" })
  const merchantsList = await axios.get('https://api.xxxxx.io/cashback/merchants', { headers: { 'api-token': 'xxxxx', 'jwt-token': res.data.jwtToken }});
  const merchantsSerializer = new RecordSerializer({ name: 'merchants' });
  const merchants = await merchantsSerializer.serialize(merchantsList);
  response.send({ ...merchants });

Here is my collection (forest/merchants.js):

const { collection } = require('forest-express-sequelize');

collection('merchants', {
  isSearchable: false,
  fields: [{
    field: 'merchantId',
    type: 'Number',
  }, {
    field: 'isActive',
    type: 'Boolean',
  }, {
    field: 'name',
    type: 'String',
  }, {
    field: 'category',
    type: 'String',
  }, {
    field: 'description',
    type: 'String',
  }, {
    field: 'condition',
    type: 'String',
  }, {
    field: 'image',
    type: 'String',
  }, {
    field: 'websiteUrl',
    type: 'String',
  }, {
    field: 'activationUrl',
    type: 'String',
  }, {
    field: 'online',
    type: 'Boolean',
  }, {
    field: 'addresses',
    type: '[\'String\']',
  }, {
    field: 'externalMerchantSource',
    type: 'String',
  }, {
    field: 'externalMerchantId',
    type: 'String',
  }, {
    field: 'systemAdditionalField',
    type: 'String',
  }, {
    field: 'clientComissionInPercent',
    type: 'Number',
  }, {
    field: 'balanceAlertingAmount',
    type: 'Number',
  }, {
    field: 'balanceAlertingEmails',
    type: '[\'String\']',
  }],
});

Finally, here is the result of the merchants value from the serialize method:
{ data: { type: 'merchants' } }

Is there a solution to fix this ? Am I missing something from the documentation ?

Hi @Hsohm,

You will find here an explanation with examples about the input format for the serializer.

I suggest to start with a minimal model with just the id and the name.

Let me know if that helps.

Regards

I already followed this documentation for my project.

I tried with the name and the merchantId only but the result is still the same, empty…

Hello @Hsohm,

Would you mind sharing the response from const merchantsList = await axios.get(...?
This may come from a data format incompatibility between your records and what is expected by our serialiser.

Thank you.

Hello @anon79585656,

Here is the output of merchantsList wrapped:

{[
    {
        createdAt: '2021-06-23T07:49:02.580Z',
        merchantId: 2302,
        isActive: true,
        name: 'TITI',
        category: 'TOTO',
        description: 'Lorem Ipsum',
        condition: 'Lorem Ipsum',
        image: 'https://static.xxxxxxx.htmal1.com/logos190_90/logo-6111.gif',
        activationUrl: 'https://xxxxxxx.xxxxxx.xxxxxx.xxx/cashback/activate/xxxxxx/129143',
        online: true,
        externalMerchantSource: 'TATA',
        externalMerchantId: '129143',
        amount: 1000000,
        clientComissionInPercent: 30,
        clientId: 21,
        addresses: [],
        rules: [Array] },
      ... 445 more items ] }

A quick shot.

I see a pair of curly brackets in your last response. Is it really there or is that due to how you logged the data? If it is there, please remove it, the serialiser expects an array.

Also there is no id in you data. Is one of your fields set as a primary key?

Can you tell me your project name, and on which environment you are working so I can look a bit deeper in the configuration on our side?

Thank you

Yes I reworked the indentation because there is too many elements, I don’t have the beginning of the logs.

About the ID it’s not set as a primary key, could solve the problem ? How to define a value as the Id ?

I’m on macOs with forest-express-sequelize version 7.0.0

@Hsohm, I was talking about the name for your ForestAdmin project and environment (“production”, “dev”… you can see it in the top left of ForestAdmin).

Regarding the log, it would really help to have it all.
Can you try something like

console.dir(merchantsList, { depth: null });

Or (first item only):

console.dir(merchantsList[0], { depth: null });

Thanks

The project name is “sponsoplus-admin” in development.

The first value is the list of the merchants but the second value is undefined.

Here is an example of the first console.dir:

{
      createdAt: '2021-06-23T07:49:02.580Z',
      merchantId: 2302,
      isActive: true,
      name: "xxxx",
      category: 'xxxx',
      description: "xxxx",
      condition: "xxxx',
      activationUrl: 'xxxx',
      online: true,
      externalMerchantSource: 'xxxx',
      externalMerchantId: '129143',
      amount: 1000000,
      clientComissionInPercent: 30,
      clientId: 21,
      addresses: [],
      rules: [
        {
          createdAt: '2021-06-23T07:49:02.651Z',
          cashbackRuleId: 1497,
          isActive: true,
          description: 'xxxx',
          rules: [
            '(^| )kiehls($| )',
            '(^| )kiehl($| )',
            '(^| )kieh($| )',
            '(^| )kie($| )'
          ],
          merchantId: 2302,
          isCashbackDynamic: false,
          cashbackType: 'PERCENTAGE',
          cashbackAmount: 5.2,
          cashbackAmountMin: 0,
          cashbackAmountMax: 1000000,
          condition_name: 'NONE',
          condition_params: 0,
          dateStart: '2021-04-02 07:57:36',
          dateEnd: '2349-12-31 23:00:00',
          externalRuleSource: 'xxxx',
          externalRuleId: '416733'
        }
      ]
    },
    ... 445 more items
  ]

I think I’m missing the id value but how to define it when it’s not present in the api response ?

@Hsohm,

Thank you for the details.

Per the doc, in this (sightly hidden) snippet,

You MUST declare an id field when creating a Smart Collection. The value of this field for each record MUST be unique.

You have to add an ID to your records. Adding it to the records seems to be enough, no need to change your collection definition.

A fast way to do it can be to require the uuid module and modify your code like that:

const { v1: uuidv1 } = require('uuid');

// .....

router.get('/merchants', async (request, response, next) => {
  const res = await axios.post('https://api.xxxxx.io/client/signin', { login: "xxxxx", password: "xxxxx" })
  const merchantsList = await axios.get('https://api.xxxxx.io/cashback/merchants', { headers: { 'api-token': 'xxxxx', 'jwt-token': res.data.jwtToken }});

  // <--------
  merchantsList.forEach((merchant) => { merchant.id = uuidv1(); });
  // <--------

  const merchantsSerializer = new RecordSerializer({ name: 'merchants' });
  const merchants = await merchantsSerializer.serialize(merchantsList);
  response.send({ ...merchants });
});

Let me know if this works.

1 Like

That was my mistake, I solved this by adding a uuid as u said and here is the final code working:

router.get('/merchants', async (request, response, next) => {
  const { data } = await axios.get('https://api.xxxxx.xx/cashback/merchants', { headers: { 'api-token': 'xxxxxxxx' }});
  data.forEach((merchant) => { merchant.id = uuidv1(); });
  const merchantsSerializer = new RecordSerializer({ name: 'merchants' });
  const merchants = await merchantsSerializer.serialize(data);
  response.send({ ...merchants });
});

I replaced merchantsList by { data } because axios doesn’t return only the data, there is more informations that we don’t need/use and can’t iterate on this.

I found a new solution with less compute for the back-end using the get option on the collection in the forest directory.

Here is the solution to use an existing ID as primary ID:

collection('merchants', {
  isSearchable: true,
  fields: [{
    field: 'id',
    type: 'String',
    get: record => record.merchantId
  }, {
    field: 'merchantId',
    type: 'Number',
  }],
});
1 Like