vineet
vineet

Reputation: 14236

How to make optional params name in express route?

Here is below my code of route:-

app.get('/server/lead/get/:id?', leadCtrl.get);
app.get('/server/lead/filter/:filterQuery', leadCtrl.get);

As you see above i am using different route to access same controller method leadCtrl.get.

Now, i want something like route app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get params either req.params.id or req.params.filter but only one at a time.

Upvotes: 2

Views: 13226

Answers (2)

rsp
rsp

Reputation: 111296

What you asked in the question is not possible in the form that you describe it.

Now, i want something like route app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get params either req.params.id or req.params.filter but only one at a time.

Your router would have no way to differentiate those two parameters. If it got a request to /server/lead/get/X then what is X? A filter or an ID?

Your options

You have few solutions here:

  1. You can either keep using two routes like you did before.

  2. You can use a common parameter for both cases as Robert explained in the comments.

  3. Or you can use what seems to me the perfect solution for your use case - named query parameters - just use a route /server/lead/get and use query parameters to pass id and the filter.

Example URLs:

  • /server/lead/get?id=xxx
  • /server/lead/get?filterQuery=xxx

You will only have to make sure in your handler that only one of those two are set at a time with something like:

if (req.query.id && req.query.filterQuery) {
  // respond with error
}

You can even mix the two if you have app.get('/server/lead/get/:id?') route you can have the id in the route and filterQuery as a query parameter. Now the URLs would be:

  • /server/lead/get/xxx (for id)
  • /server/lead/get?filterQuery=xxx (for filter)

For more info see: http://expressjs.com/en/api.html#req.query

Better way

If you follow some REST conventions then you can use:

  • app.get('/server/lead/:id') for one object with id (not optional)
  • app.get('/server/lead') for a list of objects (with optional filterQuery passed as a query parameter)

That way you would always know that when you access:

  • /server/lead/xxx - then it's one object with ID = xxx
  • /server/lead - then it's a list of any objects
  • /server/lead?filterQuery=xxx - then it's a list of objects that match the query

If you follow the REST conventions for things like this instead of inventing your own, it would be much easier for you to design the routes and handlers, and it would be much easier for other people to use your system.

You may also want to use plural /server/leads instead of /server/lead which is common with REST. That way it will be more obvious that leads is a list and leads/id is one of its elements.

For more info see:

Upvotes: 5

robertklep
robertklep

Reputation: 203241

You have to realize that the following two routes match exactly the same:

app.get('/server/lead/get/:id?',     leadCtrl.get);
app.get('/server/lead/get/:filter?', leadCtrl.get);

Express doesn't care about how you name the placeholders, so any requests for /server/lead/get/SOMEVALUE will always match the first (the one with :id).

You can add a distinction yourself, by only allowing a parameter to match a particular regular expression. From your code, it looks like :id should match MongoDB ObjectId's, so you can create a specific match for those:

app.get('/server/lead/get/:id([a-fA-F0-9]{24})?', leadCtrl.get);

If SOMEVALUE matches an ObjectId, it will call leadCtrl.get and populate req.params.id. If you also add another router for "the rest", you can also cover the req.params.filter case:

app.get('/server/lead/get/:filter?', leadCtrl.get);

As an aside: you're saying that you're passing JSON to the "filter" routes, in the URL. I would strongly suggest using a POST route for that, and post the JSON as request body content.

Upvotes: 4

Related Questions