we are using Node.js + Express as back-end for an Angular2 app. One of the modules of the back-end is responsible for the information gathering about products, based on barcode, which is a param for the Express router. Currently, we're facing an issue when adding a GET request route that does not use the barcode param.
The router file looks as follows:
'use strict';
const express = require('express');
const router = express.Router();
const prodCtrl = require('./controller');
const auth = require('../middlewares/authenticationBearer');
module.exports.init = function(app) {
router.param('barcode', prodCtrl.findById);
router.get('/products/:barcode', auth.bearer(), prodCtrl.getProduct);
router.post('/products/article', auth.bearer(), prodCtrl.getProductData);
router.get('/products/csv', auth.bearer(), prodCtrl.csv);
return router;
}
The problem is the /products/csv route. In its current position, calling the route gives a 404 error seemingly because the param barcode is expected, as the function prodCtrl.findById is called first. By moving this route before the /products/:barcode route like so:
'use strict';
const express = require('express');
const router = express.Router();
const prodCtrl = require('./controller');
const auth = require('../middlewares/authenticationBearer');
module.exports.init = function(app) {
router.param('barcode', prodCtrl.findById);
router.get('/products/csv', auth.bearer(), prodCtrl.csv);
router.get('/products/:barcode', auth.bearer(), prodCtrl.getProduct);
router.post('/products/article', auth.bearer(), prodCtrl.getProductData);
return router;
}
the code works fine. Is this a bug in Express? Or am I missing something here?
You should put '/products/:barcode' route after '/products/article' because it blocks the request to get to the article (the barcode param catch any suffix)
Related
I am trying to make post request but unable to get values in Postman; it's sending undefined. I am using Express version 4.17.1. Below is my code:
const express = require('express');
const router = express.Router();
const MongoClient = require('mongodb').MongoClient;
const dburl = process.env.URL;
router.use(express.json());
router.use(express.urlencoded({extended:true}));
router.post('/register',(req,res) => {
var data = {
name:req.body.name,
email:req.body.email,
};
res.send(data);
});
module.exports = router;
What am I doing wrong?
Your code snippet works, tested with express 4.17.1 on node 12.19.0. The issue must be from elsewhere.
Possible issues are:
The parser for router could have been overridden by the parser for app (assuming you're calling app.use(router) somewhere).
Can you move this to app level?
router.use(express.json());
router.use(express.urlencoded({extended:true}));
I want to use router.all('path', RouterObject) for all method with right path to route to RouterObject.
const express = require("express");
const signup = require("./signup");
const router = express.Router();
router.all("/signup", signup);
router.use((_req, res) => res.status(404).send(`<h1>Page Not Found</h1>`));
./signup.js
const express = require('express');
const router = express.Router();
const controller = require('../controllers/signup');
router.get('/', res.send("OK");
module.exports = router;
but It doesn't work as what I was expected.
It shows 404 Page, not 'hello', when I request with 'GET /signup'.
I want to use the signup module with same path name for '/signup' (not '/signup/something')
I tried router.use("/signup", signup);, It works, but I don't want pass the request with path like path '/signup/something' to the signup module.
How can I fix the problem using router.all() or is there any better way?
How can I successfully configure my routes to access multiple methods on my controller accordingly to the endpoint and parameters passed to the URL?
When accessing /companies/:companyId/createCheques I would like to call the method createCheques in cheques controller but it is still calling createCheque.
I tried adding the line below to routes/cheques.js but it did not work.
router.route('/:companyId/createCheques').post(createCheques)
// routes/companies.js
const express = require('express')
const {
getCompanies,
getCompany,
deleteCompany,
createCompany,
updateCompany,
} = require('../controllers/companies')
// Include other resource routers
const userRouter = require('./users')
const chequeRouter = require('./cheques')
const redeemRouter = require('./redeems')
const router = express.Router({ mergeParams: true })
// Re-route into another resources routers
router.use('/:companyId/users', userRouter)
router.use('/:companyId/cheques', chequeRouter)
router.use('/:companyId/createCheques', chequeRouter)
router.use('/:companyId/redeems', redeemRouter)
router
.route('/')
.get(getCompanies)
.post(createCompany)
router
.route('/:id')
.get(getCompany)
.put(updateCompany)
.delete(deleteCompany)
module.exports = router;
// routes/cheques.js
const express = require('express')
const {
getCheques,
getCheque,
deleteCheque,
createCheque,
createCheques,
updateCheque
} = require('../controllers/cheques')
// when more than 1 url param is possible to the same route, mergeParams must to be set to true
const router = express.Router({ mergeParams: true })
// Advanced results
const Cheque = require('../models/Cheque')
const advancedResults = require('../middleware/advancedResults')
router
.route('/')
.get(advancedResults(Cheque, 'cheques'), getCheques)
.post(createCheque)
.post(createCheques)
router
.route('/:id')
.get(getCheque)
.put(updateCheque)
.delete(deleteCheque)
module.exports = router;
The problem you have is that you are defining two POST controllers for the exact same route.
If you want to call both controllers createCheque and createCheques, when a POST is done to :companyId/createCheques/, you only need to add next() on the last line of createCheque, just like a middleware. See https://expressjs.com/es/4x/api.html#router
If you only want to call one controller, then you need to create a separate route for the other controller on your routes/cheques.js file.
router
.route('/cheques') //here the complete path would be companyId/createCheques/cheques
.post(createCheques)
I have 2 routes:
/api/system/list - list my systems
/api/system/:systemId/books/list - list books of current system
And different file for each API:
systemAPI.js:
const list = router.get('/list', Validate(Validation.list), listHandler)
return {
routes: [list]
}
bookAPI.js:
const list = router.get('/list', Validate(Validation.list), listHandler)
return {
routes: [list]
}
Finally, use the above routes:
express.use('/api/system', systemAPI.routes)
express.use('/api/system/:systemId/book', bookAPI.routes)
The problem is, when I'm entering list-books API (/api/system/:systemId/books/list), its actually calling the list-systems API (/api/system/list)
Update: Solved!
I had 2 main problems:
routes order (in app.use(..))
use different instance of Express.Router() on each API
Refer the answer below for more information.
Try reversing the order of the routes and this will probably solve your problem:
express.use('/api/system/:systemId/book', bookAPI.routes);
express.use('/api/system', systemAPI.routes);
The reason is that express evaluates routes 'greedily' and it will even resolve to partial matches. So, it is important to keep the more specific routes first before the more general ones.
Also, I think you are using the express router wrong according to the documentation the systemAPI:
const express = require('express');
const router = express.Router();
router.get('/list', Validate(Validation.list), listHandler)
module.exports = router;
The bookAPI route:
const express = require('express');
const router = express.Router();
router.get('/list', Validate(Validation.list), listHandler)
module.exports = router;
Finally import the routers and use them:
const express = require('express');
const bookRouter = require('./bookAPI'); //set the file paths based on your file structure
const systemRouter = require('./systemAPI');
const app = express();
app.use('/api/system/:systemId/book', bookRouter);
app.use('/api/system', systemRouter);
In my Node.js project I am using router file that imports controller files that have actual implementation of the methods. Like below.
app.js
'use strict';
var express = require('express');
var app = express();
var apiRoutes = express.Router();
routes.mainApi(apiRoutes);
app.use('', apiRoutes);
apiRoutes
'use strict';
var controller = require('../controller/apiController');
var uploadController = require('../controller/uploadController');
var fileUpload = require('express-fileupload');
module.exports.mainApi = function (apiRouter) {
apiRouter.post('/login', controller.login);
}
apiController
exports.login = function (req, res) {
// My code for login
};
I know when a api request comes then first app.js is executed. It further sends the request to apiRoutes as I called it in file. In apiRoutes when it finds
apiRouts.post(./login,controller.login) then it calls login function from controller. But I want to know that I am not passing req and res parameters anywhere in the login function then how they are being passed. Basically how this type of calling works.
Thanks in advance.
this function controller.login
as a callback parameter of r.post('path', callback)
and when controller.login is actual called by callback(request, response )
you will get req and res