How to separate middleware in feathers? - javascript

I use to upload files a multer library with feathers. I try to separate logic from code and I want put upload code not in a index.js but in my case in pdf.js in middleware directory.
Below is my works index.js:
'use strict';
const pdf = require('./pdf');
const record = require('./record');
const records = require('./records');
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
const uploadPdf = require('./upload-pdf');
module.exports = function() {
// Add your custom middleware here. Remember, that
// just like Express the order matters, so error
// handling middleware should go last.
const app = this;
app.use('/rekord/:id.html', record(app));
app.use('/rekordy.html', records(app));
app.use('/pdf/:id', uploadPdf.single('file'), pdf(app));
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
Here is upload-pdf.js file:
var multer = require('multer')
var storagePdf = multer.diskStorage({
destination: 'public/pdf',
filename: function (req, file, cb) {
var id = req.params.id
cb(null, id+'.pdf')
}
});
module.exports = multer({
storage: storagePdf,
fileFilter: function (req, file, cb) {
if (file.mimetype !== 'application/pdf') {
return cb(null, false, new Error('I don\'t have a clue!'));
}
cb(null, true);
}
});
And pdf.js file:
'use strict';
module.exports = function(app) {
return function(req, res, next) {
if (req.file) {
return res.end('Thank you for the file');
}
return res.end('false');
next();
};
};
I would like to combine upload-pdf.js and pdf.js into one file

Not particularly Feathers specific, just as with any other Express application you can put the code into their own modules:
'use strict';
const pdf = require('./pdf');
const record = require('./record');
const records = require('./records');
const handler = require('feathers-errors/handler');
const notFound = require('./not-found-handler');
const logger = require('./logger');
module.exports = function() {
// Add your custom middleware here. Remember, that
// just like Express the order matters, so error
// handling middleware should go last.
const app = this;
app.use('/rekord/:id.html', record(app));
app.use('/rekordy.html', records(app));
app.use('/pdf/:id', pdf.upload.single('file'), pdf.process(app));
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
In pdf.js:
'use strict';
var multer = require('multer')
var storagePdf = multer.diskStorage({
destination: 'public/pdf',
filename: function(req, file, cb) {
var id = req.params.id
cb(null, id + '.pdf')
}
});
exports.upload = multer({
storage: storagePdf,
fileFilter: function(req, file, cb) {
if (file.mimetype !== 'application/pdf') {
return cb(null, false, new Error('I don\'t have a clue!'));
}
cb(null, true);
}
});
exports.process = function(app) {
return function(req, res, next) {
if (req.file) {
return res.end('Thank you for the file');
}
return res.end('false');
next();
};
};
The NodeJS module system docs are quite helpful to learn how it all fits together.

Related

File upload makes Node JS unresponsive with Multer

I am using Multer Node JS package to upload files to my app sever , the code is basically typical upload file code
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
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
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
But each time a file is being uploaded the Node server becomes unresponsive and frontend from other request doesnt receive any response from other APIs until the file is uploaded.
Whats the best way to tackle this ?
In your sample code, you must just send a response to the client by res.json() or res.end() :
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
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
res.status(204).end();
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
res.status(204).end();
});
i can give you an example of how i implemented an imageupload in my app. it the code to upload a profile image for a user. i am also using multer middleware so it shoulder be similiar for you:
code is as follows:
// multer middleware:
const multer = require('multer');
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
};
module.exports = storage = multer.diskStorage({
destination: (req, file, cb) => {
const isValid = MIME_TYPE_MAP[file.mimetype];
let error = new Error('invalid mime type');
if (isValid) {
error = null;
}
cb(error, 'images');
},
filename: (req, file, cb) => {
const name = file.originalname.toLowerCase().split(' ').join('-');
const ext = MIME_TYPE_MAP[file.mimetype];
if (name.includes('.' + ext)) {
cb(null, name)
} else {
cb(null, name + '.' + ext);
}
},
});
and here the code in the service handling the fileupload
// profile service in backend written in express
exports.uploadImage = (req, res, next) => {
const url = req.protocol + '://' + req.get('host');
profileRepository
.findOne({ _id: req.params.id })
.then((response) => {
const fetchedUser = response;
fetchedUser.imagePath = url + '/images/' + req.file.filename;
profileRepository
.updateOne({ _id: req.params.id }, fetchedUser)
.then((response) => {
return res.status(200).json({
message: 'profileimage updated',
});
})
.catch((error) => {
return res.status(500).json({
message: 'uploading image failed',
});
});
})
.catch((error) => {
return res.status(404).json({
message: 'fetching user failed',
});
});
};
then i use the middleware in my profile routes file like this:
// profile.routes.js
const express = require('express');
const ProfileController = require('./profileController');
const checkAuth = require('../middleware/checkAuth');
const router = express.Router();
const fileStorage = require('../middleware/fileStorage');
const multer = require('multer');
// imageUpload
router.post('/user/image/:id', checkAuth, multer({storage: fileStorage}).single('image'), ProfileController.image);
my Controller then calls the service function with the actual business logic like this:
// profile.controller.js
const profileService = require('./profileService');
exports.image = (req, res, next) => {
return profileService.uploadImage(req, res);
};
and finally my route is used by my app.js file like this:
// app.js
const express = require('express');
const profileRoutes = require('./profile/profileRoutes');
const app = express();
// set images path for saving images on server
app.use('/images', express.static(path.join('images')));
app.use('/api', profileRoutes);
module.exports = app;
i hope i was able to point you in the right direction with my example

