Express route with optional parameter? - express

I have an Express route for public-sitemap.xml:
app.get("/public-sitemap.xml", function(req, res) {
// do stuff
});
I'd like to support URLs like public-sitemap-1.xml, public-sitemap-2.xml as well.
How can I allow these optional parameters in Express?
If I set the route to /public-sitemap-?:id?.xml that allows public-sitemap-1.xml etc, but it also allows public-sitemap1.xml, which I'd prefer to reject.

Is this what you're looking for?
/public-sitemap(-:id?)?.xml
More info here: https://expressjs.com/en/guide/routing.html

Use this:
app.get("/public-sitemap-:id(\\d+).xml", function(req, res) {
// do stuff
});

Related

How do you access previous params in router file in express.js?

let's say I create a router like so in the app file:
const usernameRouter = express.Router();
app.use('/:username', usernameRouter);
When I'm in the router file, how would access that :username variable?
There is no built in way to get that parameter from the sub-route. You'd have several options:
1) Use req.originalUrl
In your sub-route handler, parse it out of req.originalUrl.
2) Move the /:username into the route declaration
Don't use a wildcard when sending to the router. Instead, just do this:
app.use(usernameRouter);
And, then inside of usernameRouter, do this:
router.get("/:username/something", ...);
So, you can then use req.params.username to get access to that.
3) Create middleware to capture req.params.username
Use a middleware function to set the parameter to a place you can get to it:
app.use('/:username', (req, res, next) => {
req.username = req.params.username;
usernameRouter(req, res, next);
});
Then, you can access it from req.username in the sub-routes.

When to use () in a middleware and when to use just reference

var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')
var app = express()
async function validateCookies (req, res, next) {
await cookieValidator(req.cookies)
next()
}
app.use(cookieParser())
app.use(validateCookies)
// error handler
app.use(function (err, req, res, next) {
res.status(400).send(err.message)
})
app.listen(3000)
In the above code both cookieParser() and validateCookies are middlewares but the way of executing them are different. There is a function like () with cookieParser but not with validateCookies. Can someone please explain why? Sorry If I am sounding foolish.
The app.use() function takes a single parameter, which is a function reference for a function that serves as a middleware for your router in Express.
You’ve correctly included the reference to your validateCookies function without parenthesis, as you just want Express to know which function you’d like it to use as middleware, and not to execute it at the time (Express will invoke the function for you when it’s time).
cookie-parser is a bit of an outlier (and I can see from where your confusion stems). The cookieParser() function actually returns a function reference upon successful execution. This design is likely because this particular module allows developers to pass in certain values to change the resulting function’s behavior as a middleware.

Express handle routes with regex

I have an route like as '/antalya-ucak-bileti' and 'antalya' word will be dynamically change. How can I handle it in routes?
I'm used NodeJS and ExpressJS
Thanks
This should work:
app.get('/:destination-ucak-bileti', (req, res) => {
console.log('P', req.params.destination);
res.end();
});

What is the difference between get/post/... and use

All:
I am new to Express 4 router.
When I tried some login/signup example, I got one question about the .use and .get/.post function:
I saw sometimes it uses:
var express = require('express');
var router = express.Router();
router.get('/hello', function(req, res, next) {
res.send("Welcome");
});
and in main app, we use it like:
app.use("/", router);
While some other time, it uses:
var express = require('express');
var router = express.Router();
//here the router uses .use() function rather than .get/.post
router.use('/hello', function(req, res, next) {
res.send("Welcome");
});
and in main app, we use it like:
app.use("/", router);
So I am wondering what is the difference between them, does the .use() just a general name for all of get/post/put/... together?
I find this post: Difference between app.use and app.get in express.js
But still not feel easy to understand this....
Thanks
In addition to what Jonathan Lonowski said in the posted link, it might help to not compare use to get and post, but to compare it to all because both all and use work regardless of the HTTP verb used while that's obviously not true for get. Everything I'm about to say applies if you replace "all" with "get", it'll just narrow that handler down to a specific HTTP verb.
So, what's the difference between all and use?
app.all will handle incoming requests at the specified URL path regardless of the HTTP verb, just as app.use does. However, how it compares the requested URL to the handler is different. For example:
var r = express.Router();
r.use('/foo', function (...) { ... }); // Route A
r.all('/bar', function (...) { ... }); // Route B
If you make a request to /foo/123 Route A will be run.
If you make a request, however, to /bar/123 Route B will NOT be run.
This is because with HTTP verbs express compares the full path, but with 'use' it only cares about the beginning of the url. Because the URL /foo/123 begins with /foo Route A will run, but because /bar/123 does not match the FULL URL, Route B will not be. Note: You could make .all behave in the same way: r.all('/bar/*', ...), but use is easier and more appropriate for this.
So, what you would tend to mount with one vs the other is different. For example:
var app = express();
var router1 = express.Router();
var router2 = express.Router();
router2.all('*', function (req, res) { ... }); // Must specify a path!
router1.use('/secondary-routes', router2); // Can't do this with all.
app.use(router1); // Look Ma, no path!
Here I've used all to handle a request coming in, where I've used use to mount an entire router. Also, note that the usage of router.METHOD functions require a URL string as the first parameter, while use does not.
At the end of the day, if you:
Want all requests that come in under a given path (or even every request) to use the specified middleware, or
Want to mount an entire sub router/application, or
Want to include a plugin into your application
... Then use is probably what you want.
If you:
Are handling a specific request at a specific URL path (i.e. probably not doing a * match in the URL)
Generally won't be calling next and will instead actually be handling the request
... Then an HTTP verb method (like get, post or all) is probably what you want.
.use is used in 2 cases, middlewares and "modular mountable route handlers".
In your example
router.use('/hello', function(req, res, next) {
res.send("Welcome");
});
This means that any requests sent to /hello will be terminated with "Welcome" and the actual .get attached to /hello will not be called.
So, in short, call use when you need to apply some general middlewares or want to do modular architecture with routers. use can be "used" as request handlers, but you shouldn't because it is not designed for that purpose

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