how can I use router.all('path', Router Object') with Express? - node.js

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?

Related

How to structure a multiple post endpoints with node / express.js

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)

Express Router - different routes with same suffixes

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);

Routes in nodeJs + express

In the nodejs+express application can we have different routes files and include them into a single file. Like as below.
in hotel.routes.js I have few routes like
const express = require("express");
const hotelsCtrl = require("../controllers/hotels.controller");
const router = express.Router();
router
.route("/")
.get(hotelsCtrl.getAllHotels);
module.exports = router;
In the review.routes.js I have few routes like
const express = require("express");
const reviewsCtrl = require("../controllers/reviews.controller");
const router = express.Router();
router
.route("/")
.get(reviewsCtrl.getAllreviews);
module.exports = router;
Now I wanted to include both hotel.routes.js and review.routes.js in the index file and when the route is "/hotel" it should go to hotel.routes.js and when the route is "/review" it should go to review.routes.js
can someone please help in fixing this.
Thanks in advance.
You can do this:
app.use('/hotel', require('./hotel.routes.js'));
app.use('/review', require('./review.routes.js'));
This puts the hotel.routes.js exported router on /hotel and the review.routes.js exported router on /review.
It seems like you've a bit over complicated things by using three files in order to set up a single /hotel route.
You could also just do:
const hotelsController = require("../controllers/hotels.controller");
app.get('/hotel', hotelsController.getAllHotels);
There's really no need for the separate hotel.routes.js file.
Of, alternatively you could put the /hotel in the hotel.routes.js file like this:
const hotelsCtrl = require("../controllers/hotels.controller");
const router = require("express").Router();
router.get('/hotel', hotelsCtrl.getAllHotels);
module.exports = router;
And, then all you have to do in index.js is this:
app.use(require('./hotel.routes.js'));

Prefix all requests in JSON Server with middleware

I'm using the JSON Server package (json-server) from https://github.com/typicode/json-server. I'd like to make the server prefix all requests with /api/v2. The documentation even gives an example how to do this with the following:
server.use('/api', router)
However I don't want to setup my own server instance but extend the default when running json-server.
Can I somehow use the above statement in a middleware?
Since the router that json-server returns to you is an Express router.
First define all of your /v1, /v2, etc in its own routes file as show below:
// api-routes.js
const express = require('express')
const jsonServer = require('json-server')
const router = express.Router()
const server = jsonServer.create()
const middlewares = jsonServer.defaults()
const v1Router = jsonServer.router('db-v1.json')
const v2Router = jsonServer.router('db-v2.json')
router.use('/v1', v1Router)
router.use('/v2', v2Router)
module.exports = router
Then mount your API router onto /api like so:
const express = require('express')
const apiRoutes = require('./api-routes')
const app = express()
app.use('/api', apiRoutes)
// ...
Should now have /api/v1 and /api/v2. Untested code above, but should give an idea what you need to do.

Node express param issue

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)

Resources