I have an express/node app which exposes a GET end point via express router something like /api/user. The response is a JSON and i want to download the JSON to a file when i hit localhost:8080/api/user.
I tried with res.download but not sure how to handle the response data with it. This could be a duplicate question but i cannot find an example especially for this use case.
When the end point is invoked in browser it should prompt for download and then should get downloaded to the default location.
router.route('/user')
.get((req, res) => {
MyService.get().then((result) => { // the get method resolves a promise with the data
// Prompt for download
}).catch((err) => {
console.log(err);
res.status(500).json({
status: 500,
data: err
});
});
});
So i was able to do this in one of the 2 ways below,
router.route('/user')
.get((req, res) => {
MyService.get().then((result) => {
res.attachment('users.csv');
/*or you can use
res.setHeader('Content-disposition', 'attachment; filename=users.csv');
res.set('Content-Type', 'text/csv');*/
res.status(200).send(result);
}).catch((err) => {
console.log(err);
res.status(500).json({
status: 500,
data: err
});
});
});
If I understand correctly, you want to save the sent data of /api/user to a file that you are sending in a route?
var fs = require('fs')
app.get("/api/user", function(req, res){
var data = fromDb()
fs.writeFileSync("/tmp/test", JSON.stringify(data))
res.send(data)
})
You need to write the JSON response to a file using the node filesystem module. You can check out an example here Writing files in Node.js
If I got you right then You can try Content-Type and Content-disposition headers like below:
res.writeHead(200, {'Content-Type': 'application/force-download','Content-disposition':attachment; filename={your_file_name}.json});
res.end(data);
NOTE :
data in res.end(data) is your json data.
{your_file_name}.json is your actual file name , give it any name.
Related
I'm trying to test an endpoint that should receive a multipart/form-data. I'm sending a collection of images, which i want to process and save on the server or CDN. I'm using Jest, Express and Formidable.
Endpoint
router.post("/videos", async (req, res) => {
new formidable.IncomingForm().parse(req, (err, fields, files) => {
console.log('PARSE FORM');
if (err) {
console.error('Error', err);
throw err
}
console.log('Fields', fields);
console.log('Files', files);
for (const file of Object.entries(files)) {
console.log('FILE', file)
}
});
res.status(200).send('Created Video');
});
Test
describe("Video Endpoints", () => {
it('should create a new timelapse video', done => {
request
.post('/api/videos')
.field('file', 'some random value')
.attach('image', `${__dirname}/__mocks__/image.png`)
.then(res => {
console.log('THEN');
done();
})
});
});
When running the test it doesn't reach the formidable parse method.
If change my my attach method to this...
.attach('image', fs.readFileSync(`${__dirname}/__mocks__/xdebugcurlaccessingwpapi.png`))
It will reach the parse method but it sees the it as field and not a file.
If i make the same request but from my react app using fetch, it works perfectly fine.
What am i doing wrong? Been on this for a few days now lol.
Any help would be great.
Thanks.
I'm not entirely sure why but if you add
.set({connection: 'keep-alive'})
Then it works.
Final solution
request
.post('/api/videos')
.set({connection: 'keep-alive'})
.field('name', 'Richard')
.attach('image', mockImage)
.then(res => {
console.log('THEN');
done();
});
});
Would be good if someone has an understanding to why this is the case.
I think it might close the stream to image but can't be sure.
I'm trying to download a photo through a URL passed as a query string using Express, but every time I try to use it, I get Error: Invalid URI "favicon.ico" Is there a way I can get my browser to stop requesting a favicon? For downloading images, I'm using the image-downloader package (NPM page)
Code:
app.get('/:url', (req, res) => {
let url = req.params.url;
const options = {
url: url,
dest: /path'
};
download.image(options)
.then(({ filename, image }) => {
console.log('File saved to ', filename);
})
.catch((err) => {
console.log(err);
});
res.send("Done");
});
It's probably easiest to just make a route for favicon.ico in your server.
app.get('/favico.ico', (req, res) => {
res.sendStatus(404);
});
Of course, you could actually send a valid icon too if you wanted, but this will at least keep your Express server from showing an error.
FYI, this has nothing to do with the image-downloader. This has to do with the browser requesting a favico.ico icon that it uses to show in the URL bar (and some other places in the browser UI). If your server returns a 404 for favicon.ico, the browser will use a generic icon in its UI.
If you want to make yourself a simple favico.ico, you can go here and it will help you generate one and then you can change the above route to:
app.get('/favico.ico', (req, res) => {
res.sendFile("myfavico.ico");
});
Try using another package like request module. I believe it got this type of things handled.
var fs = require('fs'),
request = require('request');
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.google.com/images/srpr/logo3w.png', 'google.png', function(){
console.log('done');
});
I am using Next.js, Redux, and Express. My page has this code:
static async getInitialProps({store, isServer, pathname, query}) {
const res = await fetch('http://localhost:3001/tutorials');
const tutorials = await res.json();
store.dispatch(tutorialsReceived({tutorials}));
}
I get the React debug error saying my server response is different than my client. It's expecting a very long JSON response (252KB), and the server render is getting cut off incredibly early. I have tried two ways to send the file and am unsure why either would cut short.
// Try 1
server.get('/tutorials', (req, res) => {
fs.createReadStream('./common/content.json').pipe(res);
});
// Try 2
server.get('/tutorials', (req, res) => {
fs.readFile('./common/content.json', 'utf8', function(err, tutorials) {
res.send(tutorials);
});
});
Modifying the file to be smaller like {a:1,b:2,c:3} results in no error for my sanity check.
Looks like express is setting wrong Content-Length header in the response due to which your JSON gets chopped off. You can set it explicitly and that should work.
server.get('/tutorials', (req, res) => {
fs.readFile('./common/content.json', 'utf8', function (err, tutorials){
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(tutorials, 'utf8')
})
res.send(tutorials);
});
});
I have the following problem:
I want to get a static file from another server, and give it back to the user with another content-type header.
The following code works just fine, but I can't figure out a way to change the response header, though.
const request = require('request');
app.get('video', function (req, res) {
request.get('http://anotherurl.com/video-sample.mp4').pipe(res);
});
I tried to do this thing more manually, but the response was very slow.
app.get('video', function (req, res) {
request.get('http://anotherurl.com/video-sample.mp4', function(error, response, body) {
// ...
res.setHeader('content-type', 'image/png');
res.send(new Buffer(body));
});
});
Can you guys help me with that?
Thanks
Just set the response header when the 'response' event fires.
app.get('video', (req, res) => {
request.get('http://anotherurl.com/video-sample.mp4')
.on('response', response => {
res.setHeader('Content-Type', 'image/png');
// pipe response to res
// since response is an http.IncomingMessage
response.pipe(res);
});
});
I have this code
app.get('/imgs/:id', function(req, res) {
// Validate that req.params.id is 16 bytes hex string
// Get the stored image type for this image
var stream = fs.createReadStream(path.join(UPLOAD_PATH, req.params.id));
stream.on("readable", function() {
res.setHeader('Content-Type', "image/jpeg")
stream.pipe(res)
})
stream.on('error', (e) => {
res.redirect(404, "404")
})
});
Now the problem is that I always get an error of
Error: Can't set headers after they are sent.
because I used the res.setHeader function.
However, i don't know how to solve it. Let's say I want to use in a page, that has obviously the res.send() function has well,
the <img src="imgs/pic">, then I must set the header for the this page request to "image/jpeg" because otherwise the browser wouldn't know it's an image and won't show it as one.
What can I do then?
Check Express response document here. Try this code
app.get('/imgs/:id', function (req, res) {
res.sendFile(req.params.id, {root: UPLOAD_PATH, headers: {'Content-Type': 'image/jpeg'}}, function (err) {
if(err) throw err;
else console.log('sent')
})
})