The majestic monolith is how I build backends since I started. Microservices seemed like too much work for the small teams I worked with. However, some of the patterns used to build and service applications running in a microservice architecture can be useful for monoliths.
One of these patterns is the backend-for-frontend pattern. The idea is to have a dedicated backend for your frontends. It can be a separate backend for each type of frontend or one backend for all frontends.
To understand how this pattern can be useful, let's imagine we're building an online store. We have our backend exposing a public REST API, this API can be consumed by our web UI, mobile apps, and other 3rd party consumers. Authentication to our backend is done using OAuth2.0, all consumers must send a bearer token to protected routes.
Storing the authentication token in the mobile app is fine, but there's no way to store the tokens in the browser securely. Using a dedicated backend for our web frontend, we can use that BFF (Backend For Frontend) as a gateway to the actual backend and store the token in it.
So to log the user in to our web frontend, the frontend will make a request to the BFF which will send a login request to the backend, receive the token, and then store it in the session.
Communication between the web frontend and the BFF is authenticated using sessions, while the BFF communicates with the backend using token-based authentication.
Roles and permissions for an app that's used to make orders and browser products are different from ones for an app that's used to manage inventory and suppliers.
Using a BFF for each type of client, we can run the authorization checks in the BFF and keep our backend as much open as we want it to be. Allowing us to build more clients in the future without having to change the backend.
To render a screen that displays all products, featured products, and recommended products. A client may need to make 3 requests to 3 different backend endpoints. Even if these requests are made concurrently, the client still has to send 3 requests and wait for the responses.
Using a BFF, the client can make a single request to a /products-list endpoint on the BFF and the BFF will aggregate the response needed by making the 3 requests to the backend.
Server-to-server communication will experience less latency and we can add a caching layer in the BFF which will make things even better.
BFF and Laravel
In the following video, I discuss the BFF pattern and explain how we can implement it using Laravel.