How Airbnb ships features faster across web, iOS, and Android using a server-driven UI system named Ghost Platform 👻.

By Ryan Brooks

Background: Server-Driven UI

Before we dive into Airbnb’s implementation of server-driven UI (SDUI), it’s important to understand the general idea of SDUI and how it provides an advantage over traditional client-driven UI.

In a traditional world, data is driven by the backend and the UI is driven by each client (web, iOS, and Android). As an example, let’s take Airbnb’s listing page. To show our users a listing, we might request listing data from the backend. Upon receiving this listing data, the client transforms that data into UI.

This comes with a few issues. First, there’s listing-specific logic built on each client to transform and render the listing data. This logic becomes complicated quickly and is inflexible if we make changes to how listings are displayed down the road.

Second, each client has to maintain parity with each other. As mentioned, the logic for this screen gets complicated quickly and each client has their own intricacies and specific implementations for handling state, displaying UI, etc. It’s easy for clients to quickly diverge from one another.

Finally, mobile has a versioning problem. Each time we need to add new features to our listing page, we need to release a new version of our mobile apps for users to get the latest experience. Until users update, we have few ways to determine if users are using or responding well to these new features.

The Case for SDUI

What if clients didn’t need to know they were even displaying a listing? What if we could pass the UI directly to the client and skip the idea of listing data entirely? That’s essentially what SDUI does — we pass both the UI and the data together, and the client displays it agnostic of the data it contains.

Airbnb’s specific SDUI implementation enables our backend to control the data and how that data is displayed across all clients at the same time. Everything from the screen’s layout, how sections are arranged in that layout, the data displayed in each section, and even the actions taken when users interact with sections is controlled by a single backend response across our web, iOS, and Android apps.

The Ghost Platform (GP) is a unified, opinionated, server-driven UI system that enables us to iterate rapidly and launch features safely across web, iOS, and Android. It is called Ghost because our primary focus is around ‘Guest’ and ‘Host’ features, the two sides to our Airbnb apps.

GP provides web, iOS, and Android frameworks in each client’s native languages (Typescript, Swift, and Kotlin, respectively) that enable developers to create server-driven features with minimal setup.

The core feature of GP is that features can share a library of generic sections, layouts, and actions, many backward compatible, enabling teams to ship faster and move complicated business logic to a central location on the backend.

A Standardized Schema

The backbone of the Ghost Platform is a standardized data model that clients can use to render UI. To make this possible, GP leverages a shared data layer across backend services using a unified data-service mesh, called Viaduct.

The key decision that helped us make our server-driven UI system scalable was to use a single, shared GraphQL schema for Web, iOS, and Android apps — i.e., we’re using the same schema for handling responses and generating strongly typed data models across all of our platforms.

We’ve taken time to generalize the shared aspects of different features and to account for each page’s idiosyncrasies in a consistent, thoughtful way. The result is a universal schema that’s capable of rendering all features on Airbnb. This schema is powerful enough to account for reusable sections, dynamic layouts, subpages, actions, and more, and the corresponding GP frameworks in our client applications leverage this universal schema to standardize UI rendering.

The first fundamental aspect of GP is the structure of the overall response. There are two main concepts used to describe UI in a GP response: sections and screens.

Figure 1. How users see Airbnb features on GP vs. how GP sees those same features as screens and sections.
  • Sections: Sections are the most primitive building block of GP. A section describes the data of a cohesive group of UI components, containing the exact data to be displayed — already translated, localized, and formatted. Each client takes the section data and transforms it directly into UI.
  • Screens: Any GP response can have an arbitrary number of screens. Each screen describes the layout of the screen and, in turn, where sections from the sections array will appear (called placements). It also defines other metadata, such as how to render sections — e.g., as a popover, modal, or full-screen — and logging data.
Figure 2. A sample of the GP Response GraphQL schema.

A feature’s backend built with GP will implement this GPResponse (fig. 2) and populate the screens and sections depending on their use case. GP client frameworks on web, iOS, and Android provide developers standard handling to fetch a GPResponse implementation and translate that to UI with minimal work on their part.

Source link