Reputation: 25
Hello im trying to send a response from a post req that includes download attachment. I get the correct response, but no download or save-as pop up. I checked and headers are correctly set. Im using express, mongodb, mongoose, and nextjs. This controller function takes a start and end date from the request and queries collection. cvsReadStream streams to csv table format and then pipes to response.
controller:
exports.postExportApplications = (req, res, next) => {
const startDate = new Date(req.body.startDate)
const endDate = new Date(req.body.endDate)
const fileName = `${moment(startDate).format('MM-DD-YYYY')}-${moment(endDate).format('MM-DD-YYYY')}-Applications.csv`
if (req.session.user) {
res.attachment(fileName)
return Application.find({ dateTime: { $gte: startDate, $lte: endDate } } )
.sort({ dateTime: 1 })
.then(applications => {
Application.csvReadStream(applications)
.pipe(res)
})
} else {
return res.sendStatus(401);
}
}
response headers:
Connection: keep-alive
Content-Disposition: attachment; filename="12-13-1994-12-20-2020-Applications.csv"
Content-Type: text/csv; charset=utf-8
Date: Sat, 14 Dec 2019 22:42:10 GMT
Strict-Transport-Security: max-age=15552000; includeSubDomains
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-DNS-Prefetch-Control: off
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
form component:
import React, { useState } from 'react'
import InputMask from 'react-input-mask'
const ExportAppsForm = (props) => {
const defaultData = {
startDate: { value: '', error: false },
endDate: { value: '', error: false },
}
const [form, setform] = useState(defaultData)
const handleChange = (event) => {
const target = event.target
const name = target.name
setform({
...form,
[name]: target.value
})
}
const submitform = () => {
props.handleFormSubmit({...form})
}
return (
<form encType="multipart/form-data">
<div className="form-row">
<div className="form-group col-md-4">
<label htmlFor="year">Start Date:</label>
<InputMask
mask="99/99/9999"
onChange={handleChange}
value={form.startDate}
name="startDate"
className="form-control"
id="startDate"
aria-describedby="emailHelp"
/>
</div>
<div className="form-group col-md-4">
<label htmlFor="make">End Date:</label>
<InputMask
mask="99/99/9999"
onChange={handleChange}
value={form.endDate}
name="endDate"
className="form-control"
id="endDate"
/>
</div>
</div>
<button onClick={submitform} type="button" className="btn btn-primary">Export Now!</button>
</form>
)
}
export default ExportAppsForm;
axios post request:
export const postExportApplications = (query) => {
return axios.post(`${BASE_URL}/export`, query).then(res => res.data)
}
Upvotes: 0
Views: 1017
Reputation: 789
It looks like you are just making a query to get your data in csv format so an HTTP GET method is the most appropriate for this case since you are not modifying any resources see: http://restcookbook.com/HTTP%20Methods/idempotency/.
So first of all you have to alter your controller to accept the query as query parameters and make a GET request using axios as shown below
export const getCsv = (params) => {
axios({
method: 'GET',
url: '[YOUR_URL_HERE]'
params,
responseType: 'arraybuffer',
headers: {
'Accept': 'text/csv'
}
}).then(response => {
if(response.status === 200 && response){
return response.data;
}
}).catch(error => console.log(error));
}
To download the csv file in your class component Using a package called file-saver
npm i file-saver
and import the package as follows
import { saveAs } from 'file-saver';
In your component you can then use the getCSv function for your onClick handler
funcion onHandleDownload(query) => {
getCsv(query).then(data => {
const blob = new Blob([data], {
type: 'text.csv',
});
saveAs(blob, 'csv_name.csv')
})
}
Upvotes: 1