Creating folders by using object values

I am learning Nodejs, and I am trying to create folders for each new user.
The folder will be linked to the User name (when clicking on it will open folder/ftp)
I am using the Admin-bro interface.
Here is the User object.
const { model } = require("mongoose");
const User = model("User", {
name: String,
surname: String,
age: Number,
email: String,
description: String
});
module.exports = User;
User router:
const { Router } = require('express')
const paginate = require('../services/paginate.service')
const User = require('../models/user.model')
const dir = require('../routers/ftp')
const router = new Router()
const serializer = (user) => {
return user.toObject({ versionKey: false })
}
router.get('/', async (req, res) => {
const users = await paginate(User.find({}), req)
res.send(users.map(serializer))
})
router.post('/', async (req, res) => {
const user = await new User(req.body.user).save()
res.send(serializer(user))
})
module.exports = router
I have no idea how to create a folder for each new user I add, passing name_surname as the folder name.
I trying to create a router but failed.
This is what I tried:
"use strict";
module.exports = function(app) {
const fs = require("fs");
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
desctination: function(req, file, cb) {
const uploadDir = path.join(__dirname, "..", "..", `${Date.now()}`);
fs.mkdirSync(uploadDir);
cb(null, uploadDir);
},
filename: function(req, file, cb) {
cb(null, file.originalname);
}
});
const upload = multer({ storage });
const controller = require("../routers/createDir");
};
PS: there is no controller as I don't know what do to.
Please give me an advice or a link where I can learn how it's done. Thank you
User mkdrp node module package
var mkdirp = require('mkdirp');
mkdirp('/tmp/foo/bar/baz', function (err) {
if (err) console.error(err)
else console.log('pow!')
});
I am willing to pass the user name or id to the folder and create it dynamically, not manually. smth like this
const multer = require("multer");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const { userId } = req.body;
const dir = `../uploads/${userId}`;
fs.exists(dir, exist => {
if (!exist) {
return fs.mkdir(dir, error => cb(error, dir));
}
return cb(null, dir);
});
},
filename: (req, file, cb) => {
const { userId } = req.body;
cb(null, `UserId-${userId}-Image-${Date.now()}.png`);
}
});
const upload = multer({ storage });

How I can export multer module

I want to export modul multer to another file but the console returns an error to me.
TypeError: uploadImg.single is not a function
here is my multer.js
module.export = () => {
const multer = require("multer");
const storage = multer.diskStorage({
destination(req, file, cb) {
const url = `./uploads/catalog`;
cb(null, url);
},
filename(req, file, cb) {
file.originalname = "re_" + file.originalname;
cb(null, `${file.originalname}`);
}
});
const uploadImg = multer({
storage: storage
});
return uploadImg;
};
And here is a part of my routes file
const uploadImg = require("./../services/multer");
app.post("/catalog/upload/img", uploadImg.single("image"), async (req, res, next) => {
console.log(req.file);
});
You start with this: module.export = () => {... which means that you export the function.
So uploadImg is the function const uploadImg = require("./../services/multer"); and the only way how to call it is with uploadImg().
If you have everything else correct then uploadImg().single("image") should do the trick, but then it does not make sense to export it as function. If you use it in static context (which routes are), then you probably want something like this:
const multer = require("multer");
const storage = multer.diskStorage({
destination(req, file, cb) {
const url = `./uploads/catalog`;
cb(null, url);
},
filename(req, file, cb) {
file.originalname = "re_" + file.originalname;
cb(null, `${file.originalname}`);
}
});
const uploadImg = multer({
storage: storage
});
exports.uploadImg = uploadImg;
Then you can call it as following
const myMulter = require("./../services/multer");
app.post("/catalog/upload/img", myMulter.uploadImg.single("image"), async (req, res, next) => {
console.log(req.file);
});
You have a typo in multer.js
You should write module.exports = instead of module.export =

angular-file-upload to nodejs backend unable to read file contents

I'm using angular file upload which previously did work when I used Laravel Lumen for the backend but I've moved to Node and unable to return the file contents of an upload.
FRONT END ANGULAR
$scope.upload = Upload.upload({
url: ENV.apiEndpoint + '/upload',
method: 'POST',
data: {
fname: $scope.fname
},
file: file
}).progress(function(evt) {
}).success(function(data, status, headers, config) {
});
BACK END NODE
upload/index.js
'use strict';
var express = require('express');
var controller = require('./upload.controller');
var router = express.Router();
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './my-uploads');
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now());
}
})
var upload = multer({ storage: storage });
router.post('/', upload.single('file'), controller.index);
module.exports = router;
upload/upload.controller.js
'use strict';
var _ = require('lodash');
var db = require('../../db');
var https = require('https');
var Q = require('q');
var fs = require('fs');
var multer = require('multer');
exports.index = function(req, res, next) {
console.log(req.files.file);
res.status(204).end();
};
Old Laravel Lumen Request
public function data(Request $request) {
$path_parts = pathinfo($_FILES["file"]["name"]);
$extension = $path_parts['extension'];
$contents = file_get_contents( $_FILES['file']['tmp_name'] );
return response()->json(['type'=> $extension, 'content'=> $contents]);
}
All I'm looking to do is upload a file but only return the contents of the file to the front end again I dont want the file to be stored.
Here you have an example, you have a couple of things wrong. Check it out
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/images/banks')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + path.extname(file.originalname));
});
}
});
var upload = multer({storage: storage});
router.post('/uploadImage', upload.single('file'), function (req, res, next) {
if(!req.file) {
res.status(400);
res.send({error: 'No se pudo subir el archivo'});
}
res.send({filename: req.file.filename});
});

Express middleware (multer) in seperate file

I was able to move a very simple middleware (isAuthenticated) over to an external middleware file, but I'm having a harder time with moving my multer upload over. I just learned how to move them to seperate files, so it's probably obvius.
routes/index.js
var middleware = require('../middleware/common');
var isAuthenticated = middleware.isAuthenticated;
var upload = middleware.multerSetup;
...
router.post('/updateuser',
upload,
...,
function (req, res, next) {
res.redirect('/dashboard');
}
);
--
//middleware/common.js
var multer = require('multer');
Middleware = {
//Checks whether user is logged in
isAuthenticated: function(req,res,next){
if(req.isAuthenticated()){
return next();
}
req.flash('auth',"You do not have the proper permissions to access this page");
res.redirect('/');
},
multerSetup: function(req,res,next){
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
//detects file type, then adds extension to match file type
filename: function (req, file, cb) {
var ext = "";
switch(file.mimetype){
case 'image/png':
ext = '.png';
break;
case 'image/jpeg':
ext = '.jpeg';
break;
default:
ext = '';
}
cb(null, Date.now() + ext); //Appending .jpg
}
});
var upload = multer({storage:storage, fileFilter: function (req, file, cb) {
var acceptedExt = ['.png','.jpg','.gif','.bmp'];
if (req.hasOwnProperty('file') && acceptedExt.indexOf(path.extname(file.originalname))=== -1) {
return cb(new Error('Image type not allowed: ' + path.extname(file.originalname)));
}
cb(null, true)
}});
return upload.single('upl');
}
};
module.exports = Middleware;
Error:
routes\index.js:108
upload.single('upl'),
^
TypeError: upload.single is not a function
at Object.<anonymous> (C:\Users\Tyler\WebstormProjects\volunteer\volunteerApp\routes\index.js:108:12)
You're setting up your multer middleware wrong. Your Middleware.multerSetup is a middleware function, which is then calling upload.single to set up multer (which is then never called and the request is left hanging). Move your multer upload setup outside your custom middleware and have your module export just the return function from upload.single.
Example:
Middleware = {
...
multerSetup: upload.single('upl')
...
}
Got it! Just needed to define upload in routes/index.js as a function.
var upload = middleware.multerSetup();
Brother in the separate file, declare your setup function, then your middleware and export it, and pass the "file" as a parameter in upload function and return upload.single(file):
const multer = require("multer");
function multerSetup() {
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
return storage;
}
Middleware = {
upload: function (file) {
const upload = multer({ storage: multerSetup() });
return upload.single(file);
},
};
module.exports = Middleware;
In your route file write your route:
const router = require("express").Router();
const Middleware = require("../helper/uploadImages");
router.post("/", Middleware.upload("file"), (req, res) => {
res.status(200).json("file has been uploaded!");
});
module.exports = router
in index.js file just you need to import your route and use it:
const uploadImageRoute = require("./routes/uploadImages");
app.use("/api/upload", uploadImageRoute);

Categories

Resources