Home > Software design >  why does a route without path params needs to come before a path with path params
why does a route without path params needs to come before a path with path params

Time:03-15

When I ran my code like this I was having errors like castError: cast to object failed for value new

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

but when I switched the format like this the code was running normally on my local machine.

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

What could be the problem is it as a result of my path params or does order count I don't understand as am just beginning to learn express.js

CodePudding user response:

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

In the format above, the route above the new route includes a route parameter :id. Express matches anything that comes after /products as if it is the route parameter :id that's why in the format above you got an error.

For this one, express knows that if what comes after /products/ is new, it will run the code inside the app.get('/products/new', callback:

  app.get('/products/new', (req, res) => {
    res.render("products/new");
});

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

CodePudding user response:

In this case order matters. If you put the route with the param first (/products/:id), it will treat any routes that start with /products/ as a param route. Therefore, the route below will be treated as a products api call with id equal to new.

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

You can fix this by putting your param route after the new route.

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

CodePudding user response:

The routes are evaluated in the order that they are defined, and it also doesn't what what an id might look like.

So let's say you have a request going to /products/new

When your code looks like this:

app.get("/products/:id", async (req, res) => {
    const { id } = req.params;
    const product = await Product.findById(id);
    res.render('products/show', { product });
});

app.get('/products/new', (req, res) => {
    res.render("products/new");
});

The first route declared is "/products/:id", which is a match and req.params.id will equal "new". Because there was a match, it will not even look at routes that were declared after it.

*edit how you could have the "/products/:id" come first and still work the way you want, probably not the best but an example of the use case for the next param

app.get("/products/:id", async (req, res, next) => {
    const { id } = req.params;
    
    if (id === 'new') {
      next();
      return; // important to remember, without it the code below will also fire
    }
    

    const product = await Product.findById(id);
    res.render('products/show', { product });
});

app.get('/products/new', (req, res) => {
    res.render("products/new");
});
  • Related