I am new at ExpressJs. so I have some questions about middlewares. So,when do we have to use route middleware in ExpressJs?
First off middleware is code that generally operates on a number of incoming requests. For example, you might have some middleware that checks a cookie to see if this request is authorized before allowing routing to other request handlers to continue. If the request is authorized, it would call next() to continue routing to whatever route handles that specific URL. If the request is not authorized, then it would send an error response and stop further routing. There are thousands of possible uses for middleware - authorization checking is just one such example.
So, you would use middleware when you have multiple routes that all want some sort of pre-check or pre-processing done before the individual routes get called.
Since you asked about "route middleware", perhaps you also wanted to know when you would use middleware on a specific router rather than on the app object. That would be the same when you want middleware to apply only to the routes that are directed to a router object, not on all routes. That can also be done by specifying a path for the middleware such that is only gets called for certain paths.
You can use middlewares when you want to filter your requests before it goes to the next step and make an operation that you want to do there. For e.g in following ways you can have make use of middewares:
Validate
Authorization
Access levels
Restrict requests calls
Related
I have been working on a typescript project. I have created a middleware to check users' subscription and do not want to let users access PUT and POST routes. But I still want them to be able to access GET and DELETE requests.
I know that the following line applies the checkSubscription middleware to all the requests on the route.
router.use(checkSubscription)
I only want the middleware to run if the request type is PUT or POST.
I could do the following, of course
router.get("/endpoint1", controller1);
router.put("/endpoint2", checkSubscription, controller2);
router.post("/endpoint3", checkSubscription, controller3);
router.delete("/endpoint4", controller4);
Notice that the above PUT and POST requests run the checkSubscription middleware.
But if I could declare on the top of the route file to run the middleware on all POST and PUT requests, that would save a lot of work and time.
Any kind of help would be highly appreciated. Thanks!
You can restrict the middleware to PUT and POST requests by evaluating the req.method inside:
function checkSubscription(req, res, next) {
if (req.method !== "PUT" && req.method !== "POST") return next();
// Rest of your middleware code
}
This keeps the rule "this middleware is only for PUT and POST" local to the middleware, no matter how often it is referenced in other statements like router.use and router.post.
But if I could declare on the top of the route file to run the middleware on all POST and PUT requests, that would save a lot of work and time.
You can just do something like this:
router.put("*", checkSubscription);
router.post("*", checkSubscription);
This will only call the checkSubscription() middleware for all PUT or POST requests that hit this router.
The "*" will match any path that goes through this router, but you could use any particular Express route pattern/regex there that you want if you want it to match more than one path, but not all paths.
As it sounds like you already know, you can also control route declaration ordering to give some routes a chance to handle the request before the middleware gets a shot to run.
Since Express runs middleware (including route handlers) in order, you can place the routes for which you don't want to run the middleware first, then the middleware, then the routes for which it does need to run:
router.get(...);
router.delete(...);
router.use(checkSubscription);
router.post(...);
router.put(...);
It does require some diligence with regards to app maintenance, because developers need to understand that the order in which the handlers are declared is relevant.
Say this is my router config
<apikit:config name="apiConfig" raml="api.raml" doc:name="Router" >
<apikit:flow-mapping resource="/resourceOne" action="get" flow-ref="flow-1"/>
<apikit:flow-mapping resource="/resourceTwo" action="post" flow-ref="flow-1"/>
</apikit:config>
As you can see the calls to these two resources are being redirected to the same flow, but based on the method action.
How do I read this action value (Get or Post) in the called flow flow-1?
I believe you should be having separate flows, but if you need to it this way, you can use #[attributes.method] to get the method of the HTTP Request. The APIKIT router will forward the same event that the HTTP Listener will receive, so it will contain HTTPRequestAttributes. For more info you can refer this section HTTP Request Example
I am trying to write a middleware that creates a new method on app created with express(). For example, I would like to achieve the following:
app.use(myMiddleware())
// ...
app.newMethod() // added through the previous middleware
Is there a way to achieve this? A way I have thought of, as referenced in some other questions, is to pass in app itself as a param to my middleware so that I could tweak it:
app.use(myMiddleware(app))
// ...
app.newMethod() // ok, definitely doable
However, this does not seem elegant enough.
Also, req.app and res.app references won't work for me in this case, since the (req, res, next) => {} function returned by myMiddleware() only executes when receiving requests, while I possibly want to access the method before even app.listen() is called.
Is there a way I can achieve this?
It really doesn't make sense to add an app method in middleware. The purpose of middleware is to process an incoming request, either in preparation for later middleware or later request handlers or to just handle the request itself in the middleware.
Middleware gets called over and over during incoming requests. It should never be used for something that should just happen once and it should only be used for processing related to an incoming request.
while I possibly want to access the method before even app.listen() is called
So, that definitely has nothing to do with an incoming request then so using middleware is just not the right design choice.
If all you're trying to do is to add your own method to the app object, you can do that when you are initializing your server:
const app = require('express')();
// add my own method to the app object
app.myMethod = function(myArg1, myArg2) {
// put the implementation here
}
app.use(...);
app.get(...);
app.get(...);
app.listen(...);
Then, anywhere you want, you can call app.myMethod(...).
Interested in grabbing the user on every request so that I can have funtionality even on pages that don't have any stormpath functionality middleware.
Any issues with this? If user is logged in it returns the user in the request object, if the user is not logged in, it returns undefined. which is exactly what I want. Any 'gotchas' I'm missing? It 'seems' to work great.
app.get('*', stormpath.getUser, function(req, res, next) {
next()
});
That's fine, although your code won't cover all routes & http methods. It's probably easier to do this:
app.use(stormpath.getUser)
Since in express, all route handlers are "middleware", you can pass stormpath.getUser directly into the handler without the function calling next().
Also, matching all GET requests by using * will miss any POST, DELETE, PUT, etc requests. app.all will match all routes and all HTTP methods.
I am having a very similar issue to this post here: How to use custom route middleware with Sails.js? (ExpressJS)
in that I want all non ajax requests (or all routes with the prefix /api) to load the same view, regardless of route. I have implemented the given answer in that question, but came across the issue that the policy is not called for any unspecified routes.
If I was to catch all routes so that the policy was called, all my blueprints would be overwritten.
Ideally, I would catch all routes last, after the blueprints, since every non API route should be sent to the front end.
I am using angularjs for the front end and want angular to deal with all non API routing.
I would rather not use a .htaccess file as I need to put session information into the page on it's initial load.
Thanks
It seems like your use case is very similar to a HTTP 404 Error situation - you want all requests which don't satisfy blueprint (and possibly route.js) routes to be handled in the same manner.
From api/responses/notFound.js:
* NOTE:
* If a request doesn't match any explicit routes (i.e. `config/routes.js`)
* or route blueprints (i.e. "shadow routes", Sails will call `res.notFound()`
* automatically.
*/
You can have special handling code here which calls the appropriate view if the request path contains /api:
if (req.path.match('^/api')) {
return res.view('your-view-here');
}