Think of an HTTP request like an assembly line. The user is at the start of the line and submits the request. The server is the next person in line: it receives the request, attaches it to a (currently empty) response object, routes it to the correct endpoint, and passes it on. Then each other person in the line can alter the request and response (or not), then choose whether to pass them on, throw them away, or pick them up and throw them back to the user. Each of these other people is a middleware. At the end of the line is a person who does what the user actually asked for, whether that's fetching data, updating a database, or communicating with a third-party service. The user hopes the request will make it all the way to the end.
In Express (a popular NodeJS server framework), a middleware is a plain old JavaScript function. It does something to a request or a response, then either continues or terminates the request. For example, you might have an endpoint that looks like this:
So when the server receives an HTTP GET request at the /api/chapters URL, the first thing it will do is call the isAuthenticated function, which could look like this:
This is a very small middleware. It has access to the request object req, the response object res, and a function next that can continue the request. We check whether the user has an authentication token (in a real-life app we would validate it somehow) and if so we continue the request, which in this case will proceed to get the user's chapters from the database and return them in the response. But if the user doesn't have a token, we redirect the user to the /auth page so they can log in.
The nice thing about a middleware is that it's separate from the logic of any other middlewares or the endpoint itself. We can use the same isAuthenticated middleware on any endpoint, just by adding it to the arguments of app.get(), app.post() or any other endpoint method.
We can use as many middlewares as we want on any endpoint:
app.get('/api/books',isAuthenticated,isPremium,validateRequest,transformRequest,(req,res,next)=>{// Get the user's books and return them});
They're executed in order. When a GET request comes to this endpoint, Express will hand the request and response off to isAuthenticated, then isPremium, then validateRequest, then transformRequest, then the final arrow function. Any of these middlewares could choose to end the request (or make it time out by never calling next()), in which case everything will stop there--the other middlewares and the last function will never be called. But if they all choose to continue the request, the user will most likely get what they want.
You'll notice that the last argument in the list--the arrow function--looks a lot like a middleware. It pretty much is! The difference is that I didn't make it a named function, since it probably isn't shared with any other endpoint. Since it's just another middleware, we could put more middlewares after it, and if it called next(), they would get called too. But in my experience a function like this usually calls res.send(books) and the request ends there.
Middlewares in .NET work similarly, although they're a bit harder to set up. I assume the concept is the same in every server-side language.
Think of an HTTP request like an assembly line. The user is at the start of the line and submits the request. The server is the next person in line: it receives the request, attaches it to a (currently empty) response object, routes it to the correct endpoint, and passes it on. Then each other person in the line can alter the request and response (or not), then choose whether to pass them on, throw them away, or pick them up and throw them back to the user. Each of these other people is a middleware. At the end of the line is a person who does what the user actually asked for, whether that's fetching data, updating a database, or communicating with a third-party service. The user hopes the request will make it all the way to the end.
In Express (a popular NodeJS server framework), a middleware is a plain old JavaScript function. It does something to a request or a response, then either continues or terminates the request. For example, you might have an endpoint that looks like this:
So when the server receives an HTTP GET request at the
/api/chapters
URL, the first thing it will do is call theisAuthenticated
function, which could look like this:This is a very small middleware. It has access to the request object
req
, the response objectres
, and a functionnext
that can continue the request. We check whether the user has an authentication token (in a real-life app we would validate it somehow) and if so we continue the request, which in this case will proceed to get the user's chapters from the database and return them in the response. But if the user doesn't have a token, we redirect the user to the/auth
page so they can log in.The nice thing about a middleware is that it's separate from the logic of any other middlewares or the endpoint itself. We can use the same
isAuthenticated
middleware on any endpoint, just by adding it to the arguments ofapp.get()
,app.post()
or any other endpoint method.We can use as many middlewares as we want on any endpoint:
They're executed in order. When a GET request comes to this endpoint, Express will hand the request and response off to
isAuthenticated
, thenisPremium
, thenvalidateRequest
, thentransformRequest
, then the final arrow function. Any of these middlewares could choose to end the request (or make it time out by never callingnext()
), in which case everything will stop there--the other middlewares and the last function will never be called. But if they all choose to continue the request, the user will most likely get what they want.You'll notice that the last argument in the list--the arrow function--looks a lot like a middleware. It pretty much is! The difference is that I didn't make it a named function, since it probably isn't shared with any other endpoint. Since it's just another middleware, we could put more middlewares after it, and if it called
next()
, they would get called too. But in my experience a function like this usually callsres.send(books)
and the request ends there.Middlewares in .NET work similarly, although they're a bit harder to set up. I assume the concept is the same in every server-side language.
thanks a lot, it was exactly what i wanted to know.