vars in express routes are blocking any following routes - express

I'm trying to use vars in my Express routes. They work fine but after i use a variable in a route, any routes after that one will not work. Here's really simple example.
/////////////////////////////////////////////planets
router.get('/:planetID', function(req, res, next) {
if(req.params.planetID == "hoth"){
res.render('index', {
title: 'Hoth',
subtitle:"Damn its cold"
});
}
});
////////////////////////////////////////////////jedi
router.get('/jedi', function(req, res, next) {
res.render('characters', {
title: 'Jedi',
subtitle:"why the f is this happening?",
});
});
In this example, the jedi route doesnt render anything. But if i put the jedi route before the planet route, everything works fine. Has anyone encountered this before?
Many thanks in advance for any help.

Express routes work in a pipe, that means that it will first check the first route and it will see that it accepts a parameter and it cannot see any difference between "/23423423" and '/jedi'. It assumes that jedi is an ID aswell. you should prefix it with
/planet/:planetID
for them not to conflict each other.

Express uses path-to-regexp for matching the route paths; see its documentation for all the possibilities in defining route paths. Apart from that, when you are working in express middle wares, do take care of the order of middle wares defined.
Note : Router is also a middleware in Express.
So you are working with two routes :
/:planetId
/jedi
If you define route /:planetId at the top then it actually treats /jedi as the same route with value of param planetId = jedi, whereas if you place your second route i.e.; /jedi at the top then it goes for exact match condition and if it find /jedi then only it executes the corresponding action else it will try with other routes defined.

ahh ok scopsy, now I see how your /23423423 example applies. Im sorry guys, I didnt post enough info I'm realizing. I had to use an if() statement to tell the route to move on if it didnt find a match. I did this using the next() function and a counter var.
router.get('/:planetID', function(req, res, next) {
var counter = 0;
planetJSON.planets.forEach(function(item){
counter++;
if(item.link == req.params.planetID){
planetDisplay.name = item.name;
planetDisplay.text = item.text;
planetDisplay.image = item.image;
res.render('index', {
planetGrab:planetDisplay,
planetList:planetJSON
});
}//end if()
else if(counter + 1 > planetJSON.planets.length){
next();
}
});//end for each()
});//end router.get
thanks again for your help

Related

Vue axios delete request not working. How do I fix it?

