Node+Express pipe file directly to writeStream - node.js

In terms of learning i need to make a file uploading by myself with fs.streams
router.post('/upload', (req, res, next) => {
req.pipe(fs.createWritableStream('files/file.png'))
.on('error', (err) => next(err))
.on('close', () => {
res.json({image: 'files/file.png'});
})
})
This is dosen't work. So two questions
How to get file name and data from req?
How to connect this two streams?
Update: In all tutorials described opposite action - read file from fs and pipe it to res to enduser.

you can use multer
const multer = require('multer');
const upload = multer({
dest: 'folderName'
});
router.post('/upload', upload.single('formField'), (req, res, next) => {
res.json({image: req.file.path});
})
in this code file path will be sent.
if you want to send file itself, then you should write:
res.download(req.file.path);
instead of res.json({image: req.file.path}).
I don't know how res.download works exactly. maybe it takes whole buffer of the file and sends it.
multer's documentation is here

Related

Is there any way to serve binary file input(stream?) directly to multer middleware(for unit test purpose)?

I'm trying to write test codes on multer and my service.
As multer is an express's middleware, multer is intended to process the request from client and automatically handle the file and put it in req.file.
But I wonder if there is any way without making real HTTP request, to pass binary file or stream to multer middleware so that I can check whether the file is saved in local disk properly or the file's size is put afterward in req.file.
My code as middleware module of multer is below, just for reference:
import { Request, Response, NextFunction } from 'express';
import multer from 'multer';
const multerMiddleware = (dest: string) => (req: Request, res: Response, next: NextFunction) => {
const upload = multer({
storage: multer.diskStorage({
destination: dest,
filename: (req, file, cb) => {
const { videoId } = req.body;
const filename = `${videoId}-${file.originalname}`;
cb(null, filename);
}
})
});
upload.single('file')(req, res, next);
}
export default multerMiddleware;
Or, is it the best way to do just make a test-purpose route in Express app and test with it? Like below:
app.post('/testMulter', multerMiddleware('temp/'), (req, res, next) => {
res.status(200);
res.json(req.file);
// ...
});
// in test codes
import request from 'supertest'
import App from '../app.ts'
it('multer middleware download files well', async (done) => {
const app = new App.app;
const response = await request(app)
.post('/testMulter')
.attach('file', './test.mp4');
expect(response.file.filename).toBe('test.mp4');
})
Thank you in advance.
So you want to do an integrational test but without HTTP stuff.
According to the provided code, only req.body is used. In terms of the unit testing, it is simple to mock such Request.
But we do not "know" how multer uses Request and Response. So if you still want to do an integrational test, you approach is good enough.
Overwise it is better to pass { body: { videoId: fakeId } } instead of Request and mock multer, multer.diskStorage, and and multer.single`.

How to read data as buffer from an audio file as soon as it is added to the file in nodejs?

I have a .wav audio file being recorded live. I just want to read it's data as soon as the data is added to it and send to some other server (or web browser to listen live)
How can I do this in nodejs.
TL;DR: Create a read stream of your .wav file and pipe it with your write stream.
This is not an actual working example. This is just to demonstrate how you can achieve it.
Here, res is a write stream!
const fs = require('fs');
const file = fs.createReadStream('audio.wav');
app.get('/', (req, res) => {
file.on('data', (chunk) => {
// Send chunk to client
res.send(chunk); // May be?
});
});
Or, you can use pipe!
app.get('/', (req, res) => {
file.pipe(res);
});

Why MongoDB adding extra slash to path?

Good evening for everyone, I have some trouble with saving my url to mongodb database as string. Because mongo adding extra slash to every part of url. Like this:
"localhost:3333\uploads\Untitled1.cpp"
but in my console log I have normal result(look at the terminal in the screenshot). Whyy? Please, help
let storage = multer.diskStorage({
destination: (req, file, cb) =>{
cb(null, '/uploads')
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
})
let upload = multer({ storage: storage })
let type = upload.single('myFile');
app.post('/upload', type, (req, res) => {
const url = `http://localhost:3333${req.file.path}`;
const image = {
name: req.file.originalname,
url: url
}
console.log(image.url)
const newImage = new Image(image);
newImage.save()
.then (res.json('Картинку додано'))
.catch(err => res.status(400).json(err));
});
I assume you're using a Windows operating system which uses back slashes '\' for paths in its filesystem. The web (and Linux-based operating systems) use forward slashes '/' for paths. Therefore ${req.file.path}, which I'm guessing is referencing a file on your computer, is returning a path including back slashes.
You can use String.replace() with a regular expression to replace the back slashes with forward slashes:
let webPath = req.file.path.replace(/\\/g,'/'))
const url = `http://localhost:3333${webPath}`;
I have found the solution. What you need to do is when you are posting/saving your file into db there you need to use replace function and then your path will be saved with forward slash into your DB.
Here is the snippet:
app.post('/upload', upload.single('file'), (req, res, next) => {
const file = new Cluster1({
filePath: req.file.path.replace(/\\/g, '/'),
name: req.file.originalname
});
file.save()
You can see how I am using the replace fucntion to avoid \\ or \

node.js | loopback, handling direct file upload

is it possible for the client to directly push a file onto our servers via API? How about pushing a file from our server to another again via API?
Right now my servers go out and grab files from locations via 'get'. This isn't the most efficient potentiality and there are reasons to believe I won't be able to access all files directly via get.
For sending you can use the request module's form feature to upload files.
var formData = {
my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
};
request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
For receiving files in node you can use something like express with multer:
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})

Cannot read property 'displayImage' of undefined

I am developing a web app with node js. When trying to upload a picture and save in the file system of the app I get the error :
Cannot read property 'displayImage' of undefined
My code for the post of the image is the following:
router.post('/upload', function (req, res, next) {
fs.readFile( req.files.displayImage.path, function (err, data) {
var newPath = __dirname + "/uploads/uploadedFileName";
fs.rename(newPath, 'filename', function (err) {
res.redirect('/');
});
});
});
And in the view
form(action="upload", method="post", enctype="multipart/form-data")
input(type="file", name="displayImage")
input(type='submit')
Thanks a lot for your help!
PS: I also have read some tutorials in where formidable module is used. It is recommended to use it or as I have done is enough?
Which version of express are you using ? In express 4.0 for multipart bodies you should use an alternatives.
For example, you can implement upload files using multer npm module
var multer = require('multer');
app.use(multer({dest: './uploads/'}));
//app.post('/upload', function (req, res, next) {
// console.log(req.files);
//});

Resources