Pass request to every Swig template using Express - express

Is it possible to pass request/req object to every template I render, so I wouldn't have to pass it as local in every render() method?

You can use res.locals for that.
Insert the following middleware somewhere before your routes:
app.use(function(req, res, next) {
res.locals.req = req;
next();
});
This exposes req as a variable in your templates.

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.

VueRouter make HTTP request within beforeEach

I am attempting to make an AXIOS request within router.beforeEach. However, it looks like the request is being made with my next destination URL being prepended; if trying to access /client/create, the beforeEach appears to prepend '/client/create' to the request.
Instead of '/api/participant/test/{some_id}' the request is being sent to '/client/create/api/participant/{some_id}'.
I'm not quite sure why this is happening. The documentation indicates that you could use a getPost() method to make requests:
beforeRouteEnter (to, from, next) {
getPost(to.params.id, (err, post) => {
next(vm => vm.setData(err, post))
})
},
However it seems the getPost() method is unrecognized, which could be because of the beforeEach call (the documentation does not show that this could be used with this particular method).
Here is the code with the AXIOS request.
router.beforeEach((to, from, next) => {
console.log(to.params.id);
// Check to see if the cookie exists
if (document.cookie.match(/^(.*;)?\s*participant_token\s*=\s*[^;]+(.*)?$/)) {
axios.get('api/participant/test/' + to.params.id)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}
Any ideas on how this can be avoided? I imagine one could use beforeRouteEnter for each of the routes I have set up, but this would be a more elegant solution.
It should be
axios.get('/api/participant/test/' + to.params.id)
(with forward slash character at the beginner).
The more properly way to set baseURL in axios config
For example:
axios.defaults.baseURL = 'your base url';
First, there is no built-in getPost method in Vue.js. Documentation has mentioned it just as an illustration purpose.
Also, use root relative URL instead of relative URL that you are trying to use.
axios.get('/api/participant/test/' + to.params.id)
You are trying to use relative URL which is causing a problem for you. The more generic way would be to set default base URL in Axios global config.

Reference app in express middleware

Supposing we have some middleware in express 4.0:
app.use((req, res, next) => {
// ... i want app here. except this
// method is imported from another file
// so app isn't in scope.
});
Is there any way to get the app object?
I'm writing several custom middleware packages and I keep finding myself needing to reference app (from another file of course). I'm doing hokey things like this:
app.use(fabMiddleware(app));
Which is really a high-order function:
const fabMiddleware = (app) => {
return function(req, res, next) {
// ... now i can use app
}
}
modue.exports = fabMiddleware;
Does perhaps this, req or res have a reference to app?
Yes you can access the app instance without needing to explicitly pass it in. Simply call req.app or res.app to get access to it.
https://expressjs.com/en/4x/api.html#req.app
https://expressjs.com/en/4x/api.html#res.app

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