How to download and upload file to Meteor.js

meteorjs_download_upload.png

Following is simple snippet how to download file and upload file (POST method) to Meteor.js. I use iron router as router for Meteor.js.

Download file

Following snippet put to lib/router.js. It'll execute at server side.

Router.route('/json/items', function() {
    let headers = {
      'Content-Type': 'text/json',
      'Content-Disposition': "attachment; filename=items.json"
    };

    let items = Items.find().fetch();
    this.response.writeHead(200, headers);
    return this.response.end(JSON.stringify(items));
}, {
    name: 'jsonItems',
    where: 'server'
})

Test from command line

wget http://localhost:3000/json/items -O m.json

Upload file

This task is more complicated. First, we need busboy to modify incoming request and add file field.

So, add busboy to package.json

meteor npm install --save busboy

Second, add middleware to server/middleware.js. Following snippet will add filenames field to iron router's this.request.

# vim server/middleware.js

const Busboy = require("busboy");
const fs = require("fs");
const os = require("os");
const path = require("path");

Router.onBeforeAction((req, res, next) => {
    let filenames = [];
    _.extend(req, {postData: {}});

    if (req.method == "POST") {
        let busboy = new Busboy({ headers: req.headers });
        busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
            let saveTo = path.join(os.tmpDir(), filename);
            file.pipe(fs.createWriteStream(saveTo))
            filenames.push(saveTo)
        })

        busboy.on("field", (fieldname, value) => {
            req.postData[fieldname] = value;
        })

        busboy.on("finish", () => {
            req.filenames = filenames;
            next();
        })

        req.pipe(busboy);
    } else {
        next();
    }
})

Following snippet put to lib/router.js. It'll execute at server side.

Router.route('/upload', function() {
    let result = {status: "OK"};
    if (this.request.filenames.length) {
        const fs = require("fs");
        let path = this.request.filenames[0];
        // save photo to store
        let photo = PhotosFS.insert(path);
        fs.unlink(path);
        result.photoID = photo._id;
    } else {
        result.status = "FAIL";
    }

    let headers = {'Content-Type': 'text/json'};
    this.response.writeHead(200, headers);
    return this.response.end(JSON.stringify(result));
}, {
    where: 'server',
    name: 'upload'
});

Test from command line

curl -i -F fd=@image.png http://localhost:3000/upload
comments powered by Disqus