Im having issues with delete request, my post, get are working fine.
What am I doing wrong?
removeUser(id) {
axios.delete('https://jsonplaceholder.typicode.com/users' + id)
.then(function(response) {
const user = response.data;
this.users.splice(id, user);
});
if response.status === 204, then delete is succeed.
for the client, here is an axios example, notice there is a ' after users
destroy() {
return request.delete('/api/users/' + id)
}
for the server, here is an Laravel example:
if( $article->delete() ) {
return response()->json(null, 204);
} else {
abort(409);
}
I can see only 1 problem on the code you provided.
You're trying to modify the Vue instance $data users object by executing this.users.splice(id, user);. But you're inside the callback function and this no longer represents the Vue instance.
To fix this & make the users object actually modify after the response comes you'll need to do it like this :
removeUser(id) {
let that = this;
axios.delete('https://jsonplaceholder.typicode.com/users' + id)
.then(function(response) {
const user = response.data;
that.users.splice(id, user);
});
Now , I don't have any code from the back-end so I'll just make some assumptions :
The route might not be well defined > if you're using NodeJS then you should check your routes , it should look like this :
router.route('/users:id').delete(async function(req,res,next){ /* ... */ });
You might have a route problem because / is missing before the user value
1 hint : Again , if you're using NodeJS , you could use this inside your .delete route :
res.status(200).json({ errorCode : null , errorMessage : null , users : [] });
To see if you're receiving it on front-end.
I think you do need to append the trailing '/' to the URL, that way the URL is properly formed, such as "https://jsonplaceholder.typicode.com/users/123" (rather than "users123" at the end).
Aside from that, the first parameter to Array.prototype.splice is the position where item removal should begin. The second (optional) parameter, deleteCount, is the number of items to remove. Beyond deleteCount, you can pass a collection of objects which are to be inserted after the start position and after items have been removed.
You just need to find the object in your this.users array and remove it. If you want to use Array.prototype.splice for that, then you can use Array.prototype.findIndex to find the index of the user in the array then remove it:
// Find the index of the item to remove
const indexOfUserToRemove = this.users.findIndex(u => u.id === id);
// Call splice to remove the item
this.users.splice(indexOfUserToRemove, 1);

Getting requested page route in Nuxt middleware

I have a very simple 'named' Nuxt middleware set up (taken from the docs) which checks in the store to see whether a user is authenticated before they can navigate to certain routes. If the user is not authenticated, they are directed to a straightforward form in which they have to provide an email address to gain access (at http://example.com/access). All of that works fine, after they fulfil the middleware's store.state.authenticated check they can navigate around no problem.
export default function ({ store, redirect }) {
if (!store.state.authenticated) {
return redirect('/access')
}
}
My question is, once the user has entered their email address, I have no way of knowing what route they were initially trying to access. I've looked at other questions here about passing data between routes but because of the way the middleware works these solutions don't seem to be feasible.
I really would rather not set the slug in the vuex state as this will lead to a whole other set of complications – I also don't mind setting the intended slug as a query or a param on the /access url. I have read through the docs for the Nuxt redirect function and realise you can pass a route.query as an argument. So it seems that you could potentially do something like this:
return redirect('/access', intendedSlug)
...or, if using params(?):
return redirect(`/access/${intendedSlug}`)
But I don't know how to pass that intendedSlug value to the middleware in the first place as it's not exposed on the context passed to the function or anywhere else. It seems like this would be a common problem, but I can't find any simple solutions – any help would be really appreciated!
To help #Bodger I'm posting how I resolved this, it may not be perfect and it's working on a slightly older version of Nuxt (I know 😵!) but this is how I resolved the issue.
.../middleware/authenticated.js
export default function (context) {
const path =
context.route.path.length && context.route.path[0] === '/'
? context.route.path.slice(1)
: context.route.path
const pathArray = path.split('/')
if (process.server && !context.store.state.authenticated) {
return context.redirect('/access', pathArray)
} else if (!context.store.state.authenticated) {
return context.redirect('/access', pathArray)
}
}
The pathArray is then accessible in my /access page.
.../pages/access.js
data() {
return {
attemptedRoutePathArray: Object.values(this.$route.query)
...
}
},
...
computed: {
attemptedRouteURL() {
return new URL(
this.attemptedRoutePathArray.join('/'),
process.env.baseUrl
)
},
...
}

ExpressJS - Small curiosity

My thing is a small project.
In main what it does is that the "server" will get a call from the link directly what will run some functions that will update the database and the data that has to be shown.
I will show what I mean:
function updateData(){
connection.query(`SELECT * FROM muzica WHERE melodie = "${updateList()}"`, function (error, rezultat, fields) {
if (error) {console.log('err la selectare')};
//express output
let data = {
melodie: rezultat[0].melodie,
likes: rezultat[0].likes
}
console.log(data.likes);
app.get('/like', (req,res) =>{
res.json(`${data.likes}`);
});
}
setInterval(()=>{
updateData();
}, 20000)
Uhh, how to explain it, I'm so bad at this...
So, in main, I'm new to back-end work, everything that I did was based on their Documentation as I learn way faster by my needs than some guides and so on.
So, when I or someone does my http://website/like it should show just data.likes, cause that is all that I need, don't count data.melodie (i will clean that later on) after I finish all the code.
Anyway, whenever I do website/like data.likes is not updating to the new database data.likes.
For example, data.likes before were 5, in a few minutes it can be 2 but whenever I call website/like show "5" than its new value 2.
Don't be hash on me, I'm new and I want to learn as much as I can, but I can't understand the above case, by my logic it should ALWAYS show what its in database when it refreshes each 10 seconds(I run this in localhost so I will not stress any online server).
But if there is any better way to check for databases update than "setInterval" please notice me.
It's hard to learn alone without a mentor or someone else to talk about this domain.
Thank you for your time!
Kind regards,
Pulsy
You have things a bit inside out. A request handler such as app.get('/like', ...) goes at the top level and you only ever call it once. What that statement does is register an event handler for any incoming requests with the /like path. When the server receives an incoming request for /like, it will then call the function for this route handler.
You then put inside that route handler the code that you want to run to generate the response and send the response back to the client.
app.get('/like', (req, res) => {
connection.query(`SELECT * FROM muzica WHERE melodie = "${updateList()}"`, function (error, rezultat, fields) {
if (error) {
console.log(error);
res.sendStatus(500);
} else {
//express output
let data = {
melodie: rezultat[0].melodie,
likes: rezultat[0].likes
}
res.json(data);
}
});
});
The endpoints need to be outside of any functions in express.
For example, if you look at the express "hello world" example here, you will see that they have a basic app that only has a single GET endpoint defined which is "/" so you would access it by running "localhost/" or "127.0.0.1/".
In your case, you want your endpoint to be "/like", so you must define something like:
const express = require('express')
const app = express()
const port = 3000
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
app.get('/like', (req, res) => {
// do database stuff and assign data variable
// res.json(data);
}

NodeJS Express Moongose route regex [duplicate]

This question inspired by this post but in my case I need to filter MongoId. Is it possible to make filtering easily that the below because I need use it in each route?
app.post('/:mongoId(^[0-9a-fA-F]{24}$)', function(req, res){
// Send query based on mongoId
}
You're almost there, just don't add the ^ and $ anchors. And the uppercase A-F range isn't even necessary since Express seems to match case-insensitive:
app.post('/:mongoId([0-9a-f]{24})', function(req, res){
var id = req.param('mongoId');
...
});
According to the Express API documentation, yes, you can use a regular expression as a path:
Regular expressions may also be used, and can be useful if you have
very specific restraints.
app.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){
var from = req.params[0];
var to = req.params[1] || 'HEAD';
res.send('commit range ' + from + '..' + to);
});

expressjs not passing req.params through middleware

Similar to this
I have the following route:
app.get('/blogpost/:link', middleware.loginCheck, blog.postBlogs);
Using req.params.link returns the link parameter.
When I ask for the req.params.link in middleware.loginCheck I receive an undefined.
It seems that req.params.link is not being passed through to the middleware because I can access it like so:
app.get('/blogpost/:link', function(req, res){console.log(req.params.link)});
Whats the problem with my middleware?
FINAL
a(href='/post/#{post.link}') #{comments} renders /post/myPostLink
{#post.link} only renders the variable substitute and does not add an extra /
a(href='/post#{post.link}') #{comments} renders '/postmyPostLink'
a(href='/post/' + post.link) #{comments} renders /post/myPostLink
So both #{post.link} or post.link work the same and req.params.link works on both calls.
UPDATE_2
I am using jade to render the web page. Inside there I have an anchor tag written as so: a(href='/post/#{post.link}) #{comments}
The achor tag works fine and directs me to the correct page. But express does not like this representation. Instead, if I change the anchor tag to a(href='/post/' + post.link) #{comments} req.params.link works fine.
UPDATE_1
req.param('link') works for this case.
There is no problem with the middleware.
But why wouldn't req.params.link work?
OK, we went back and forth in the comments a bit, but now my guess is that the problem is double slashes in your URL
a(href='/post/#{post.link}') #{comments}
That is A) missing a closing quote, but I assume that is a typo just in your question here, not in your code. and B) the real problem is that post.link includes a leading slash, so you end up with this HTML:
<a href='/post//post_link_name'>42</a>
Thus express is parsing that as an empty :link parameter. Change your jade to this:
a(href='/post#{post.link}') #{comments}
and you should get back in business.
In recent versions of express you can use router.param() as your middleware to specifically work on the req.params:
var router = express.Router();
router.param( "nickname", function (req, res, next, nickname) {
console.log( "nickname: ", nickname );
next();
});
router.get( "/user/:nickname", myController.method );
what does the signature of middleware.loginCheck look like? It needs to return a function(req, res, next)