Sling Academy
Home/Node.js/Node.js + Express: How to return CSV files

Node.js + Express: How to return CSV files

Last updated: December 30, 2023

Introduction

In modern web applications, the ability to export data in a CSV (Comma-Separated Values) format is fundamental for users who need to perform further data analysis alongside their workflows. Node.js partnered with Express.js framework simplifies the process of sending CSV files to the client. In this tutorial, I will guide you through multiple examples detailing how to return CSV files from an Express server using latest Node.js and JavaScript/TypeScript features.

We will start with the basic setup of an Express server, move to serving a simple CSV file, and progressively delve into more advanced topics such as generating dynamic CSV content, setting proper headers, and streamlining the CSV file generation and delivery for efficiency and scalability.

Setting Up Your Project

// set up our Express application
import express from 'express';

const app = express();
const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is running on port: ${PORT}`);
});

First, ensure you have Node.js installed on your computer. Create a new directory for your project, initialize your node environment with ‘npm init -y’ and install Express with ‘npm install express’. Then, create an ‘index.js’ file with the above code snippet.

sending a simple CSV file

For the most basic example, let’s return a static CSV file that’s stored on the server.

// defining your Express route for downloading CSV
app.get('/downloadCSV', (req, res) => {
  res.download('path/to/your/staticfile.csv');
});

This route simply triggers a file download when a GET request is made to ‘/downloadCSV’. The ‘res.download()’ function is straightforward and handles setting the right headers internally.

Generating dynamic content

More often, you’ll want to return CSV files with dynamic content based on data in a database or some in-memory data structure. Here you’ll utilize libraries such as ‘csv-writer’.

// using async/await along with arrow functions for a dynamic CSV
import { createObjectCsvWriter } from 'csv-writer';

app.get('/dynamicCSV', async (req, res) => {
  const csvWriter = createObjectCsvWriter({
    path: 'path/to/dynamic.csv',
    header: [
      {id: 'name', title: 'NAME'},
      {id: 'lang', title: 'LANGUAGE'}
    ]
  });

  const records = [
    { name: 'John', lang: 'JavaScript' },
    { name: 'Arthur', lang: 'Python' }
  ];

  await csvWriter.writeRecords(records);
  res.download('path/to/dynamic.csv');
});

In the above route, we utilize ‘csv-writer’ to create CSV content dynamically from an array of objects. Here the ‘writeRecords’ function is asynchronous and returns a promise, which you can wait to resolve with ‘await’ before sending the actual file with the ‘res.download()’ method.

Streaming CSV files

Building on the previous examples, streaming the CSV data becomes necessary when working with large datasets. It’s increasingly valuable as it reduces memory overhead. Node.js streams fit in perfectly, optionally with a library like ‘fast-csv’.

// setting proper headers for a CSV response
app.get('/streamCSV', (req, res) => {
  res.setHeader('Content-disposition', 'attachment; filename=computedData.csv');
  res.writeHead(200, { 'Content-Type': 'text/csv' });

  // Stream some CSV content to HTTP response
  fastcsv
    .write(records, { headers: true })
    .pipe(res);
});

This uses the streaming APIs of ‘fast-csv’ to pipe the CSV data directly into the HTTP response object accompanied by the appropriate headers and HTTP status code.

Advanced error handling

You should also consider error handling to cater for the unexpected, particularly when dealing with files or data fetched from external sources. This maintains robustness and reliability of your API endpoint.

// advanced error management
app.get('/errorManagedCSV', async (req, res) => {
  try {
    // assume data fetching and CSV writing as previous examples
    await SomeDataFetchingFunction();
    await PossibleCsvWritingMethod();

    res.download('path/to/data.csv');
  } catch (error) {
    console.error(error);
    res.status(500).send('Internal Server Error');
  }
});

Conclusion

To wrap up, returning CSV files from an Express application can meet various degrees of complexity based on your project’s needs. Whether you’re serving static CSVs or riding the bleeding edge with dynamically generated, streamed, and memory-efficient datasets, Node.js and Express, armed with the right libraries and streaming APIs provides you a robust groundwork. As of importance, test comprehensively especially for error scenarios and edge-cases to ensure user reliability and enhance experience. Happy Coding!

Next Article: Express + Handlebars: How to Include Subviews

Previous Article: Node.js + Express: How to return text files

Series: Node.js & Express Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates