I am using express-fileupload to parse the body of my request and access any files that are sent with the request. This works fine when I am trying to do this locally but when I push it to heroku, the files are not being parsed - instead req.files is null. My code is below:
Parsing middleware:
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
module.exports = function (app) {
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload()); // EXPRESS-FILEUPLOAD BEING USED HERE
};
Routes file:
router.post('/photo', function(req, res, next) {
console.log("INSIDE OF THE ROUTE =======>>>>>");
const userId = req.body.userId;
const busketName = 'my-bucket-name';
let newPhotosArray = [];
var busboy = new Busboy({ headers: req.headers });
req.pipe(busboy);
busboy.on('finish', function() {
const filesObj = req.files;
console.log('FILES OBJ: ', filesObj); // THIS IS LOGGED OUT AS NULL ON HEROKU - LOCALLY IT IS AN OBJECT WITH FILES
// rest of code....
});
});
The code works great when I use it locally. However, when I push the code to Heroku, req.files is null. Why is this?
Related
I use vue3, vuex, express.js and mysql. In the below router get method, I call "console.log(req.body)" and shows "[object Object]", and I call "console.log(req.body.userid)" and shows "undefined".
router.get('/',async function(req,res){
const userId = req.body.userid;
console.log("req body is: "+req.body);
console.log("req.body.userid is: "+req.body.userid);
.....
}
In the below method, I pass userid value as a json object. I call "console.log("post userid: "+userinfo.userid);" and shows the the right value "1";
async getsp(){
var userinfo = JSON.parse(localStorage.getItem('user'));
console.log("post userid: "+userinfo.userid);
var userid = userinfo.userid;
var obj = {userid};
return await axios.get('//localhost:8081/getSp',obj)
.then(...)
},
And in the main router file I used body-parser, the file context is below:
require("dotenv").config();
const express = require('express');
const bodyParser = require('body-parser');
var cors = require('cors');
const signup = require('./userSignUp');
const login = require('./userLogin');
const createEvsp = require('./createEvsp');
const getSp = require('./getSp');
//const createFile = require('./createFile');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.use(cors())
app.use(express.json());
app.use(
express.urlencoded({
extended: true
})
);
app.use("/signup",signup);
app.use("/dologin",login);
app.use("/createEvsp",createEvsp);
app.use("/getSp",getSp);
//app.use("/createFile",createFile);
app.listen(8081,function () {
console.log('Server running at 8081 port');
});
The problem was an HTTP method understanding and how express works
To solve it it was needed to use the express middleware /:userid for accessing to the parameter using req.params.userid
According to the http standards for sending the data we generally use POST request.
There is a good answer in stack here Information about Get HTTP Request
Sayf-Eddine
In my express app router, I've routes for accepting POST request of JSON data as well as binary data. The problem is when I use body parser for passing JSON data, it also considers the binary data as JSON and gives error while POSTing binary data. i.e. when I use:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
And When I remove this, It only works for binary data. Following is my route for POSTing binary file.
router.post('/file', function (req, res) {
var gridfs = app.get('gridfs');
var writeStream = gridfs.createWriteStream({
filename: 'file_name_here'
});
writeStream.on('close', function (file) {
res.send(`File has been uploaded ${file._id}`);
});
req.pipe(writeStream);
});
I've also tried moving this file route to other router. In that case, when I don't set anything regarding body parser, it still gives the same error.
One fix that works correctly is placing this file route in my main app.js prior to setting body parser. But I think this would not be good approach. I want these routes to be in separate files.
So what I'm missing here? Any alternatives will also be appreciated.
EDIT
As per the answer, I've first separated out my routers which requires body parsing and which do not. Also removed the bodu parser from my main app.use() Now in the router in which, I need body parser, I've added those 2 lines. But the behavior is same.
When I add those 2 lines, only JSON reqquest works and when I remove, only binary POST req. works.
Here is my updated code:
app.js
const express = require('express');
const app = module.exports = express();
const bodyParser = require('body-parser');
const port = 8080;
// //parsing incoming requests using body-parser middlewares
// app.use(bodyParser.json());
// app.use(bodyParser.urlencoded({ extended: false}));
//adding routes
app.use(require('./routes/additionRouter'));
app.use(require('./routes/mediaRouter'));
//catch 404 file not found here
app.use((req, res, next) => {
const err = new Error('Page Not Found');
err.status = 404;
next(err);
});
//Error Handler
app.use((err, req, res, next) => {
res.status(err.status || 500);
res.send(err.message);
});
app.listen(port, () => {console.log('Server listening on port: ' + port)});
additionRouter.js
const express = require('express');
const router = express.Router();
var exported = require('../config/dbConnection');
const bodyParser = require('body-parser');
// parsing incoming requests using body-parser middlewares
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false}));
//Endpoint for adding new challenge
router.post('/endpoint1', (req, res, next) => {
});
module.exports = router;
and mediaRouter.js
const express = require('express');
const mediaRouter = express.Router();
const exported = require('../config/dbConnection');
exported.cb((gridfs) => {
//For adding media files to database named 'mediadb'
//POST http://localhost:8080/file
mediaRouter.post('/file', function (req, res) {
// var gridfs = app.get('gridfs');
var writeStream = gridfs.createWriteStream({
filename: 'file_name_here'
});
writeStream.on('close', function (file) {
res.send(`File has been uploaded ${file._id}`);
});
req.pipe(writeStream);
});
//GET http://localhost:8080/file/[mongo_id_of_file_here]
mediaRouter.get('/file/:fileId', function (req, res) {
// var gridfs = app.get('gridfs');
gridfs.createReadStream({
_id: req.params.fileId // or provide filename: 'file_name_here'
}).pipe(res);
});
});
module.exports = mediaRouter;
By specifying
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
your entire app uses the body parser middleware. You could create another middleware to handle whether or not the body parser is used. For example:
const bodyParse = bodyParser.json();
app.use((req, res, next) => {
if(req.originalUrl == "restOfUrl/file") next();
else bodyParse(req, res, next);
});
I am building a Node application using Express, Massive JS, and Postgresql. I was using sequelize but decided to try Massive JS, so I started converting my code to use it.
I have a login endpoint that I'm trying to reach from my Angular 5 app and I am getting an error. This error only occurs on my deployed application. It does work locally without any issues.
Here is the specific error:
TypeError: Cannot read property 'get_user' of undefined<br> at login (/root/firstImpression/server/features/auth/authController.js:7:26)
Here is my folder structure:
+Server
-server.js
+config
-secrets.js
+db
-get_user.sql
+features
+auth
-authController.js
-authRoutes.js
server.js file contents:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
const cookieParser = require('cookie-parser');
const secrets = require('./config/secrets');
const massive = require('massive');
// used to create, sign, and verify tokens
var jwt = require('jsonwebtoken');
// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
app.use(cookieParser());
//routes
require('./features/auth/authRoutes')(app);
//Connect to database
massive(secrets.development).then(db => {
app.set('db', db);
});
// Angular DIST output folder
app.use(express.static(path.join(__dirname, '../dist')));
//Set up static files
app.use(express.static('../dist'));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/index.html'));
});
//Set Port
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
get_user.sql file contents:
SELECT * FROM users WHERE username = $1;
authController.js file contents:
const jwt = require('jsonwebtoken');
const secrets = require('../../config/secrets');
const bcrypt = require('bcrypt');
module.exports = {
login: (req, res) => {
req.app.get('db').get_user(req.body.username).then(user => {
if(user[0]) {
bcrypt.compare(req.body.password, user[0].password,
function(err, result) {
if(result) {
var token = jwt.sign({user}, secrets.tokenSecret,
{expiresIn: '1h'});
res.status(200).json({
token: token,
user: user
})
} else {
res.status(200).json("Invalid username and/or
password.");
}
});
} else {
res.status(200).json("Could not find that user.");
}
})
}
}
authRoutes.js file contents:
var authController = require('./authController');
module.exports = (app) => {
app.post('/user-auth', authController.login);
}
The error is occuring in the authController.js file on this line:
req.app.get('db').get_user(req.body.username)
I've been reading the docs for massive js and learned the importance of keeping the DB folder on the same level where it's initialized, which is my server.js file.
As I stated earlier, when I run this on my local machine, it works great; However as soon as I deploy it to my live environment, I receive the error.
Any help or direction would be greatly appreciated. Let me know if any other information is required, and I will gladly provide it.
Your app setup should probably be wrap like
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
const cookieParser = require('cookie-parser');
const secrets = require('./config/secrets');
const massive = require('massive');
// used to create, sign, and verify tokens
var jwt = require('jsonwebtoken');
//Connect to database
massive(secrets.development).then(db => {
// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
app.use(cookieParser());
app.set('db', db);
// Angular DIST output folder
app.use(express.static(path.join(__dirname, '../dist')));
//routes
require('./features/auth/authRoutes')(app);
//Set up static files
app.use(express.static('../dist'));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/index.html'));
});
//Set Port
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
});
I am writing a simple MEAN app, and I am currently working on the routes.
In my server.js, I have
var express = require('express');
var multer = require('multer');
var upload = multer({dest: 'uploads/'});
var sizeOf = require('image-size');
var app = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
// configuration ===========================================
require('./app/models/Purchase');
require('./app/models/Seller');
require('./app/models/User');
// config files
var db = require('./config/db');
var port = process.env.PORT || 8080; // set our port
// mongoose.connect(db.url); // connect to our mongoDB database
// get all data/stuff of the body (POST) parameters
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(bodyParser.urlencoded({ extended: true })); // parse application/x-www-form-urlencoded
app.use(methodOverride('X-HTTP-Method-Override')); // override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
// routes ==================================================
var routes = require('./app/routes/routes');//(app); // pass our application into our routes
var price = require('./app/routes/pricing');
var processing = require('./app/routes/processing');
var uploads = require('./app/routes/uploads');
var seller = require('./app/routes/seller');
app.use('/', routes);
app.use('/price', price);
app.use('/processing', processing);
app.use('/uploads', uploads);
app.use('/seller', seller);
// start app ===============================================
app.listen(port);
console.log('Magic happens on port ' + port);
exports = module.exports = app;
Then, in my route, I have
var express = require('express');
var mongoose = require('mongoose');
var Seller = mongoose.model('Seller');
var router = express.Router();
router.get('/', function(req,res){
res.json({message: 'youre in router.get'});
});
router.post('/registerSeller', function(req,res,next){
console.log('You made it all the way to seller route!');
res.json({message: "you did it"});
next();
});
module.exports = router;
When I start my node server, everything goes well. When I use Postman to POST to the above route, it just 'hangs' and eventually gives an error message that it cannot connect. In Postman, I select 'POST' to http://localhost:8080/seller/registerSeller.Clicking 'code', I get
POST /seller/registerSeller HTTP/1.1
Host: localhost:8080
Cache-Control: no-cache
Postman-Token: 070cb9b3-992a-ffd6-cede-c5b609bc9ce5
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Looking at the browser's developer tools, it shows a POST being made, and then after a while, it also reads that the POST failed.
Could anyone tell me what I'm doing wrong? Thank you.
The problem is that you are responding and then trying to call the next() function in the router stack.
router.post('/registerSeller', function(req,res,next){
console.log('You made it all the way to seller route!');
return res.send({message: "you did it"});
//next(); remove this shit.
});
This should work. Express middlewares go in order. So if you need to have a middleware to be called before this function, then you have to put it before in the stack. If you need to do something after this function, forget about the res.json... part.
I need to set some common global variables in one config file and will get those values where required using Node.js. Here I need to implement process.env. My code is below:
var port=8989;
var express=require('express');
var morgan = require('morgan');
var http=require('http');
var bodyParser= require('body-parser');
var methodOverride = require('method-override');
var mongo = require('mongojs');
var session = require('express-session');
var multer = require('multer')
var app=module.exports=express();
var server=http.Server(app);
var admin=require('./route/route.js');
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
app.use(methodOverride()); // simulate DELETE and PUT
app.use(session({secret: 'FGDPlexel',resave: true,saveUninitialized: true}));
app.get('/',function(req,res){
res.sendFile(__dirname + '/index.html');
})
var storage =multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
server.listen(port);
console.log("Server is running on the port"+port);
Here I am assigning port=8989 but here I need to create one config file and will assign all variable there. In this server.js that file will include and user will get the required values.
You can use the dotenv npm package. It requires you to setup an .env file with key-value pairs in the format KEY=VALUE like SECRET_KEY=MEGASECRETKEY.
const dotenv = require('dotenv');
dotenv.load({
path: '.env.globals' // example
});
and you can access your variables like process.env.SECRET_KEY
It is not very clear for me what you are specifically asking for, but for configuration purposes, you can create your own config.js file and require it.
For instance;
var settings = {
port: process.env.PORT
};
module.exports = settings;
Then at your server.js, you can require this file.
var settings = require('./config.js');