mwild
mwild

Reputation: 1655

Node.js to send images via REST API

Im struggling to find material on this

I have a rest API, written in node.js, that uses mongoDB.

I want users to be able to upload images (profile pictures) and have them saved on the server (in mongoDB).

A few questions, Ive seen it is recommended to use GridFS, is this the best solution?

How do i send these files? Ive seen res.sendFile, but again is this the best solution?

If anyone has any material they can link me I would be appreciative

thanks

Upvotes: 4

Views: 7787

Answers (4)

Derrick
Derrick

Reputation: 1606

Also, this is a good case for shared object storage like AWS S3 or Azure blob storage. If you are running a distributed setup in something like AWS, you usually don't want to store photos on the local server.

Store the url or key name in the database that points to the S3 object. This also integrates with CloudFront CDN pretty easily.

As suggested before. MultiPart for the actual upload.

Upvotes: 0

Pawan Gupta
Pawan Gupta

Reputation: 154

You won't be able to get the file object on the server directly. To get file object on the server, use connect-multiparty middleware. This will allow you to access the file on the server.

var multipart = require('connect-multiparty');
var multipartmiddleware = multipart();
var mv = require('mv');
var path = require('path');

app.post("/URL",multipartmiddleware,function(req,res){
    var uploadedImage = req.files.file;
    for (var i = 0; i < uploadedImage.length; i++) {
        var tempPath = uploadedImage[i].path;
        var targetPath = path.join(__dirname ,"../../../img/Ads/" + i + uploadedImage[i].name);

        mv(tempPath, targetPath, function (err) {
           if (err) { throw err; }
        });
    }
})

Upvotes: 3

user1381004
user1381004

Reputation:

If you're using the mongoose odm you can use the mongoose-crate module and send the file wherever for storage.

Upvotes: 0

Tom
Tom

Reputation: 5121

Use file system

Generally in any database you store the image location in the data as a string that tells the application where the image is stored on the file system.

Unless your database needs to be portable as a single unit, the storing of images inside of the database as binary objects generally adds unnecessary size and complexity to your database.
-Michael Stearne

In MongoDB, use GridFS for storing files larger than 16 MB. - Mongo Documentation

Therefore unless your images will be over 16 MB, you should either store the file on a CDN (preferable) or the server's own file system and save its URL to user's document on the database.


Local file system implementation

This method uses Busboy to parse the photo upload.

in relevant html file:

<input type="file" title="Choose a file to upload" accept="image/*" autofocus="1">

Handler function for your photo upload route in server file (you will need to fill in the variables that apply to you and require the necessary modules):

function photoUploadHandlerFunction (req, res) {
  var busboy = new Busboy({ headers: req.headers })
  busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
    const saveToDir = path.join(__dirname, uploadsPath, user.id)
    const saveToFile = path.join(saveToDir, filename)
    const pathToFile = path.join(uploadsPath, user.id, filename)
    const writeStream = fs.createWriteStream(saveToFile)

    createDirIfNotExist(saveToDir)
      .then(pipeUploadToDisk(file, writeStream))
      .then(findUserAndUpdateProfilePic(user, pathToFile))
      .catch((err) => {
        res.writeHead(500)
        res.end(`Server broke its promise ${err}`)
      })
  })

  busboy.on('finish', function () {
    res.writeHead(200, { 'Connection': 'close' })
    res.end("That's all folks!")
  })

  return req.pipe(busboy)
}

Where the promise functions createDirIfNotExist and pipeUploadToDisk could look like this:

function createDirIfNotExist (directory, callback) {
  return new Promise(function (resolve, reject) {
    fs.stat(directory, function (err, stats) {
      // Check if error defined and the error code is "not exists"
      if (err) {
        if (err.code === 'ENOENT') {
          fs.mkdir(directory, (err) => {
            if (err) reject(err)
            resolve('made folder')
          })
        } else {
          // just in case there was a different error:
          reject(err)
        }
      } else {
        resolve('folder already existed')
      }
    })
  })
}

function pipeUploadToDisk (file, writeStream) {
  return new Promise((resolve, reject) => {
    const fileWriteStream = file.pipe(writeStream)
    fileWriteStream.on('finish', function () {
      resolve('file written to file system')
    })
    fileWriteStream.on('error', function () {
      reject('write to file system failed')
    })
  })
}

To answer your question 'How do I send these files?', I would need to know where to (MongoDB, to the client...). If you mean to the client, you could serve the static folder where they are saved.

If you still want to learn about implementing GridFs tutorialspoint have a good tutorial


More material

Upvotes: 1

Related Questions