Note: The examples used below are highly simplified. I made it up for the sake of the article. Of course, you’ll want to be more sophisticated in your approach for a real-life business example.
The idea for the Backend-For-Frontend pattern came from the software engineers at SoundCloud. Phil Calçado (one of the creators) gave an architectural explanation of the pattern, so you can go give it a look here.
Why the BFF pattern?
Let’s use a case study.
Suppose you are building an application for a Real estate firm, which allows users to view properties for sale, and probably book appointments or something.
The pattern of fetching data is as such (assuming you use the MVC pattern):
Fetch Properties from Database -> Model serializes data ->Controller performs whatever logic is needed -> Data passes to view
Of course, this method is not the best, especially when working with a team and/or a large project. There are too many dependencies between both ends and little separation of concerns.
A more, modern approach is to make the backend an API resource, with an easy-to-use output (JSON, for example), and then let the frontend team simply focus on consuming the API data output by hitting defined endpoints.
A very simplistic model of such an approach is described below:
As you can see here, roles have been clearly defined for both the frontend and backend sections. The backend team is solely focused on the backend and ensure the proper output format is sent out. The front-end team knows what endpoints to hit, and how they can make use of the data.
You see, a lot of development teams stop at this point; a central API acts as a connector between frontend and backend, and all’s right with the world. What some don’t consider, however, is the limitation it brings. We will go through a couple of those.
First, what if you had a mobile app, which is to consume the same API, but not the same result as the web application? Let’s take, for example, the Real estate application.
For the web, we may prefer to use session-based authentication and use tokens for mobile authentication. Or we may have a feature we don’t want in the web app, so we want to exclude it from the web view. Heck, we may even decide to give special treatment to our loyal customers who installed the app. There’s always a reason to dish out different results.
A second limitation: what if we decide to make the API public? There’s the example of SoundCloud's public API, where SoundCloud gives something special to give their website users, that the public API didn’t offer. With a central API for every frontend, we have no straightforward way of identifying which feature to give to which API consumer.
To solve this, the Backend-For-Frontend pattern came into play.
Let’s make some BFFs
The idea is simple — make a Backend for every Frontend.
You have a web app that wants to consume the main API? Create a Backend specifically for the Web Frontend.
Got an Android/iOS interface that needs the main API? Create a Backend for the Android/iOS Frontend.
And then create the main API source code and store it in a separate, independent space.
The Backend will be in charge of making the main API requests and passing data to your frontend. In that way, you have absolute control over what each interface of your API’s ecosystem has access to.
Using the Real estate example, suppose we want to login through the web, but for the main backend, we have to use API authentication. We will take advantage of Laravel sessions to store tokens and use them as an Authentication Header.
How it works:
The main backend domain: http://main-backend.test
The web frontend domain: http://web-frontend.test
The web backend domain (our BFF): http://backend.web-frontend.test
We will use Passport for Authentication, (check this link for a quick Laravel Passport tutorial).
The Login code is stored in the main backend code (http://main-backend.test). It’s exemplified below:
What happened there is simple:
- Create Methods for sending out responses; output is JSON
- In the Login Method, retrieve the request data, [you can perform any validation at this point]
- Authenticate the retrieved data using the Auth Facade provided by Laravel, ensure the data is reflected in the User Model, and the ‘users’ table. Specify if otherwise.
- Return success response on correct details, or error response otherwise.
You can store this main API source code in a different server, independent of the code consuming it.
In order to authenticate with the BFF code (hosted at http://backend.web-frontend.test), the code below can be in the BFF route file:
As you can observe, the GuzzleHttpLaravel package is being used to send an HTTP request to your main backend server.
If you can recall, (or go back to check), your main backend returns a JSON output, with 2 pieces of information; token and user data. The ‘token’ is very vital here. On successful validation in the backend server, it sends a success response to your BFF, which then proceeds to the ‘else’ block (as the response isn’t failed()). The token is then retrieved and passed into your web session and a response is generated to your http://web-frontend.test view.
Now that you’ve successfully logged in, let’s dive into making a request to fetch properties.
Say, this is the code for fetching properties from the database, stored in our main backend server, http://main-backend.test
As you can see, the resource is protected by the auth/api middleware, which means we aren’t getting any data without API authentication. Let’s show our API token and get data from our BFF source code:
This should sum up all my points. From the above code snippet, I made an HTTP request, using the ‘withHeaders’ and ‘withToken’ methods to set the header and API token respectively. It can now access the API resource and retrieve the data listing. (Learn more about making Laravel Http Requests here)
Why go through all these?
Well, as I mentioned earlier, it solves the limitations a coupled, direct API brings. With this, you have the ability to control how any client interacts with your API. You can make part of your services public, and keep your special data and features to yourself. You can give customized experiences to your mobile and web interface. It’s all up to you and your Backend-For-Frontend interface. You can build a similar BFF for your Android interface. And another for your iOS interface.
And then your main API can remain undisturbed by the hagglings of its consumers.
Useful: Check out Mohamed Said for useful backend tips