Remember one week ago I talked about the concept of UX APIs? Or in other words, how the Backend for Frontend pattern seemed to solve a common problem in REST-API-driven SPAs: resource representation is semantically unaware of UX needs.
Well, after further deliberation and experimentations with my colleagues, here I am listing out a few not-so-positive conclusions about this approach. Let me explain.
Backend for Frontend pattern, in its purest interpretation and implementation, tends to couple FE and BE forever. Letting alone that you might end up needing one BFF per channel (web, mobile, chatbot) and per App. You see the point? Maintainability hell.
So you started looking for a solution to make your APIs fit your UX needs and turns out that you end up having yet another monolith; a component where you start coding all the fetching and adapting ad-hoc logic for a concrete channel for a concrete app. We need to be careful. If it talks like an antipattern and walks like an antipattern, it is probably an antipattern.
GraphQL. Lots of fuss around it, and I am sure it is well deserved. But be careful where and how you use it. In our case, we were thinking of using GraphQL as a facade for REST APIs and this seems to rise up a few issues:
- Fetching: It is true that by using GraphQL we solve a common problem of resource under-fetching (data needed in the UI comes from various REST resources and hence you have to do multiple GETs) and over-fetching (download a full resource when you only need a few properties). But there is a trade-off since all the GraphQL communications are tunneled through POST, where the filter criteria is embedded in the body request. This makes all server calls way heavier and may result in performance degradation.
- Adapting: There is a problem when you want to implement a GraphQL API that facades a REST Level 3 API, and this has to do with HATEOAS. In a nutshell, you might end up having to replicate the full original network of resources in your facade GraphQL API, even for those resources not impacted by the adaptation. This is needed by the API consumers: our API-driven SPAs that rely on HATEOAS for resource discoverability and therefore all hypermedia links between resources need to be preserved.
After a few ramblings and discussions, the solution has been always in front of us. We are pushing and transforming our monoliths into microservices, so the obvious approach would be building a simple Custom Microservice implemented by a REST API.
- This is like a proxy API, which will implement all the fetch and adapt logic based on client request.
- It likely not to be reused between Apps, but definitely can be reused by channels within the same App.
- It helps to create mocking resources for testing by having an alternative implementation.
I still like the idea of labelling the APIs provided by this Custom Microservice as UX APIs. If only because they are semantically aware of UX needs, so it is OK if the component is semantically coupled to the UI.