Presentation Oriented APIs in Affirm

Ralph Pina
Affirm Tech Blog
Published in
5 min readSep 3, 2020

--

Affirm’s mission is to deliver honest financial products that improve lives. To maximize the impact of our products we need to make them available to as many people as possible, and we need to iterate quickly to incorporate the constantly evolving feedback from users and the market.

To make our products universally available we need to build cohesive and engaging experiences for the devices our customers use. Today we support Android, iOS, and Web apps. Iterating and extending these experiences in a way that maintains their cohesion over time is not trivial, and requires that we make deliberate architectural decisions.

We’ve identified three large pain points in building high-quality experiences across multiple clients:

  • Business logic is implemented multiple times (once per client)
  • Part of the state is maintained in the client, requiring synchronization with a server
  • Some clients require that we support multiple versions in the wild, others require a lot of time and effort to update (compared to backend services)

One solution to these pain points is building server-driven UI clients. In this pattern:

  • Business logic is only implemented in the server. The server “presents” the data needed by the UI clients, which uses it to render the experience.
  • The state is only maintained by the server, UI clients request state changes, e.g. as a result of user input, and the server responds with the new “presentation” of the updated state.
  • Since clients have less logic, changes in business rules do not require client deployments.

Traditionally, APIs have been designed to be resource-oriented, however, these have architectural drawbacks that make it hard to build server-driven UI clients. By adopting presentation-oriented APIs we can mitigate some of the drawbacks to quickly deploy and iterate on cohesive and engaging experiences across multiple devices and OSes.

This document:

  • Defines traditional resource-oriented APIs.
  • Identifies architectural pain points in resource-oriented APIs.
  • Defines presentation-oriented APIs.
  • Identifies the benefits of presentation-oriented APIs for UI clients.

Resource-Oriented APIs

Engineers are probably familiar with this pattern, it is more popularly referred to as RESTful APIs. Resource-oriented APIs are “modeled as collections of individually-addressable resources (the nouns of the API). Resources are referenced with their resource names and manipulated via a small set of methods (also known as verbs or operations).”

In a Services Oriented Architecture, you might split your data into distinct stores, and each of these might be fronted by a microservice. Since resource-oriented APIs are designed to be general-purpose, they are not opinionated about the use cases of its clients, and therefore might return the entire data representation to all clients, although using field projection a client may request a different representation.

Below is an example of an SOA with three resource-oriented APIs consumed by multiple UI clients.

Data Modeling

A canonical example of how data is modeled in a resource-oriented API is a user object, which has a set of properties that map to the data persistence layer. It might look something like:

{
"first_name": "Jane",
"last_name": "Doe",
"address": {
"street": "123 Main St.",
"city": "Anytown",
"state": "CA",
"zipcode": "US"
},
...
}

Pain points of Resource-Oriented APIs

  • Depending on the size of the resource and the use cases of the clients consuming the API, it might be an inefficient use of computing and networking resources: we may make extra DB transactions or use bandwidth to transmit data that the client ignores.
  • Depending on the parsing implementation, a larger data model may result in performance degradation in the client.
  • Clients may need to make multiple network calls to fetch and join results to draw one screen. This has performance implications and requires this logic to be duplicated across different clients. In a cellular network, it might also incur extra data costs to the user.
  • We would leak implementation details of our SOA and data modeling into the clients, creating a strong dependency. This makes it more likely that changes in the data layer will break clients.

Presentation-Oriented APIs

Presentation logic is defined as being “concerned with how business objects are displayed to users of the software, e.g. the choice between a pop-up screen and a drop-down menu.”

Given that microservices fronting data need to satisfy a wide range of use cases one normally adds an extra layer of microservices to enable presentation-oriented APIs: this is referred to as the Backend for Frontends (BFFs) pattern, which is a flavor of the more general API Gateway pattern. The BFF pattern was first described by Sam Newman, who enumerated multiple implementations.

The BFF pattern is normally architected such that different clients will interact with different BFF microservices. Another implementation, which we will refer to as Backend For Experiences (BFEs) instead implements one microservice to enable one feature, screen, or experience across multiple clients.

Data Modeling

These APIs provide the clients the data needed to render a screen, this data will change for different reasons and at different times (normally product and business-related) than the modeling and backend architecture which normally changes based on technical decisions.

In the implementation shown below the client/server contract is a layout and the data to populate it. The client is unaware of how that data is modeled in the backend, or the product and business decisions that produced it. The BFE may be fronting a monolith or an SOA. When the data models or service dependencies change in the backend only the BFE needs to be modified and deployed, which is normally much easier than modifying and deploying N clients.

{ 
"universal_search": {
"layout": "universal_search",
"data": {
"title_text": "Any time. Any store.",
"subtitle_text": "Find a store to see how much you can spend. Then, make easy monthly payments just about anywhere.",
"title_color": "#ffffff",
"subtitle_color": "#ffffff",
"background_color": "#ffffff"
}
}
"modules":[
{
"module_id": "merchant_categories",
"layout": "merchant_categories”,
"title": "Shop by category",
“data_url”: <current url>
},
// rest of the modules
]
}

Benefits of Presentation-Oriented APIs

  • Responses only include the data needed by clients to render a page. Depending on the use cases, it might require less bandwidth than fetching all the individual models.
  • Clients will only parse the data they need.
  • Ideally, all the information needed to render one screen is returned as the result of one API call, avoiding extra client-side logic.
  • We can build a strong separation of concerns between our backend architecture and the clients that consume it. Any needed changes can be made in one BFE microservice.

Conclusion

By using the Backend for Experience pattern we can build a strong separation of concerns, first between our backend infrastructure and the clients, and secondly between different products or experiences. These architectural constraints enable clients that contain less logic, and the logic that gets shipped in the clients is strictly presentation-related. Changes driven by business or product requirements are made in the BFE, accelerating the development lifecycle. This faster iteration shortens the time to deliver more honest financial products that improve more lives.

--

--