node.js - download files and content from DB to client - node.js

I want to send to the client in the same request files from the dir and some content from the DB.
DB query -
const derivatives = await Derivative.findAll();
Here is the res -
res.status(200).send({
data: derivatives.map((derivative) => ({
id: derivative.id,
date: derivative.date,
})),
});
Here is the download -
const fileName = derivatives.map((name) => name.wex);
res.status(200).download(__dirname, `/assets/${fileName}`);
How can I add that to my response?

HTTP lets you specify a "content disposition" to indicate whether a response should be treated as a download, but doesn't support sending downloads arbitrarily, it has to be a response to a request. You can't have part of a response be a download and part be not, for a single request.
So if you need a file to be downloaded, and some JSON used to display some UI, you need to handle that in the client somehow. Either:
The client sends a request, and server returns JSON containing a URL for the download as well as the other data you wanted to send, and then the client requests a download of the URL through JavaScript
The client sends two requests, one for the download and one for the other data; this may complicate things on the server if you need to associate the two requests (want to do a database lookup only once for instance), but is simplest on the client.
The client sends a request, and the server returns a response containing the JSON data and the file data, packed in some way (the file data could be inside the JSON but that would be inefficient), and it's unpacked on the client (using JavaScript) and the client then constructs a Blob URL to "download" (in this case the data is already downloaded, so this just entails saving a file)
There are any number of ways you might pack the file and JSON data together, which is what /u/Quentin was alluding to. Sending both as one response may be better for performance, but you probably don't need to.

Related

how to create a readable stream from a remote URL and pass it into another API without saving it into the local file system in nodejs using got?

I want to access an image from a remote URL and pass it into another API request as request body.
I am using got stream API library to stream the data from the external url.
const url = "https://media0.giphy.com/media/4SS0kfzRqfBf2/giphy.gif";
got.stream(url).pipe(createWriteStream('image.gif'));
const response= await axsios.post('post_url',fs.createReadStream('image.gif');
The download operation is working as expected, but I don't want write the data to the local system.Instead, I woud like pass the response from the got stream API to another API as a request body.

Send metadata with file as a response in Sanic Server Python

I want to send an audio file, along with some other metadata text (like server details, etc.), as a response in the Sanic server using Python.
I know that we can send, responses in text, JSON, or as a file. But would like to know, is there any way we can send the file as well as some other datatype as a response in a single request?
I tried with response.json by sending the metadata, as well as audio data (converting bytes to string), but while converting to string, I feel, some of the metadata of the audio is lost.
Would like to know, is there any effective way to send files, as well as some other metadata using Sanic in a single request?
Thanks :)
I just tried to do a little hack... I send the metadata in the header and stream the file as usual (response.file()), so from the client side, I read the metadata from the header, and get the file as resp
example:
headers = {
'metadata': text,
}
return await response.file(audio_file, headers=headers)

running function after res.send

I'm trying to run this code
module.exports = async (req, res, next) => {
res.set('Content-Type', 'text/javascript');
const response = {};
res.status(200).render('/default.js', { response });
await fn(response);
};
fn is a function that calls an api to a service that will output to the client something. but its dependent on the default.js file to be loaded first. How can do something like
res.render('/default.js', { response }).then(async() => {
await fn(response);
};
tried it, but doesn't seem to like the then()
also, fn doesn't return data to the client, it calls an api service that is connected with the web sockets opened by the code from default.js that is rendered.
do i have to make an ajax request for the fn call and not call it internally?
any ideas?
Once you call res.render(), you can send no more data to the client, the http response has been sent and the http connection is done - you can't send any more to it. So, it does you no good to try to add something more to the response after you call res.render().
It sounds like you're trying to put some data INTO the script that you send to the browser. Your choices for that are to either:
Get the data you need to with let data = await fn() before you call res.render() and then pass that to res.render() so your template engine can put that data into the script file that you send the server (before you send it).
You will need to change the script file template to be able to do this so it has appropriate directives to insert data into the script file and you will have to be very careful to format the data as Javascript data structures.
Have a script in the page make an ajax call to get the desired data and then do your task in client-side Javascript after the page is already up and running.
It looks like it might be helpful for you to understand the exact sequence of things between browser and server.
Browser is displaying some web page.
User clicks on a link to a new web page.
Browser requests new web page from the server for a particular URL.
Server delivers HTML page for that URL.
Browser parses that HTML page and discovers some other resources required to render the page (script files, CSS files, images, fonts, etc...)
Browser requests each of those other resources from the server
Server gets a request for each separate resource and returns each one of them to the browser.
Browser incorporates those resources into the HTML page it previously downloaded and parsed.
Any client side scripts it retrieved for that page are then run.
So, the code you show appears to be a route for one of script files (in step 5 above). This is where it fits into the overall scheme of loading a page. Once you've returned the script file to the client with res.render(), it has been sent and that request is done. The browser isn't connected to your server anymore for that resource so you can't send anything else on that same request.

Nodejs: downloading and transforming large data from mongodb

I use Node JS. (Sails JS framework, but that's less important).
Purpose
Download a CSV file that includes data transformed from MongoDB.
That's the scenario of the server on a response to a large data download request
Read data from MongoDB.
Transform the data format (to CSV).
Send the data to response. (Download).
So, the user is expected to download this large data to their browser.
I'm not sure what would be the best way to handle such request.
MongoDB has built-in support for streaming and Node.js clients can provide a readable stream for the cursor. All HTTP response objects also provide a way to stream the response body through a series of writes or you can pipe to a socket when using WebSockets. Most of the work will be offloaded to the MongoDB server and Node.js was developed for exactly these kinds of requirements.
If you're going to use HTTP on the client side, you can use fetch() and stream the response body into memory. Here is an excellent article that shows how to efficiently process a response for large a CSV file:
const res = await fetch('/big-data.csv')
const csvStream = response.body
.pipeThrough(new TextDecoder())
.pipeThrough(new CSVDecoder())
for (;;) {
const {row, done} = await csvStream.read()
if (done) break
drain(row)
}
Don't forget that both the server and client support encoded content, so make sure you compress the responses to further improve I/O.
It is always a good idea to post some code of what you have tried so far.
First, you would have to retrieve the data from MongoDB using something like mongoose or Waterline if you are using SailsJS
Secondly you can use a library like csv to convert the data to a csv file.
Once you have created the file you can return the file to the user using the sails response like so:
res.attachment('path/to/file.csv');

How to receive a zip file in koa server

I'm implementing a webserver using Koa. One of my request handlers needs to receive and store a large zip file. The file is NOT uploaded from a web page, but sent from another NodeJs application. Therefore it's not multipart encoded, but just applcation/octet-stream. How can I read such a file from the request?
I've noticed there is a request.socket object but I could not find any documentation on how to use it.
In other words I need the opposite to
this.body = fs.createReadStream(path);

Resources