0

I am creating a project in Node JS and Typescript in which I want to download a CSV with the information that an API contains in JSON format. Given the url http://localhost:3000/?api=api1, I have to read the JSON related to api1.

I have added the modules that I have seen that are necessary but I cannot download the CSV from an external JSON by url.

This is my controller:

import { Request, Response } from 'express';
const converter = require("json-2-csv");
const fetch = require("node-fetch");
const fs = require("fs");
const flatten = require('flat');
    
const conf = require(`../config/${process.env.NODE_ENV}.json`);
    
class IndexController {
    public async index(req: Request, res: Response) {
        const api =req.query.api; //api1
        const url = conf.API_MOCS[`${api}`].url; //https://mocks.free.beeceptor.com/api1 

        const env = process.env.NODE_ENV;
        const nameFile = `${env}.${api}.csv`;

        let json = await axios.get(url);

        const header={
          'index':'Index',
          'integer':'Integer',
          'float': 'Float',
          'name': 'Name'};

        let json2csvCallback = function (err:any, csv:any) {
           if (err) throw err;
           const maxRecords = 50;
           const headers = csv.split('\n').slice(0,1);
           const records = csv.split('\n').slice(0,);
           for(let i=1; i<records.length; i=i+maxRecords) {
                let dataOut = headers.concat(records.slice(i, i+maxRecords)).join('\n');
                let id = Math.floor(i/maxRecords)+1;
                 fs.writeFileSync(`${dir}/${nameFile}.${id}.csv`, dataOut);
            }
        };

        converter.json2csv(json.data.items, json2csvCallback);
    }
}
export const indexController = new IndexController(); 

In a file I have stored the URL where the information is in JSON, which I read with the variable (url), how can I download the information from that URL in a CSV file with a maximum of 999 lines and save it in src / output?

menphis
  • 85
  • 1
  • 8

1 Answers1

0

You can call that url using axios or request, after getting the JSON in response you can use https://www.npmjs.com/package/json2csv to convert JSON to csv.

import { Request, Response } from 'express';
const converter = require("json-2-csv");
const fetch = require("node-fetch");
const axios = require('axios');
const fs = require("fs");
const flatten = require('flat');
    
const conf = require(`../config/${process.env.NODE_ENV}.json`);
    
