Using NextJS API Routes as a BFF
How NextJS API Routes can work as an out-of-the-box BFF
What is NextJS
NextJS is an incredibly popular React web framework that allows for out-of-the-box server-side rendering and static site generation, alongside a suite of opinionated settings and tools such as “routing” and “dynamic imports”. One of these features is “API routes”, which automatically exposes the files under the API folder as endpoints. The documentation describes this feature as follows:
Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.
What is the BFF architectural design pattern
The BFF, or “Backend-For-Frontend” architecture pattern involves creating a specified backend service with an interface or set of contracts specified to a specific frontend service. Microsoft has a great description of this pattern as part of their “Cloud Architecture” series.
There are many styles and variations to this, some of which are outlined by Sam Newman in his article talking about the pattern. For the purpose of this implementation, we will be referring to a sole BFF that exposes an interface for the NextJS frontend.
Leveraging API Routes to create a BFF
As mentioned earlier, NextJS by default has an opinionated way of creating API routes alongside the front-end code. Below is an example of how NextJS structures its frontend and API routes.
In this example, the API routes would be mapped as such:
- https://{some-host:api-port}.com/users/{id}
And the frontend routes are like this:
With this, we’re able to use some form of HTTP client like Fetch or Axios to make requests to the BFF, where we will have endpoints that perform things such as:
- Data Transformation: The BFF can call some services and perform transformations on the response data to make it fit for the frontend.
- Integrating Multiple Services: The BFF is able to orchestrate many different services together, even if they live within different service boundaries. It can be used to integrate with public APIs such as Stripe or MailChimp and interweave those APIs with possible in-house services.
- Caching: To prevent overcalling services, intermediary caches can be set up exclusively for the BFF and have their settings tailored to the needs of the frontend.
- Uniform Error Handling: As the BFF is the sole interface for the frontend to use, we can provide a single uniform way of handling and forming error codes that the frontend will consume, allowing us to manipulate or enrich existing errors that services may return into something the frontend can easily parse.
- Authentication: The BFF can endpoints for provisioning and controlling the life-cycle of JWT tokens, and furthermore use them to protect certain API routes and also proxy the tokens to further services, or just control the auth flow of the frontend.
Although these benefits can be achieved via the BFF pattern alone, NextJS allows for a convenient and efficient way of standing up a BFF in new or existing projects. Furthermore, it does provide additional benefits on top of the pattern as they work together synergistically.
Sharing code and types
The benefit of having shared code between the frontend and the BFF is that you’re able to reuse code and types across both systems. This means you’re able to have type safety and a stable contract between both services as the BFF is the sole interface that the frontend will interact with. This is quite handy when crafting requests and responses across both services that incorporate certain commonly used types.
Although this introduces tight coupling between services, due to the nature of this pattern it is actually beneficial for us.
Fewer deployments
Due to the fact that the services exist together within the same NextJS codebase, changes can be made across the entire stack in a vertical fashion and only require one deployment. This also reduces the amount of IaaC needed to maintain the project and should make implementing and maintaining CI/CD practices much more efficient.
Conclusion
The BFF pattern is powerful and flexible. It can be designed in several different variations, and provide a lean and focused interface for the frontend to develop against. NextJS is becoming an increasingly popular React web framework, and with its pre-packaged API routes, developers can easily create and maintain a powerful BFF service for their frontend.