jeudi 22 janvier 2015

Design pattern for writing a list of filters for image uploading using node.js

I'm writing a simple image uploader in node.js and express 4. When the file is posted, the enclosed image will run through a series of filters:



  • is this an acceptable MIME type? (jpg, gif, png, tiff)

  • does this have a correspondingly acceptable extension?

  • is this image less than 2 megabytes?

  • has the file been truncated in the upload?


I'm used to doing this sort of thing in synchronous languages, where I would run the object through a series of if's, and return false if something catches. In javascript, however, the same approach will result in sending multiple headers.


I have gotten around this by nesting the filters in else clauses, but this is quickly becoming very unwieldy. This seems like a common design pattern, so what is the best way to handle something like this?


app.js:



var express = require('express')
, fs = require('fs')
, bodyParser = require('body-parser')
, serveStatic = require('serve-static')
, multer = require('multer')
, port = 80
;

var app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(multer({ dest: "./images/tmp" }))
app.use(serveStatic(__dirname + '/public'));
app.listen(port);

app.get('/', function(req, res, next) {
console.log(req);
res.render("uploader");
});

var uploadConfig = {
acceptedMimeTypes : [ "image/jpeg", "image/png", "image/gif", "image/tiff" ],
acceptedExtensions : [ "jpg", "jpeg", "png", "gif", "tiff" ],
maxFileSize : 2000000
};

app.post('/upload', function(req, res, next) {
var image = req.files.image;
var removeTempImage = function() {
fs.unlink('images/tmp/' + image.name)
};
// Here is where things become a mess
if (uploadConfig.acceptedMimeTypes.indexOf(image.mimetype) == -1) {
removeTempImage();
res.send({success: false, message: "Incorrect MIME type"});
} else {
if (uploadConfig.acceptedExtensions.indexOf(image.extension) == -1) {
removeTempImage();
res.send({success: false, message: "Incorrect file extension"});
} else {
if (image.size > uploadConfig.maxFileSize) {
removeTempImage();
res.send({success: false, message: "File is too large"});
} else {
if (image.truncated) {
removeTempImage();
res.send({success: false, message: "The file was truncated"});
} else {
// it survived the gauntlet
fs.rename('images/tmp/' + image.name, 'public/completeImgs/' + image.name, function (err) {
if (err) {
removeTempImage;
res.send({success: false, message: err});
} else {
res.send({success: true, message: "Your image has been saved"});
}
})
}
}
}
}
});


console.log("uploader is listening on port " + port);


uploader.jade



doctype
html
head
body
h1 Image Uploader
form(method="post" action="/upload" enctype="multipart/form-data")
input(type="file" name="image")
input(type="submit")
h1 !{test}

Aucun commentaire:

Enregistrer un commentaire