zemirco / json2csv

Convert json to csv with column titles
http://zemirco.github.io/json2csv
MIT License
2.71k stars 364 forks source link

Data transforms error handling #574

Open CarlosVilasAlvarez opened 2 years ago

CarlosVilasAlvarez commented 2 years ago

Hi, I'm having some trouble handling errors caused on data transform functions. json2csv: 5.0.7 Node v16.13.2

When you run this code

const { AsyncParser } = require('json2csv');
const { Readable } = require('stream');

const mockData = [
  {
    id: 1,
    name: 'John',
    surname: 'Doe',
  },
  {
    id: 2,
    name: 'Jane',
    surname: 'Doe',
  }
];

const mockDataStream = Readable.from(mockData);

const dataTransform = (data) => {
  if (data.name === 'Jane') throw new Error('Unhandled error');
  return data;
};

const asyncParser = new AsyncParser({ transforms: [dataTransform] }, { objectMode: true });

try {
  const parsingProcessor = asyncParser.fromInput(mockDataStream).toOutput(process.stdout);
  parsingProcessor.promise(false).catch(err => {
    console.log('Something happened');
  });
} catch (error) {
  console.log('Hello?');
}

You cannot handle the exception, it'll be an unhandledException one.

Screenshot 2022-09-20 at 15 40 36

Only approach that works is to put a try catch inside the data transform function like this.

const dataTransform = (data) => {
  try {
    if (data.name === 'Jane') throw new Error('Unhandled error');
    return data;
  } catch (error) {
    return undefined;
  }
};
juanjoDiaz commented 2 years ago

This does not happen in v6 which was just published as a separate package: https://www.npmjs.com/package/@json2csv/node

Although, the API has changed to make the async api more similar than the other. Also, when piping to an output stream the promise method has been removed since it's trivial to wait for the end event and node nowadays even provides the pipeline method for that. In v6 you can do:

const { pipeline } = require('node:stream/promises');

// ...

try {
  pipeline(asyncParser.parse(mockDataStream), process.stdout).catch(err => {
    console.log('Something happened');
  });
} catch (error) {
  console.log('Hello?');
}

or using the transform

const json2csvTransform = new Transform({ transforms: [dataTransform] }, { objectMode: true });

try {
  pipeline(mockDataStream, json2csvTransform, process.stdout).catch(err => {
    console.log('Something happened');
  });
} catch (error) {
  console.log('Hello?');
}

I haven't tested the code. It's just a quick guidelines. If you have more issues with it I can look deeper into it.

CarlosVilasAlvarez commented 2 years ago

Thank you @juanjoDiaz I didn't know that package existed, is this repo "deprecated" then? I think I'll just migrate all the code from v5 to the new v6.

juanjoDiaz commented 2 years ago

Yup. I'd consider it deprecated. And I think that you'd do well moving to v6 🙂