I have written simple express middleware to parse files and add them to req. It looks like this.
import formidable from 'formidable';
export const parseForm = (req, res, next) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if(err) {
next(err);
}
req.files = files; // eslint-disable-line
next();
});
};
I'm adding it to app like this(along with other middleware).
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(parseForm);
// static paths
const publicPath = express.static(path.join(__dirname, '../client/public'));
app.use(publicPath);
// routes
app.use('/api', adminRoutes);
app.use('/api', ingredientRoutes);
app.use('/api', productRoutes);
My problem is that despite calling next function in middleware my request is left hanging. Is next supposed to pass some arguments or maybe I'm passing my middleware in wrong fashion?
Thanks for help.
Turns out you can't use body-parser and formidable simultaneously. I resigned from body-parser and added to my middleware
req.body = fields;
Related
After trying to log some data on index file. I found my express server execute twice. Why do i get this error/bug?
Running Node 12.13.0 LTS, Express 4.17.1 and latest packages versions by the date of this post. I’ve tried on commenting some parts of code and always seem to end up running twice.
My app.js code:
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const path = require('path');
const bodyParser = require('body-parser');
const favicon = require('serve-favicon');
const app = express();
// ENV Variables
require('dotenv').config();
const PORT = process.env.PORT;
// Authentication Packages
const session = require('express-session');
const passport = require('passport');
// Middlewares
app.use(favicon(path.join(__dirname,'public','images','favicon.ico')));
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.json());
app.use(session({
secret: 'GBR6N7^?5Xx-Ldqxf&*-Hv$',
resave: false,
saveUninitialized: false,
//cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
// View Engine
app.use(expressLayouts);
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// Routes
app.use('/', require('./routes/index'));
// Controllers
app.use('/profile', require('./routes/profile'));
app.use('/products', require('./routes/products'));
app.use('/bookmarks', require('./routes/bookmarks'));
// Catch 404
app.use((req, res) => {
res.render('pages/404');
});
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
and my index.js code:
const express = require('express');
const router = express.Router();
// Official pages
router.get('/', (req, res) => {
// THIS IS THE CODE I GET TWICE ON CONSOLE
console.log(req.user);
console.log(req.isAuthenticated());
// THIS IS THE CODE I GET TWICE ON CONSOLE
res.render('pages/index');
});
router.get('/about', (req, res) => {
res.render('pages/about');
});
router.get('/features', (req, res) => {
res.render('pages/features');
});
// Footer pages
router.get('/terms', (req, res) => {
res.render('pages/terms');
});
router.get('/refunds', (req, res) => {
res.render('pages/refunds');
});
module.exports = router;
Also i have those two functions on my profile.js (for passport.js):
passport.serializeUser((userId, done) => {
done(null, userId);
});
passport.deserializeUser((userId, done) => {
done(null, userId);
});
I get those results twice:
console.log(req.user);
console.log(req.isAuthenticated());
Output (Executed twice!):
undefined
false
undefined
false
and I expect one:
undefined
false
Due to how Express routing works, the path / will match / and /about and /favicon.ico etc. This is because Express supports not just endpoint routing but also path mounting. In other words, express supports things like this:
const app = express();
const route = express.Router();
route.get('/world', (req, res) => { res.send('hello') });
app.get('/hello', route); // mounts world to hello
// so we can access /hello/world
In order to support the feature above, express needs to interpret paths such as /hello to mean both /hello and /hello/anything/else. It needs to treat it as both the endpoint and potentially just a path leading to an endpoint.
This means that if you have a path:
app.get('/', () => {});
It will also trigger if the browser requests /favicon.ico. And browsers request favicon.ico to draw the tiny icon in the browser tab. This is why your route is triggered twice.
A few things to keep in mind when writing Express routes/controllers:
Make sure that the / path is last because otherwise it will also respond to requests to all your other paths.
If you are using express.static() make sure it is set up before the / path. Yes, the first rule above should also cover this but I see this issue often enough that it merits its own point.
In your case you can possibly fix the issue by simply creating a favicon.ico icon and saving it in the static (public) folder.
When I use the "use" method my code works fine, but when I use the "get" it gives an error: "Cannot GET /route1".
My Code:
const express = require('express');
const app = express();
const expbs = require('express-handlebars');
const path = require('path');
const routes = require('./routes/handlers');
app.use(express.static('public'));
const hbs = expbs.create({
defaultLayout: 'main',
layoutsDir: path.join(__dirname, 'views/mainLayout'),
partialsDir: path.join(__dirname, 'views/pieces'),
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.get('/route1', routes);
app.listen(8080, () => {
console.log('Server is starting at port ', 8080);
});
I am new to node js, please tell me can i define routes with "get" method.
I believe your routes/handlers.js look something like this
var express = require('express');
var router = express.Router();
function greetUser(req, res){
res.send("Welcome dear user");
}
router.get("/", greetUser);
router.post("/", (req, res)=>{ res.send("user registered") });
module.exports = router
The problem here is this last line, this router object which is being exported works fine for app.use middleware, while .get or .post expects 2nd parameter to be a function
If you export this greetUser function from your router as well or receive this function from anywhere, this should start functioning well. Practically it would be
app.get("/route1", (req, res)=>{ res.send({status : true, message : "sample JSON"})})
If you are using router you coudn't use get method.
Here is the docs.
Only the handler has access to get method. app.use will add path to api route which point to get,post and etc.
You could only explicitly define a get as a standalone get route.
app.get('/route1', (req, res) => {
res.send("You have hit route1 - get");
});
When using router you could only include the router object as a parameter in app.use(path, routerObj) method.
app.get('/route1', routes);
woulde be app.use('/route1', routes);
I am new to nodejs/express and have followed a blog article "Build Node.js RESTful APIs in 10 Minutes". It provided detailed steps to create simple REST apis. After finishing every code mentioned in the article, the app have not been working properly, it would just return
{
"url": "/transactions not found"
}
I found that the culprit was in the last part of the article, which told me to add this line to server.js:
Having done all these, what happens if we entered a wrong route? say
you entered 'http://localhost:3000/task', It responds with a message
“Cannot GET /task”. Let’s add express middleware which could be used
to return more interactive messages.
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
It seems to hardcode a HTTP status code of 404 no matter what does my api returns. After removing this line, the app return meaningful response.
Here is my server.js:
var express = require('express'),
app = express(),
port = process.env.PORT || 3000,
mongoose = require('mongoose'),
Transaction = require('./api/models/transactionModel'), //created model loading here
bodyParser = require('body-parser');
// mongoose instance connection url connection
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/transactionDb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
var routes = require('./api/routes/transactionRoutes'); //importing route
routes(app); //register the route
app.listen(port);
console.log('Transaction List RESTful API server started on: ' + port);
And the controller:
'use strict';
var mongoose = require('mongoose'),
Transaction = mongoose.model('Transactions');
exports.list_all_transactions = function (req, res) {
Transaction.find({}, function (err, transaction) {
if (err)
res.send(err);
res.json(transaction);
});
};
exports.create_a_transaction = function (req, res) {
var new_transaction = new Transaction(req.body);
new_transaction.save(function (err, transaction) {
if (err)
res.send('Error creating a new transaction!');
res.json(transaction);
});
};
it wasn't override your response, just because it returned in the middle before touch your api. The flow of request is running from top to bottom, example in your code above:
[coming request] --> bodyParser --> bodyParser --> 404 handler (returned here) -x-> api (cannot reach).
Just use() 404 middleware to the bottom and everything works fine.
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/transactionDb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var routes = require('./api/routes/transactionRoutes'); //importing route
routes(app); //register the route
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
I suspect your
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
should be lower: the server is finding that piece of code first, while the actual routes are loaded later.
app.use means that it always executes that code, so it handles every request by sending a 404 error and saying it can't find the URL.
Put that code under all of the other routes (right above app.listen(port)) and it should work!
I am using the express.static built-in middleware function to serve static files, but the console prints the error: Can't set headers after they are sent.
here is my code, i don't know what is wrong with this
'use strict';
let path = require('path');
let express = require('express');
let bodyParser = require('body-parser');
let mongoose = require('mongoose');
let formidable = require('express-formidable');
let routes = require('./routes');
let app = express();
let port = process.env.PORT || 3000;
let db = mongoose.connect('mongodb://localhost:27017/old-driver');
// deal with img post
app.use(formidable({
uploadDir: path.join(__dirname, 'upload'),
keepExtensions: true
}));
app.use(bodyParser.urlencoded({extended: true }));
app.use(bodyParser.json());
// access-control
app.all('*', (req, res, next) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
res.set("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.set("X-Powered-By",' 3.2.1')
res.type("application/json");
res.type("jpg");
next();
});
// set assets path, GET /assets/demo.png
app.use('/assets', express.static('upload'));
routes(app);
app.listen(port);
the route middleware method:
getAllTeachers: (req, res) => {
Teacher.find({}, (err, teacher) => {
if (err) {
res.send(err);
} else {
res.json(teacher);
}
});
},
Even if I remove the access-contol code as shown below, still get error
let db = mongoose.connect('mongodb://localhost:27017/old-driver');
// deal with img post
app.use(formidable({
uploadDir: path.join(__dirname, 'upload'),
keepExtensions: true
}));
app.use(bodyParser.urlencoded({extended: true }));
app.use(bodyParser.json());
// set assets path, GET /assets/demo.png
app.use('/assets', express.static('upload'));
routes(app);
app.listen(port);
when I request 2 existing jpg file, I also get 404 error in one jpg file
404 screenshot
To solve this you need to use app.use function instead of app.all for mounting your middleware function. app.use adds the middleware function to middleware stack ensuring that they are executed in same order at which they are added.
So you need to do this :
app.use((req, res, next) => { //change app.all to app.use here and remove '*', i.e. the first parameter part
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
res.set("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.set("X-Powered-By",' 3.2.1')
res.type("application/json");
res.type("jpg");
next();
});
EDIT:
As you told in comments the above method doesn't work so what you can do is use the setHeaders method of express.static method to set headers before file is served like this :
app.use('/assets', express.static('upload', {
setHeaders: function(res, path) {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
res.set("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.set("X-Powered-By",' 3.2.1')
res.type("application/json");
res.type("jpg");
}
}));
Put this static file serving middleware method above the app.use so that app.use method for setting headers is not called hence the headers won't be set again.
I actually have a very tiny app in node.js with Express, and I can't access to req.body.
This is my app.js code:
var express = require('express'),
middleware = require('./middleware'),
mysql = require('mysql'),
app = express();
app.use(middleware.authenticate);
app.use(middleware.getScope);
app.listen(3000);
module.exports = app;
And the file with the middlewares:
var bcrypt = require('bcrypt'),
mysql = require('mysql');
function authenticate(req, res, next){
console.log(req.body);
next();
}
function getScope(req, res, next){
console.log(req.body);
next();
}
module.exports.authenticate = authenticate;
module.exports.getScope = getScope;
In all cases req.body is undefined.
I'm sending data throw Postman with x-www-form-urlencoded protocol, in this case is a must.
Thanks!!
You need to add body-parser to express:
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
Check Request here http://expressjs.com/en/api.html
And perhaps a POST route could help too:
app.post('/', function (req, res, next) {
console.log(req.body);
res.json(req.body);
});