0

I am generating an excel file and want it to be downloaded for the client by triggering an API route using the Next.js framework. I am having trouble triggering the download by using fetch. The download can be triggered by window.open(//urlhere, '_self') but the API call using fetch gives this response on request:

API resolved without sending a response for /api/download?Students= this may result in stalled requests.

The excel4node documentation says we can send an excel document through an API like this:

// sends Excel file to web client requesting the / route
// server will respond with 500 error if excel workbook cannot be generated
var express = require('express');
var app = express();
app.get('/', function(req, res) {
  wb.write('ExcelFile.xlsx', res);
});
app.listen(3000, function() {
  console.log('Example app listening on port 3000!');
});

Here is my backend download.js which lives in pages/api/:

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import Link from "next/link";
import getPartners from "../../components/main";
import excel from "excel4node";

export default function handler(req, res) {
  const students = req.query.Students.split(",");
  const partners = JSON.stringify(getPartners(students));
  let workbook = createExcelList(partners);
  workbook.write("PartnerList.xlsx", res);
}

const createExcelList = (partnersJSON) => {
  const workbook = new excel.Workbook();
  const partnersObject = JSON.parse(partnersJSON);
  
 /* Using excel4node a workbook is generated formatted the way I want */
  return workbook;
};

export const config = {
  api: {
    bodyParser: true,
  },
};

And here is the function that is triggered on a button press in the front end.

  const makePartners = async () => {
    let queryStudents = studentList.join(",");
    const url = "http://localhost:3000/api/download?Students=" + queryStudents;
    if (studentList.length !== 0) {
      try {
        const res = await fetch(url, {
          headers: {
            "Content-Type":
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          },
        });
        console.log(res);
      } catch (e) {
        console.log(e);
      }
    }
  };

Which does not trigger the download. But using window.open(url, '_self) does. So, I can trigger the download by changing the function to the following. However I don't think this is the correct way of doing things and would like to be able to understand how to use fetch correctly.

  const makePartners =  () => {
    let queryStudents = studentList.join(",");
    const url = "http://localhost:3000/api/download?Students=" + queryStudents;
    if (studentList.length !== 0) {
       window.open(url, "_Self");
    }
  };

I am not sure if this is a Next.js issue or not. Does anyone have any insight? Any help would be appreciated.

juliomalves
  • 42,130
  • 20
  • 150
  • 146
  • Does adding `res.end();` as the last statement in your `handler` function in `/pages/api/download` fix the issue? – juliomalves Jan 03 '21 at 14:14
  • Unfortunately not. If I add ```res.end()``` I get a different error however: ```Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:518:11)``` Thanks for the suggestion though. – Jack_Krebsbach Jan 03 '21 at 14:24

0 Answers0