Introduction
In a tipical development, the frontend application consumes data from a backend API. The backend API is designed to be generic and serve multiple clients which can lead to a situation where the frontend application needs to make multiple requests to the backend API to get all the data it needs. This can lead to performance issues and a poor user experience. Aditionaly, the data returned by the backend API may contain more data than the frontend application needs or data that is not in the format that the frontend application expects.
In the image above, the frontend application needs to make multiple requests to the backend API to get all the data it needs.
Backend For Frontend
To solve these issues, you can create a dedicated backend which is optimized for the specific needs of the frontend application. This dedicated backend is called Backend For Frontend (BFF). In this backend you can extend the API with new properties, reduce the amount of data or join data from multiple sources to reduce the number of requests from the frontend application.
Example with a single service
Let’s say you want to add to a frontend application a list that displays cron jobs. The backend API is already created and returns a list of cron jobs with the following properties:
But bussiness requirements says that the frontend application should also display the next execution time of each cron job and a human readable description of the cron schedule.
Without BFF
The frontend application needs resolve a next execution time and a human readable description of the cron schedule by itself. Parsing cron expression is not a trivial task and moreover the description should be translated to a user language. At the end you will end with a library to parse cron expressions and another library to translate cron expression to the human readable form. This will increase the bundle size and the complexity of the frontend application.
- cron-parser - 26.3kB (Minified + Gzipped)
- cronstrue - 5.6kB (Minified + Gzipped)
With BFF
With BFF you can extend the API with the next execution time and the human readable name of the cron expression and return excatly what the frontend application needs. Of course you still need to handle calculations and translations but at least you can do it in the backend without increasing the bundle size and the complexity of the frontend application.
Example with multiple services
Let’s say you want to create a list of products in a frontend application. We have many services in the architecture that provide data about products. The first service provides data about the stock of the products, the second service provides static data about the products and the third service provides translations.
As you can see to get all the data needed to display a list of products in the frontend application you need to make multiple requests to multiple services. Of course you can do it in the frontend application but it will increase the number of requests and perhaps the frontend application will need to handle the translations and join the data from multiple sources. You can resolve those issues by creating a decidated endpoint just for displaying a list of products in BFF service.
Pros
- Optimize the API for the specific needs of the frontend application.
- Reduce the amount of data returned by the backend API.
- Join data from multiple sources to reduce the number of requests from the frontend application.
Cons
- Increase the number of services in the architecture.
- Increase the complexity of the architecture.
- Increase the maintenance cost.
Q&A
Which language should I use to create a BFF?
You can use any language that you are comfortable with but if I would recommend using the same language as the FE application. Thanks to that you can share the code (and libraries!) between the FE and BFF.
Should I create a separate repository for the BFF?
Not really. Having a mono-repo with the FE and BFF can simplify the development process. When you need to make changes in the FE and BFF at the same time you can do it in a single pull request (it is especially useful when you need to break a contract between the FE and BFF). It is also easier to keep the versions of the FE and BFF in sync.
About about GraphQL?
GraphQL is a alternative to BFF. When you use GraphQL then you should not need a BFF.