class IndexController {
    public async index(req: Request, res: Response) {
        const api =req.query.api; //api1
        const url = conf.API_MOCS[`${api}`].url; //https://mocks.free.beeceptor.com/api1 
        console.log("Getting JSON ...");
        let json = await axios.get("https://mocks.free.beeceptor.com/api1");
        console.log("JSON Fetched ...");
        const header={
        'index':'Index',
        'index_start_at':'Index start',
         'integer':'Integer',
        'float': 'Float',
        'name': 'Name'};
        converter.json2csv([header,...json.data.items], (err:any, csv:any) => {
            if (err) {
                 throw err;
            }
            console.log("Making CSV ...");
            fs.writeFileSync("file.csv",csv);
            console.log("CSV File Is Ready...");

         });    
    }
}
export const indexController = new IndexController(); 
Pawan Bishnoi
  • 1,759
  • 8
  • 19
  • I have used the json-2-csv and node-fecth module for the request requests. But it shows me the following errors: ``Parameter 'err' implicitly has an 'any' type``. and ``Parameter 'csv' implicitly has an 'any' type``. I don't know if this is the correct way to do it. – menphis Jun 05 '21 at 18:59
  • Hi @menphis have a quick look to this article https://attacomsian.com/blog/nodejs-convert-json-to-csv, if it still didn't work out then let me know we can write manual code for it. – Pawan Bishnoi Jun 06 '21 at 03:43
  • I had already seen that article but I can't get it to work, the problem is that it obtains the JSON from an internal file, I am trying to collect it from an external url – menphis Jun 06 '21 at 08:35
  • If you are getting JSON from external API then you can store it in a variable and after that you can pass that variable containing JSON to this NPM module's function. – Pawan Bishnoi Jun 06 '21 at 10:38
  • But I don't know how to store the information that the JSON contains, I can only save in the url variable the address where that JSON is located – menphis Jun 06 '21 at 10:47
  • Are you using axios to call the API ? – Pawan Bishnoi Jun 06 '21 at 10:51
  • I think you are not calling the API, use this https://www.npmjs.com/package/axios package to call the API then you will get the JSON data and then you can convert the JSON data to CSV. – Pawan Bishnoi Jun 06 '21 at 10:53
  • I am using ``node-fetch``, I have updated the question with the code I do not know if it is like this – menphis Jun 06 '21 at 10:54
  • Are you getting JSON data after calling the API using node-fetch, url you mentioned in code comment i.e http://mock.com/api1 not returning any JSON. – Pawan Bishnoi Jun 06 '21 at 10:57
  • I have put a log: ``console.log (responseJson);`` and it returns ``[object Object]`` – menphis Jun 06 '21 at 11:01
  • Use console.log (JSON.stringify(responseJson)) and let me know. – Pawan Bishnoi Jun 06 '21 at 11:02
  • Ok yes, it does return the JSON – menphis Jun 06 '21 at 11:04
  • Now you can use this JSON to convert it into CSV using earlier used NPM. – Pawan Bishnoi Jun 06 '21 at 11:05
  • I don't know how to convert it to CSV using the ``json-2-csv`` module, which is the one I have installed – menphis Jun 06 '21 at 11:09
  • Read this https://attacomsian.com/blog/nodejs-convert-json-to-csv page quickly and pass your responseJSON to the converter function instead of the todos. This will return csv string and you can write that csv sting into a .csv file with the help of FS module. – Pawan Bishnoi Jun 06 '21 at 11:11
  • I have updated the question with the new function. But it returns two errors: ``Parameter 'err' implicitly has an 'any' type`` and ``Parameter 'csv' implicitly has an 'any' type.`` – menphis Jun 06 '21 at 11:15
  • Use the callback function like this (err:any, csv:any) => { if (err) { throw err; } console.log(csv); } – Pawan Bishnoi Jun 06 '21 at 11:17
  • It shows me the following error: ``Error: Data provided was not an array of documents.`` – menphis Jun 06 '21 at 11:20
  • Ohh, it means you received single JSON object in response of API call just put it in array and try again. Like :- converter.json2csv([getJson], (err:any, csv:any) => { if (err) { throw err; } console.log(csv); }); – Pawan Bishnoi Jun 06 '21 at 11:22
  • I receive the empty csv information, it does not collect any data – menphis Jun 06 '21 at 11:27
  • Can you share the URL you calling to get JSON data. – Pawan Bishnoi Jun 06 '21 at 11:28
  • https://mocks.free.beeceptor.com/api1: When I enter Postman ``http://localhost:3000/?api=api1`` I have to download the information from ``https://mocks.free.beeceptor.com/api1`` – menphis Jun 06 '21 at 11:31
  • Okay this API returning a JSON Object having "items" array so you have to call the function like this:- converter.json2csv(getJson.items, (err:any, csv:any) => { if (err) { throw err; } console.log(csv); }); – Pawan Bishnoi Jun 06 '21 at 11:35
  • Where do I declare the ``items`` variable? – menphis Jun 06 '21 at 11:37
  • You don't have to declare it when you call https://mocks.free.beeceptor.com/api1 this API it returns a JSON Object and that JSON Object containing a "items" array, so you can access that `items` array using `.` notation. – Pawan Bishnoi Jun 06 '21 at 11:40
  • I can't do this anymore, if it works for you, you can put this part for me because I can't read the csv – menphis Jun 06 '21 at 11:48
  • I still cannot access the ``getJson`` data, I have tried with all the notations but I don't know how to continue anymore – menphis Jun 06 '21 at 12:25
  • You have to call the getJson function like this :- converter.json2csv(getJson().items, (err:any, csv:any) => { if (err) { throw err; } console.log(csv); }); – Pawan Bishnoi Jun 06 '21 at 12:31
  • Yes that's how I'm calling it but it just lets me put ``getJson().then``, ``getJson().catch`` or ``getJson().finally``. Can you download the CSV from that url? – menphis Jun 06 '21 at 12:35
  • How can i download CSV, i didn't have whole code. This is very simple problem if you are not able to resolve the issue then last thing i can do is share your screen to me using anydesk i can check what is going wrong there. – Pawan Bishnoi Jun 06 '21 at 12:40
  • This is the code that I have in addition to the server. The only thing I need here is to download a CSV with the information in JSON that contains that url but I can't do it – menphis Jun 06 '21 at 12:42
  • If i change the code for JS then can you change it according to TS ? – Pawan Bishnoi Jun 06 '21 at 12:45
  • I do not understand, I'm using typescript right now, I don't know if that changes anything – menphis Jun 06 '21 at 12:53
  • I have edited your code in my answer just copy and paste it in your file and before running it install axios using `npm i axios`. – Pawan Bishnoi Jun 06 '21 at 12:58
  • What is the difference between ``axios`` and ``node-fetch``? – menphis Jun 06 '21 at 13:00
  • Axios supports async-await syntax and it's trend now a days. Let me know if this worked for you or not. – Pawan Bishnoi Jun 06 '21 at 13:02
  • Yes, now I do work with axios. Now I need to do something else: that the CSV has a limit of 999 lines and the rest in other CSVs all with a limit of 999. And I have created a constant with the headers but I don't know how to apply them to the CSV. I have updated the question – menphis Jun 06 '21 at 13:31
  • I have updated the code, I can already limit the number of lines in the CSV, but how can I apply the headers? – menphis Jun 06 '21 at 14:15
  • To apply headers you can create an array like this let array =[headersObject,...items]. And now pass this array to the csv convertor function. By this CSV file will have headers in 2nd line and after those other values row by row. – Pawan Bishnoi Jun 06 '21 at 14:50
  • I have created a ``header`` variable, I don't know if I have to create it like this but I don't understand how to apply it – menphis Jun 06 '21 at 14:57
  • Create a JSON object having all keys like other objects for e.x {name:"Name",id:"ID",float:"Float"} now put this object in items array's 1st index like i told in previous comment and then pass that array to convertor function, then 1st line of CSV will be id,name,float etc. 2nd line will be ID,Name,Float etc and further lines will have original values after downloading csv file you can delete 1st line manually and your file will now have header as you wanted. – Pawan Bishnoi Jun 06 '21 at 15:17
  • I understand how to do it but not how to apply it to my code, can you put the code? I have the JSON declared but I can't get the title from the variable – menphis Jun 06 '21 at 15:20
  • I have edited my code, try it out i hope it works. – Pawan Bishnoi Jun 06 '21 at 15:30
  • Now I get a 429 error, too many requests (axios), I have never seen this error, I don't know why – menphis Jun 06 '21 at 15:42
  • Because the mock api provider have a limit for free api calls and today's quota is expired for free api calls, you can always verify these errors by calling this url in browser. – Pawan Bishnoi Jun 06 '21 at 15:46
  • I have added another api with a JSON but now I get an error in json2csv, I don't understand this because the module is imported: ``Error: Cannot call json2csv on undefined.`` – menphis Jun 06 '21 at 15:58
  • Look previous api was giving us an object having array items, the new api maybe returning different type of object you have to check the structure of response in browser or console first then change the implementation accordingly. – Pawan Bishnoi Jun 06 '21 at 16:01
  • You are right, the JSON it returns is different, I will leave the headers applied, I will find a way to create a directory in Node to store the files and I will test everything tomorrow if the api works – menphis Jun 06 '21 at 16:06
  • I have created a ``headers`` variable inside the ``json2csvCallback`` function but I am having trouble applying the ``header`` ``JSON`` instead of that variable. – menphis Jun 07 '21 at 08:43
  • Because csv is already generated in callback function, so you can not apply headers in callback function. – Pawan Bishnoi Jun 07 '21 at 08:53
  • And how can I define the header in the ``json2csvcallback`` function? – menphis Jun 07 '21 at 09:00