ExpressJS Router URL Matching - express

code below, when I visit url like this http://localhost/. It can match the first one, but when I visit http://localhost/detail-999, It match the first one again. It can not match the second one.
I want that when I visit http://localhost or http://localhost/list-1-1 can match the first one and when visit http://localhost/detail-999 can match the second one correctly...
I have no idea to fix this problem...
router.get('/|/list-:type-:page', function (req, res) {});
router.get('/detail-:itemId', function (req, res) {});

All you need is to wrap it to brackets like this:
app.get('(/|/list-:type-:page)', function (req, res) {
});

Try this:
router.get('/list/:type/:page', function (req, res, next) {});
router.get('/detail/:itemId', function (req, res, next) {});
It can be problematic designing your routes as you did. If you have params that can not be changed then you should handle the dashes in the route's action method and just do a req.params.list_name.split('-')

Related

How does next() work in express and what happens after res.send()?

const express = require('express');
const app = express();
app.use('/', (req, res, next) => {
console.log('This always runs!');
next();
});
app.use('/add-product', (req, res, next) => {
console.log('In add product middleware!');
res.send('<h1>The "Add Product" Page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In another middleware!');
res.send('<h1>Hello from Express!</h1>');
});
app.listen(3000);
NodeJS / Express: what is "app.use"?
I read from this post and still confused about how the flow-of-control goes in this program.How come if I visit "localhost:3000/add-product" the result logged is "This always runs!In add product middleware!This always runs!In another middleware!"(I omitted the changeline)
Does this mean after it goes into the second app.use,and as I've learnt,each app.use(middleware) is called every time a request is sent to the server.So this process restarts,but why this time next() would result in the third app.use being called?I thought next would go into the next matching path..
The order of route is important in express
Express match route based on first come first serve basis, just like a queue.
If a route matches, then whatever function you pass as callback will get called.
In your case:
Route 1: Match every route
Route 2: Match /add-product
Route 3: Match every route
So the order of checking would be 1 -> 2 -> 3
So if I make GET CALL TO /add-product
(1) and (2) will be called
and the following log
This always runs!
In add product middleware!
While call to / will
result in (1) and (3) being called.
This always runs!
In another middleware!
Next() is just passing the control to the next middleware

Make an endpoint in a single page application which doesn't serve the html file

I m using express to make a server.
app.get("/*", (req, res) => {
res.sendFile("index.html");
});
For every endpoint, I serve the same HTML. I handle the routes on the client-side.
How do I make an endpoint such that it doesn't server "index.html".
I tried adding
app.get("/abc", (req, res) => {
res.json(some data);
});
But it sends the index.html file
Express basically checks if the requested route matches the ones you've specified (from top to bottom). If it does, it follows the given instructions. The very first route you've specified is /* which means it will match any GET request that the user asks for. Since it has found a match, it will not proceed to check the other routs. So instead, you want to specify a route like this at the very end so that it checks the other routs first.
app.get("/abc", (req, res) => {
res.json({"key": "value"});
});
/*
This route has to be placed at the end
(just before the listener)
*/
app.get("/*", (req, res) => {
res.sendFile("index.html");
});

Needed explanation on Express MiddleWares with next

I have only one MiddleWare with next called inside, and the request-response cycle is ended even though i did not use the res.send(), how is that?
app.use("/", function (req, res, next) {
console.log(`${req.method} ${req.path} - ${req.ip}`);
next();
});

Express: How to properly define routes?

Suppose I have two routes defined like the following.
The first route is always executed, but the second one is not.
How should I define the routes, so that requests for /about.. are properly routed?
// First route
router.get('/:id', function (req, res) {
// This will always be executed
})
// Second route
router.get('/about/:name', function (req, res) {
// This will not be executed
})
Reverse the order
The routes are stored in a sequence in the order of your router.get() function calls. That is the order the routes are tested for a matching pattern. When you have a route that matches potentially everything, like an /:Id route, then you want to place it last. You then place the static non-changing ancillary pages before it.
In the example below I reverse the order so my static less specific route of "/about/" is checked first and if there is no match then express will compare the request to the next route for a URL match.
// Executed if match is found
router.get('/about/:name', function (req, res) {
})
// No match found on the above routes so try this one
router.get('/:id', function (req, res) {
})
//TODO: Good place for 404 handler...

Is there a workaround for express 4.x route('/path') with params support?

I'm using a expressjs 4.x to build a simple api on top of mongodb.
The api needs to serve a few sets of data:
/api/v1/datatype1
/api/v1/datatype2
For each data type, I have CRUD operations (post, get, put, delete).
The api requests would look like this:
POST /api/v1/datatype1
GET /api/v1/datatype1:_id
PUT /api/v1/datatype1:_id
DELETE /api/v1/datatype1:_id
If I create a router params like this:
dataType1ApiRouter.param("entity_id", function (req, res, next, id) {
//async db fetch here by id, then call next with fetched data
//or error if faild request/not found entity.
//let's say req.dataEntity = dataEtity; next();
} );
If I create a route like this:
dataType1ApiRouter.route("/datatype1")
.get(":entity_id", function (req, res, next) {
//expcet req.dataEntity to be fetched by the param filter.
})
.post(function(req, res, next) {
//just create an new dataType1 entity.
});
I am getting a syntax error. The route .get and .post (and other methods like those) expect just one parameter, resulting in an error:
Route.get() requires callback functions but got a [object String]
Is there a way to actually group all the "/datatype1" requests under one url declaration instead of repeating the method("datatype1:entity_id") for each method that requires the ID expect for the post method?
There isn't a clean way to do this with Router.route(), but you might consider doing this with another Router instead of a Route there. Then, you could just mount that sub-router.
Basic example, modifying the code you provided:
var mainRouter = express.Router(),
subrouter = express.Router();
subrouter.param("entity_id", function (req, res, next, id) {
// param handler attached to subrouter
});
subrouter.post('/', function(req, res, next) {
// post handler attached to base mount-point
});
subrouter.get("/:entity_id", function (req, res, next) {
// get handler attached to base mount-point/<id>
});
// here we mount the sub-router at /datatype1 on the other router
mainRouter.use('/datatype1', subrouter);
Note that this requires adding a '/' to the URL, so instead of /api/v1/datatype1[someidhere] it would be /api/v1/datatype1/someidhere