What is Middleware in API?
Hello there!
My name is Angelo YANVE, I'm Software Engineer specifically Backend Engineer. In this article, We are going to learn about Middleware and we will browse some example using ExpressJs.
What is API?
API stands for Application Programming Interface is a mechanism that allows two software to communicate between each other using a set of definition protocols with Request and Response.
What is Middleware?
Middleware is an interface between Client Request and Server Response. It works like some features that can be used to handle HTTP requests and responses, process data, perform validations, and implements other specific functionality.
Middleware use cases
Here are some common roles that middleware can play in API
Authentication and Authorization: middleware can be used to verify user's identity and determine if they have the necessary permission to access the resources they need
Data Validation: middleware can performs checks on data received in requests ensuring that it is correct and complies with specified requirements before being processed by the API
Caching: Some middleware can be used to cache query to improve performance by avoiding redundant processing of similar requests.
Data Tansformation: middleware can transform data before or after processing by the API, for example by converting data formats, adding information etc...
Why use Middleware?
Now we are going to explore the essential reasons why we need to use middleware in API development. Middleware offers benefits such as :
Code simplification: Middleware help to separate business logic from common logic like authentication, data validation, error handling, etc...
Reusability: Middleware functionality can be reused in different parts of our application or between many applications by modularity and efficiency
Centralize management: Middleware allow you to centralize certain functionality in one place, then make maintenance and debugging easier
Responsibilities separation: Middleware encourages separation of responsibilities by helping them to focus on their main task. which allows adding new features or updating existing ones without changing business logic in the entire application
ExpressJS
ExpressJS is a most popular NodeJS framework that allows developers to build server side applications using JavaScript.
Middlewares in ExpressJS are functions that are executed during the lifecycle of a request to the ExpressJS server. These functions have access to the request object, response object, and a next function (which, when called, proceeds to complete the request). They can be used to modify the request and response objects.
Now we will to take the example of a
Get
request to the ExpressJS server to get all the post from a private forum and we need to be authenticated and validated by the admin to get all post
app.get('/posts',(req, res, next)=>{
// Check to see if the request has Bearer Token
const authorizationHeader = req.headers['authorization'];
if (!authorizationHeader || !authorizationHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
const token = authorizationHeader.split(' ')[1];
//Get user account and and check if validate
getAccount(token, (account)=>{
if(!account) return res.status(401).json({ msg: 'User Account not found' });
if(!account.approved) return res.status(403).json({msg: 'Your account not approved, please check your mails'});
});
// The account is valid and approved, grab the posts and send them back
db.getPosts((allPosts)=>{
if (!allPosts) {
return res.status(404).json({ msg: 'post not found' });
}
return res.status(200).json({posts: allPosts });
});
});
This above code looks good, it performs the necessary process we define to get all forum posts. However, a significant portion of this code may be reused elsewhere. For example if we need to get all comments for a post, we will authenticate the user and check if they are approved.
We could then consider splitting the code into smaller function and use it as Middleware
The request chain goes roughly like this:
Check is request has Bearer token, if not, response "Unauthorized" early
Check if user account is "Approved", if not, response "Not Approved"
Get the posts from the database and return them to the user.
If we split this out into smaller middleware functions, it might look like this.
function getUserToken(req, res, next){
const authorizationHeader = req.headers['authorization'];
if (!authorizationHeader || !authorizationHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
req.user.token = authorizationHeader.split(' ')[1];
next();
}
function checkUserApproved(req, res, next){
getAccount(token, (account)=>{
if(!account) return res.status(401).json({ msg: 'User Account not found' });
if(!account.approved) return res.status(403).json({msg: 'Your account not approved, please check your mails'});
});
next();
}
app.get('/posts',getUserToken , checkUserApproved, (req, res, next)=>{
db.getPosts((allPosts)=>{
if (!allPosts) {
return res.status(404).json({ msg: 'post not found' });
}
return res.status(200).json({posts: allPosts });
});
});
So now we have middleware for authentication and check if account is approved, which can be used in another request, like getting all comments from a post.
We can also load middleware by using app.use()
// Apply getUserToken & checkUserApproved
app.use(getUserToken);
app.use(checkUserApproved);
app.get('/posts', (req, res, next)=>{
db.getPosts((allPosts)=>{
if (!allPosts) {
return res.status(404).json({ msg: 'post not found' });
}
return res.status(200).json({posts: allPosts });
});
});
Before concluded let's explain next()
What is next()?
Middleware function get 3 parameter req
, res
which respectively access to Request and Response and next
which is used to move to the next middleware or function if the current middleware function does not complete the request-response cycle
For example when we load this get request
app.get('/', authenticate, log_data, update_req);
Middlewares functions are called in the order authenticate() -> log_data() -> update_req().
This order will be interrupted if the authenticate
and log_data
functions don't have next()
function to move on following function
The next function can be named otherwise too but this is the convention followed to avoid any confusion.
next()
in the last function update_req
is optional and won’t do anything since it is the last function in the request-response cycle.Conclusion
Middleware is a great tool for organizing your code in the Request-Response cycle. It's a function with access to the request req
and response res
before and after current request is dealt with.
Hope this article helps you!!
Leave a comment please.
Subscribe to my newsletter
Read articles from Angelo YANVE directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by