What is the purpose on the middleware Yeoman function implementation? - node.js

I'm new in grunt-contrib-connect and came across with this follow middleware function Yoeman implementation -
middleware: function(connect, options, middlewares) {
return [
proxySnippet,
connect.static('.tmp'),
connect().use('/bower_components', connect.static('./bower_components')),
connect.static(config.app)
];
}
What is the purpose of this implementation ?

These are connect middlewares. A middleware is a request callback function which may be executed on each request. It can either modify/end the curent request-response cycle or pass the request to the next middleware in the stack. You can learn more about middlewares from express guide.
In your code you have four middlewares in the stack. First one is for proxying current request to another server. And rest three middlewares are for serving static files from three different directories.
When a request is made to the server, it'll go through these middlewares in following order:
Check if the request should be proxied. If it is proxied to other server, then it's the end of the request/response cycle, rest three middlewares will be ignored.
If not proxied, it'll try to serve the requested file from ./tmp directory.
If the file isn't found in above, it'll look inside ./bower_components. Note that this middleware will be executed only for the requests that has `/bower_components/ in the path. e.g. http://localhost:9000/bower_components/bootstrap/bootstrap.js
Finally, if file isn't found in above two directories, it'll look for it in whatever the path is set in config.app.
That's the end of stack, after that you'll get a 404 Not found error.

Related

Express middleware know if incoming will be a 404

(i know there are a few official tools for SSR but we decided to roll our own for various reasons that are not important for this question)
We have a prototype of a server-side renderer running in nodejs for vue with Puppeteer. It works very well and now I would like to cache routes we want to cache. The cache invalidation is simple.
We intend to use Redis to hold the cache objects.
Proposed flow of the server:
Incoming request hits the express app
An express request middleware 1st checks if the route should be cached, if not return index.html. END else continue.
The same middleware checks if there is a Redis cache object based on incoming request object data, if yes return cache & END else continue.
Express router matches the request to a route, passes the request to the respective domain layer, creates the cache then returns it. END else next.
No express route found, handle 404 & END.
The question I have relates to proposed flow step 2
To know if the request should be cached is based on 2 parameters:
does the request cookie contain a valid token
is the request path one which is also defined in the express routes
The express routes currently look as follows, but is liable to evolve:
GET /channel/:name
GET /channel/:name/:tag
GET /item/:id
So, how in step 2 can we check if the incoming route is a route that would match the express router?
As said in first comment, express already provde a way to do this :
app.get('/channel/:name/:tag', YOUR_MIDDLEWARE, (req, res) => {
// Your Handler
})

What is the difference between a route handler and middleware function in ExpressJS?

My understanding is that a middleware function is a route handler with the exception that it may invoke the next function parameter to pass control on to the middleware function on the stack. Is this the only difference between a standard route handler and a middleware function?
Most of what you're talking about is semantics. In ExpressJS, middleware can be a route handler or a route handler can behave as middleware. So, there is not a hard and fast line between the two. But, when people refer to middleware or a route handler in a programming discussion, they usually mean something slightly different for each...
Middleware
As generic terms, middleware is code that examines an incoming request and prepares it for further processing by other handlers or short circuits the processing (like when it discovered the user is not authenticated yet). Some examples:
Session Management. Parse cookies, look for session cookie, lookup session state for that cookie and add session info to the request so that other handlers down the line have ready access to the session object without any additional work on their part. In express, this would be express.session().
Authentication. Check if the user is trying to access a portion of the site that requires authentication. If so, check if their authentication credentials are good. If not, send an error response and prevent further processing. If so, allow further processing.
Parsing of Cookies. Parse incoming cookies into an easy-to-use data structure a request handler can have easy access to cookie data without each having to parse them on their own. This type of middleware is built into Express and happens automatically.
Parsing and Reading of POST/PUT bodies. If the incoming request is a POST or PUT, the body of the request may contain data that is needed for processing the request and needs to be read from the incoming stream. Middleware can centralize this task reading the body, then parsing it according to the data type and putting the result into a known request parameter (in Express this would be req.body). Express has some ready-to-use middleware for this type of body parsing with express.json() or express.urlencoded(). A middleware library like multer is for handling file uploads.
Serve static files (HTML, CSS, JS, etc...). For some groups of URLs, all the server needs to do is to serve a static file (no custom content added to the file). This is common for CSS files, JS files and even some HTML files. Express provides middleware for this which is called express.static().
Route Handler
As a generic term, a route handler is code that is looking for a request to a specific incoming URL such as /login and often a specific HTTP verb such as POST and has specific code for handling that precise URL and verb. Some examples:
Serve a specific web page. Handle a browser request for a specific web page.
Handle a specific form post. For example, when the user logs into the site, a login for is submitted to the server. This would be handled by a request handler in Express such as app.post("/login", ...).
Respond to a specific API request. Suppose you had an API for a book selling web-site. You might provide in that API the ability to get info on a book by its ISBN number. So, you design an api that supports a query for a particular book such as /api/book/list/0143105426 where 0143105426 is the ISBN number for the book (a universal book identifier). In that case, you'd create a request handler in Express for a URL that looks like that: app.get('/api/book/list/:isbn', ...). The request handler in Express could then programmatically examine req.parms.isbn to get the request isbn number, look it up in the database and return the desired info on the book.
So, those are somewhat generic descriptions of middleware vs. request handlers in any web server system in any language.
In Express, there is no hard and fast distinction between the two. Someone would generally call something middleware that examines a bunch of different requests and usually prepares the request for further processing. Someone would generally call something a route handler that is targeted at a specific URL (or type of URL) and whose main purpose is to send a response back to the client for that URL.
But, the way you program Express, the distinction is pretty blurry. Express offers features for handling routes such as:
app.use()
app.get()
app.post()
app.put()
app.delete()
app.all()
Anyone of these can be used for either middleware or a route handler. Which would would call a given block of code has more to do with the general intent of the code than exactly which tools in Express it uses.
More typically, one would use app.use() for middleware and app.get() and app.post() for route handlers. But there are use cases for doing it differently than that as it really depends upon the particular situation and what you're trying to do.
You can even pass more than one handler to a given route definition where the first one is middleware and followed by a route handler.
app.get("/admin", verifyAuth, (req, res) => {
// process the /admin URL, auth is already verified
req.sendFile("...");
});
It is common for middleware to be active for a large number of different requests. For example, you might have an authentication middleware that prevents access to 95% of the site if the user isn't already logged in (say everything except the a few generally information pages such as the homepage and the login and account creation pages).
It is also common to have middleware that is active for all HTTP verbs such as GET, POST, DELETE, PUT, etc... In express, this would usually be app.use() or app.all(). Request handlers are usually only for one particular verb such as app.get() or app.post().
You might have session middleware that loads a session object (if one is available) for every single request on the site and then passes control on to other handlers that can, themselves, decide whether they need to access the session object or not.
It is common for request handlers to be targeted at a specific URL and only active for that specific URL. For example, the /login URL would typically have one request handler that renders that particular page or responds to login form requests.
Path Matching for app.use() is Different
In Express, there's one other subtle difference. Middleware is typically specified with:
app.use(path, handler);
And, a route is typically specified with:
app.get(path, handler);
app.post(path, handler);
app.put(path, handler);
// etc...
app.use() is slightly more greedy than app.get() and the others in how it matches the path. app.get() requires a full match. app.use() is OK with a partial match. Here are some examples:
So, for a URL request /category:
app.use("/category", ...) matches
app.get("/category", ...) matches
For a URL request /category/fiction:
app.use("/category", ...) matches
app.get("/category", ...) does not match
You can see that app.use() accepts a partial URL match, app.get() and it's other cousins do not accept a partial URL match.
Now, of course, you can use app.get() for middleware if you want and can use app.use() for request handlers if you want, but typically one would use app.use() for middleware and app.get() and its cousins for request handlers.
Ok, let's explore some definitions first.
Middleware function
definition from the express documentation:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
Handler function or callback function
definition from express Documentation:
These routing methods specify a callback function (sometimes called “handler functions”) called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application “listens” for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function.
Here Routing methods are the methods derived from HTTP requests and the all() method that matches all the HTTP methods. But remind, the use() method is not a routing method. Let's go to express documentation for clarification.
Routing Methods
From express documentation:
A route method is derived from one of the HTTP methods and is attached to an instance of the express class. Express supports methods that correspond to all HTTP request methods: get, post, and so on. There is a special routing method, app.all(), used to load middleware functions at a path for all HTTP request methods.
So we see that middleware functions and handler functions are not opposite of each other.
Middleware functions are functions that take an extra argument, next along with req and res which is used to invoke the next middleware function.
app.use() and the other HTTP derived methods(app.get(), app.all() etc) can use middleware functions. The difference between handler function and middleware function is same on both app and router object.
On the other hand, a handler function is a function that is specified by the routing methods.
So when any of the routing methods pass a function that has req, res, and next then it is both a middleware function and a handler function.
But for app.use() if the function has req, res, and next, then it is only a middleware function.
Now, what about the functions which only have req and res don't have the next argument?!
They are not middleware functions by definition.
If such function is used on routing methods then they are only handler functions. We use such a handler function which is not a middleware when it is the only one callback function. Because in such cases there is no need for next which calls the next middleware function.
If they are used on app.use() then they are not middleware, nor handler function.
Ok, enough of the definitions, But is there any difference between middleware functions of app.use() and handler & middleware functions of routing methods??
They look similar since both have the next argument and works almost the same. But there is a subtle difference.
The next('route') works only on handler & middleware functions. So app.use() can not invoke next('route') since they can have only middleware functions.
According to express Documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
METHOD is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase.
If you know what is next('route') then the answer is finished here for you :).
In case you don't, you can come along.
next('route')
So let's see what is next('route').
From here we will use the keyword METHOD instead of get, post, all, etc.
From the previous middleware function definition, we see app.use() or app.METHOD() can take several middleware functions.
From the express documentation:
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
We see each middleware functions have to either call the next middleware function or end the response.
But sometimes in some conditions, you may want to skip all the next middleware functions for the current route but also don't want to end the response right now. Because maybe there are other routes which should be matched. So to skip all the middleware functions of the current route without ending the response, you can run next('route'). It will skip all the callback functions of the current route and search to match the next routes.
For Example (From express documentation):
app.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})
See, here in a certain condition(req.params.id === '0') we want to skip the next callback function but also don't want to end the response because there is another route of the same path parameter which will be matched and that route will send a special response. (Yeah, it is valid to use the same path parameter for the same METHOD several times. In such cases, all the routes will be matched until the response ends). So in such cases, we run the next('route') and all the callback function of the current route is skipped. Here if the condition is not met then we call the next callback function.
This next('route') behavior is only possible in the app.METHOD() functions.
Recalling from express documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
That means this next('route') can be invoked only from handler & middleware functions. The only middleware functions of app.use() can not invoke it.
Since skipping all callback functions of the current route is not possible in app.use(), we should be careful here. We should only use the middleware functions in app.use() which need not be skipped in any condition. Because we either have to end the response or traverse all the callback functions from beginning to end, we can not skip them at all.
You may visit here for more information

Using res.locals in node.js model file

I am overall clueless about how and why you set up a node.js app, and how any of the app.use functions work - the tutorials on it don't explain the why of anything.
Anyway, I have socket.io, res.locals and index.js set up like so in the app.js root file.
const sockets = require('./models/socket')(io)
app.use(function (req, res, next) {
res.locals.user_id = req.session.user_id;
next();
});
const routes = require('./routes/index');
app.use('/', routes);
I'd like to be able to access res.locals in the socket.js model, like I can in index.js found in the routes folder.
I can't guess how to go about doing this. If anybody is able to explain how and why I can or can't that would be a bonus. Thanks!
Welcome to Expressjs, there are a few fundamentals you should probably research before going any further, they'll help solve some of your confusion. I'll give a brief explanation of them but I suggest you do further research. I'll then answer your actual question at the end.
Middleware and app.use
Expressjs is built upon an idea that everything is just "middleware". Middleware is a function which runs as part of a request chain. A request chain is essentially a single client request, which then goes through a chain of a number of middleware functions until it either reaches the end of the chain, exits early by returning a response to the client, or errors.
Express middleware is a function which takes the following three arguments.
req (request) - Representing the request made by a client to your
server.
res (response) - Representing the response you will return to
the client.
next - A way of telling express that your current
middleware function is done, and it should now call the next piece of
middleware. This can either be called "empty" as next(); or with an
error next(new Error());. If it is called empty, it will trigger
the next piece of middleware, if it is called with an error then it
will call the first piece of error middleware. If next is not called at the
end of a piece of middleware, then the request is deemed finished and the
response object is sent to the user.
app.use is a way of setting middleware, this means it will run for every request (unless next() is either not called by the previous piece of middleware for some reason, or it's called with an error). This middleware will run for any HTTP request type (GET, POST, PUT, DELETE, etc).
app.use can take multiple arguments, the important ones for beginners to learn are: app.use(func) and app.use(path, func). The former sets "global" middleware which runs no matter what endpoint (url path) the client requests, the latter (with a specific path) is run only if that specific path is hit. I.e. app.use('/hello', (req, res, next) => { res.send('world'); }); will return "world" when the endpoint "/hello" is hit, but not if the client requests "/hi". Where as app.use((req, res, next) => { res.send('world'); }); would return "world" when you hit any endpoint.
There are more complex things you can do with this, but that's the basics of attaching middleware to your application. The order they are attached to the application, is the order in which they will run.
One more thing, this will blow your mind, an express application made with the standard const app = express() can also be used as middleware. This means you can create several express applications, and then mount them using app.use to a single express application. This is pretty advanced, but does allow you to do some really great things with Express.
Why can you not access res.locals in socket.io? (The real question)
Within your middleware handler, you are setting up a res.locals.use_id property. This only lives with that individual request, you can pass it around as long as the request is alive by passing it into other functions, but outside of that request it doesn't exist. res is literally the response object that tells Express how to respond to the clients request, you can set properties of it during the request but once that HTTP request has ended it's gone.
Socket.io is a way of handling web socket requests, not standard HTTP requests. Thus, in a standard express HTTP request you will not be able to hand off the connection to anything with socket.io, because the connection is a single short lived HTTP request. Likewise, you won't be able to do the same the other way.
If you wish to find the users id in a socket.io request, you'll have to do this within the socket.io request itself.
Right now, you're entering a piece of middleware for an Express.js request, you are then calling next() which runs the next piece of express middleware, at no point does it cross over into Socket.io realms. This is often confused by tutorials because Socket.io can handle requests across the same port as Express is listening on, but the two are not crossed over. So you will need to write separate middleware for both Express.js requests chains, and socket.io request chains. There are ways of writing this code once and then writing an adapter to use it across both platforms, but that's not what you've tried to do here.
I would suggest you look at doing just nodejs and express for a time before taking on socket.io as well, otherwise you're trying to learn a whole heap of technologies all at once is quite a lot to try and take on board all at once.

expressjs repo documentation

I want to understand the internal working of Expressjs (just curious). Much of the thing are clear but I am not able to understand the chaining of routing and middleware. How expressjs add all the route and middleware to path / and how it keep the stack of route with middleware internally
So I will be very thankful to you if you provide some documentation or link from where I get the understanding how expressjs work internally
Thanks
ExpressJS is just an HTTP server allowing you to route and manipulate the received requests and returning a response.
So if you carefully look at the HTTP packet format below,
you can find the method and the path in the first line.
So, basically here express-router has a regex matcher that tries to match the HTTP request it receives to the predefined routes declared in the express application.
If you check L:43 Router, here it shows that the route you declare is just a function containing 3 constants:
path - That would be a path to match.
stack - Following a proper format, the URL is broken down using the / separator and a stack is formed in order of it's parsing, comprising another function called layer.
methods - Methods are the HTTP methods that we declare along with the path.
Parsing
So when a request is made, let's suppose: http://localhost:8000/user/1/test
We get the path: /user/1/test
The router's handle function is executed. Then this path is broken down into layers and formed a stack: ['user', '*', 'test']
This stack is then matched with that of the route objects that are pre-declared in the application and are used as Route functional objects.
As soon as it finds the match the callback is executed!

nodeJs/Express dealing with missing static files

I have a node App. That is configured to serve static files by:
app.use(express.static(path.join(__dirname, '../public')));
And I use some auth middlewares on other routes. The problem comes up when I hit an image that doesn't exist on the server. In this case looks like express is trying to send that request through all of the middlewares that I have for NON-static content.
Is there a way to just send 404 for missing static asset, rather than re-trigger all middlewares per missing file?
The way that the express.static() middleware works by default is that it looks for the file in the target directory and if it is not found, then it passes it on to the next middleware.
But, it has a fallthrough option that if you set it to false, then it will immediately 404 any missing file that was supposed to be in the static directory.
From the express.static() doc:
fallthrough
When this option is true, client errors such as a bad request or a
request to a non-existent file will cause this middleware to simply
call next() to invoke the next middleware in the stack. When false,
these errors (even 404s), will invoke next(err).
Set this option to true so you can map multiple physical directories
to the same web address or for routes to fill in non-existent files.
Use false if you have mounted this middleware at a path designed to be
strictly a single file system directory, which allows for
short-circuiting 404s for less overhead. This middleware will also
reply to all methods.
Example:
app.use("/public", express.static("/static", {fallthrough: false}));

Resources