Improve your Cloud Function implementations using Express middleware

Julian Wolf
Firebase Developers
4 min readDec 12, 2019

When you’re building your app’s Cloud Functions with Node.js, Google offers the possibility to directly interact with the underlying web application framework Express.js. Middleware functions are a core concept of Express which is why you should definitely consider to leverage their advantages.

An Express application is essentially a series of middleware function calls. [Express.js documentation]

The following techniques and patterns relating to middleware functions are not explicitly covered by Googles Cloud Function documentation but greatly work together with common use cases you probably want to cover with your Firebase project. These tips may help you structuring your code or even save money by avoiding unnecessary API calls (for example when accessing Cloud Firestore).

Extract frequently needed tasks to their own middleware

It’s likely that your app will use some Cloud Functions especially when you want to do some kind of authentication or verification of a sent payload. Imagine your app somehow manages restaurant entities. Only restaurant owners will be allowed to change or delete a restaurant. Hence both endpoints will have to verify that a request is authenticated. Middleware functions are a good approach to achieve this behaviour safely in a readable manner.

Speaking of code, an Express middleware is essentially a function accepting the request, the response and a “next-function”. Given these values you can handle all your authentication logic within the function.

Once implemented you can easily plug the middleware into every path of your Express app.

You may have asked yourself where the onlyLoggedInUsers middleware in the example above comes from. This middleware processes the Authorization header your client sends via Firebase SDK. In case you’re using the default Firebase Authentication you can simply use the middleware Google provides in their example repository.

Their code will handle authentication to get the unique user ID of the requesting user. In case the user is not logged in, the request will fail. After the middleware is done with its work, all the following middleware functions in the chain will have access to req.user.

The ability to extend the request object in a middleware (like adding user to the req object) is an important part of the underlying mechanism as you can easily leverage this to save api or database requests:

Save API calls (like Firestore invocations) by extending the request object

It’s likely that some of your permission checks will have to access an external API or a database. In case of Firestore (or Cloud Storage) this will occur when you can not protect your data by just using Security Rules (here is a great read about that topic).

Let’s take our example from above: imagine your restaurant will be able to receive Michelin stars as an award for great food. This event will not only affect the restaurant entity. The chef of the respective restaurant will be mentioned on some kind of “wall of fame”.

When you are accessing your Firestore data within a Cloud Function (not sure if really need to do that? Read this!) with middleware functions you could end up with code that leads to redundant database access because in Javascript the middleware and the actual function won’t share the same context.

As Firestore read and writes (or egress when you are accessing a service somewhere else) cost you money, you should consider to optimize the code above. Excluding the pre-checks into middleware functions and extending the request object with data that has to be fetched for (security) reasons anyways is a great way to do that by simultaneously increasing your code’s readability and reusability. Here is an example of how you could achieve that:

Ensure flexibility using composing methods

As your application grows it might be necessary to implement a more complex permission concept. Especially when having to handle multiple user groups, you will need to implement more middleware functions whose implementation is basically the same. If you come to that point you should consider composing your middleware with so-called curried functions. This last code example will give you an overview of how to achieve that:

Conclusion

This post focused on using middleware functions mainly for permission purposes within Cloud Functions. But their usability is not limited to that. You could also combine them with a scheme validation framework and use them to do verification of a sent payload for example.

If you would like to read more about that topic, feel free to leave a comment.

Merry Christmas! 🎄

--

--

Julian Wolf
Firebase Developers

Software Engineer / Web Developer. Mainz / Frankfurt. Open for new professional challenges. Telegram: https://t.me/julianwolf1503