Express router regex issue - node.js

I am using express router in my project, I am facing following problem,
I have 2 routes as follows
router.get("/user/:id", (req, res) => {
console.log("---- ABCD ---");
});
router.get("/user/list", (req, res) => {
console.log("---- PQRS ---");
});
When i call, http://localhost:3000/user/list api, ABCD is printed in console instead of PQRS.
I know we can write regex in router to handle this situation. I tried with following code.
router.get("/user/:id(!list$)", (req, res) => {
console.log("----- ABCD ----");
}
After making this change, /user/:id api stop working. But /user/list api is working
Please let me know, If I am doing something wrong. Thanks!

The issue is not with regex but. Reorder your route definition so that the dynamic routes are at the bottom. See the code below
router.get("/user/list", (req, res) => {
console.log("---- PQRS ---");
});
router.get("/user/:id", (req, res) => {
console.log("---- ABCD ---");
});

Related

How to combine a regex with a req.params field in a route?

I am able to have both /apply and /register going to the same action using (note it's a regex and not a string):
app.get(/apply|register/, (req, res) => {
// ...
res.send("OK");
});
How do I write the route to make both "/apply/:id" and "/register/:id" go to the same action?
Use an array.
app.get(['/apply/:id', '/register/:id'], (req, res) => {
// ...
res.send("OK");
});

Fetching from the root '/' route seems to not work?

I have a very simple server in expressjs from which I'll be getting some data, so far I just created basic routes and checked if they work, but I have an issue with the main '/' one. I added some extra routes for comparison
app.get('/', (req, res) => {
console.log('request at /');
})
app.get('/ree1', (req, res) => {
console.log('ree1');
})
app.get('/ree2', (req, res) => {
console.log('ree2')
})
app.get('/ree3', (req, res) => {
console.log('ree3')
})
Every time I fetch (from the browser console even) all the "/ree" routes log in the console, but the '/' one doesn't react at all. What could be the cause of that? Perhaps I missed something when I was learning basics.

Very simple get request yields in error: 'Cast to ObjectId failed'

So I was testing my backend with postman and have no clue what the heck is going on at the moment. I got a file users.js where I define some of my routes. I import that file into my app.js with:
// Bring in the Users route
const users = require('./routes/api/users');
app.use('/api/users', users);
So all the api requests within users.js are actually going to /api/users/......
I defined a simple route here to test it out.
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('hello world')
})
module.exports = router;
So if I send a request with postman to: http://localhost:5000/api/users/ I get back a response: hello world
If I ONLY change the endpoint to something like /test, I get an error message. In other words, If I change the route to:
const express = require('express');
const router = express.Router();
router.get('/test', (req, res) => {
res.send('hello world')
})
module.exports = router;
And again send a request with postman to http://localhost:5000/api/users/test, I get back the following error message:
{
"stringValue": "\"test\"",
"kind": "ObjectId",
"value": "test",
"path": "_id",
"reason": {},
"message": "Cast to ObjectId failed for value \"test\" at path \"_id\" for model \"Project\"",
"name": "CastError"
}
Does anyone have a clue what is going on? I cannot see why this doesn't work...
EDIT:
Okay, so I figured it out, but I still don't know why it works in scenario 1 and doesn't work in scenario 2:
This works:
router.get('/test', (req, res) => {
res.send('hello world')
})
//load project
router.get('/:id', (req, res) => {
Project.findById(req.params.id)
.then(projectFound => {
res.status(200).send(projectFound)
})
.catch(err => {
res.status(500).send(err)
})
})
This doesn't work:
//load project
router.get('/:id', (req, res) => {
Project.findById(req.params.id)
.then(projectFound => {
res.status(200).send(projectFound)
})
.catch(err => {
res.status(500).send(err)
})
})
router.get('/test', (req, res) => {
res.send('hello world')
})
Order to Precedence of Controllers
:id is a variable. When you declare the router.get('/:id', (req, res) first, your test method never gets executed.
This is because :id takes the value of test.
And your code doesn't like the 'test' id, so you get an error.
When you declare the other method first, router.get('/test' is found first, and executed first for any request that is /test. All other requests are forwarded to the :id method.
Answer to Initial Question
var express = require('express')
var app = express()
app.get('/test', function (req, res) {
res.send('HELLO WORLD')
})
Source
I got a file users.js where I define some of my routes.
How are the routes defined?
Given the error message, presumably it is expecting /api/users/{id}, where {id} is a number, not a string like "test".

prevent express middleware from executing for same parent path

This is my code when.
I am hitting put API it is executing middleware 3 times but it should execute for put API only.
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.post('/api/user', (req, res) => {
//do something
});
app.use('/api/user', MiddlewareFun);
app.put('/api/user', (req, res) => {
//do something
});
please don't say use like this.
app.put('/api/user', MiddlewareFun, (req, res) => {
//do something
});
Well, it's happening, because you've made it to. If you want the middleware, to be executed at only selected method, you have to specify it. For example:
Instead of doing:
app.use('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
replace use method with put. As you'd bind regular route:
app.put('/api/user', MiddlewareFun)
app.put('/api/user', (req, res) => {
//do something
})
Also, one more thing. You don't have to duplicate your middleware call before every route declaration. If you want to apply a middleware to your whole router, you can use .use() (as you did), or .all(); which will result in the same behavior.
The middlewares in Express are binded to app or to router.
The solution to yuur problem is to check the method of the request object at the middleware
let MiddlewareFun = function (req, res, next) {
if (req.method === 'PUT') {
// do something
}
next()
}
app.use('/api/user', MiddlewareFun);
The answer is, You need to write express middleware which is part of your app or router. You can write as many middlewares you want, but in your case you just need it only once and here is the implementation of that.
const MiddlewareFun = function(req, res, next) {
// req is object which consist of information about request made.
// From req object you can get method name which is called.
if(req.method.toLowerString() === 'put') {
// your logic goes here
}
next();
}
app.use('/api/user', MiddlewareFun);
app.get('/api/user', (req, res) => {
//do something
});
app.post('/api/user', (req, res) => {
//do something
});
app.put('/api/user', (req, res) => {
//do something
});

How do I automatically return a 404 when a GET path doesn't exist?

I am using NodeJS, Express and Handlebars (template engine) to build a web application. Currently I'm trying to automatically redirect users whenever they enter an URL that does not exist (or whenever they might not have access to it).
The following returns the index page:
router.get('/', (req, res) => {
res.render('index/index');
});
But how do I make something like this:
router.get('/:ThisCouldBeAnything', (req, res) => {
res.render('errors/404');
});
The following example is from Github:
Say that I enter this URL:
https://github.com/thispagedoesnotexist
It automatically returns a 404. How do I implement this in my application?
Thanks in advance.
Use a middleware just after all route handlers to catch non existing routes:
app.get('/some/route', function (req, res) {
...
});
app.post('/some/other/route', function (req, res) {
...
});
...
// middleware to catch non-existing routes
app.use( function(req, res, next) {
// you can do what ever you want here
// for example rendering a page with '404 Not Found'
res.status(404)
res.render('error', { error: 'Not Found'});
});
After all your other routes you can add:
app.get('*', (req, res) => {
res.render('errors/404');
});
Alternately, you can use a middleware function after all your other middleware and routes.
app.use((req, res) => {
res.render('errors/404');
});
So you might end up with something that looks like:
//body-parser, cookie-parser, and other middleware etc up here
//routes
app.get('/route1', (req, res) => {
res.render('route1');
});
app.get('/route2', (req, res) => {
res.render('route2');
});
//404 handling as absolute last thing
//You can use middleware
app.use((req, res) => {
res.render('errors/404');
});
//Or a catch-all route
app.get('*', (req, res) => {
res.render('errors/404');
});
I see that you have express tagged. All you have to do is include a default handler that includes
res.status(404).render('404template')
For example
app.get('*', (req, res,next) => {
res.status(404).render('error.ejs')
});

Resources