Server Driven UI, Part 1: The Concept

S

I’ve recently been having some conversations with developers from the community about GraphQL and how it is being used in their work, with the aim to influence some of the changes we are making in our stack at Buffer. During one of these chats with Maria Neumayer, there was some experience shared of designing GraphQL schemas to represent the presentation of screens in an app. This approach stuck in my mind for some time, and I started to think about how I could utilise that idea to completely drive the UI of applications using GraphQL.

I recently shared this tweet on twitter, which seemed to spark some interest from fellow developers around Server Driven UI. Server Driven UI is an interesting concept and is nothing new – many companies are currently using the approach to allow for more dynamic UIs in their apps, A/B testing and quicker adoption for any changes that they are shipping. However, with newer technologies, Server Driven UI becomes a lot smoother to work with – allowing you to create completely dynamic and flexible UIs with reduced friction. With that in mind, this series of articles will run through my explorations with Server Driven UI and how powerful the concept can become when coupled with declarative UI.


So, what exactly is Server Driven UI? Maybe more importantly, what is Server Driven UI not? Let’s take a look at how we currently build out most of our applications. We have a client and server, where the client will request some data from the server and then display that data within the UI which it has statically defined. For example, let’s say we are fetching a list of categories that we wish to display in a list on the screen:

Here, the client will receive back a list of categories and use them to set the data in the list. In this case, the data is driven by the server, but the UI is defined by the client. The layout of the UI is statically defined by the client, meaning the UI will always contain the Toolbar, Vertical Scrolling list and the list children which are specified by the client. With that in place, the server is returning the data which is used to populate the pre-defined UI components.

The key here is that on our client we have already defined what the UI is to look like, we are just using the data from the server to populate the components of our UI – this is a static approach to building user interfaces. On the other hand, with Server Driven UI, the application does not have the structure or components of a screen already defined. Instead, the server will return what that screen should look like – this is in terms of both the data for the screen and how that data should be presented.

Here our API returns a collection of UI components which are used to make up the presentation of a screen. The data of the categories is the same as in the previous example, but this time it is contained within the UI components which are to be displayed. With this, our application becomes a simple renderer of visual components. It doesn’t need to manually control the UI components on screen to depict how it should that content, instead it just gets told what it is to show on screen. With that emphasis, server driven UI becomes more about the what than the how.

Note: Because I am using GraphQL and its fragments functionality, the _type property above automatically maps to a strongly typed object within the clients via the use of Apollo.


Before we get started with this series of articles, I believe it’s important for us to set some expectations. Server Driven UI is not a silver bullet – it’s important to understand the use cases that it will work for. Whilst we can’t be aware of every use case and scenario here, I believe it’s fair to say that the more complex your UI gets, the more complicated your server driven UI logic will become. As things become to look more complex, it’s worth questioning whether it is the best approach to take for implementation.

Even if your UI is simple, you also need to question – do I need my UI to be driven by the server? Just because it can be, it doesn’t mean it should be. If done for the sake of it, we could introduce difficulties when moving forward with our app in future. For example, maybe we have some screens in our app that almost never change, or support some really complex native interactions. These kind of things might not make sense to drive from the server, as we either add complexity for something that does not have much rate of change, or end up trying to fight with a lot of constraints to generalise something from the server that could bring more difficulties in future maintenance.


I’m currently in the process of revamping compose.academy – the new version will not only run in the web, but there is also a supporting Android / iOS / Mac app in the works. With this range of different platforms, and the nature of the application, it felt like a good opportunity to explore Server Driven UI. The new Compose Academy will have essentially 4 screens – a list of categories (e.g Layout), followed by a list of subjects within that category (e.g Column, Row), followed by a list of Topics within that subject (e.g Building a Column, Aligning children in a Column), followed by the screen for the actual article themselves.

Currently the first 3 screens are quite basic, but the the fourth (Article) screen can contain any kind of component in any kind of order – so it feels quite dynamic. I also have plans for the other screens to be quite flexible in the content they display (e.g a whats new bar, read next bar, additional inline components), so being able to render that from the server side saves me updating the 4 different clients individually.

But how is this going to work? There are likely ways to make this work in some automatic fashion (programmatically having composables rendered directly from the server response), but for me this currently feels a little too magical. What I’ve opted for here is a design system within each application, made up of native components. These components are then mapped from the server response – so if the GraphQL fragment is of Type Image, we map to the native Image class in the client. In the Example of Android, this then can be used to construct an Image composable where required.

With this design library within client, we can literally use any component in any screen and it will be automatically rendered via the server side changes. For example, let’s say we want to add a search bar to one of the screens, or add a new component into a vertical list – all we need to do here is add the component to the server response and all clients will have that change in place.

This use of a design library and mapping from the server response still gives the client some control of what it supports, it also feels like a good balance between the client and server responsibilities. Whilst this is not a groundbreaking approach and is also possible with REST APIs and imperative UIs (with a lot more complexity and code), the type safety of GraphQL + Typescript, coupled with declarative UI frameworks like SwiftUI, React and Jetpack Compose allows us to achieve this with a lot more simplicity.


Now that we’ve talked a bit about the approach, let’s quickly look at the stack that’s being used across Compose Academy. When it comes to these clients, the stack across all the product looks like the following:

Each of the clients here are utilising the Apollo GraphQL SDKs, simplifying the tasks of querying the API for the presentation of each screen. The clients query the API using Fragments – so for example, we can query for a Detail Card component like so:

fragment detailCard on DetailCard {
    categoryId
    title
    description
    image
    type
}

Within a query, we can then query for each component type that is in our design system (and is supported by that screen), followed by mapping that Fragment result to a component from our native design system.

With this flow, the client ends up with an ordered list of components which are to be displayed on screen, fully controlled by the server and backed by strongly typed responses.


Now that we’ve introduced this concept, the following articles will focus on each of the components mentioned in the above client diagram. In the next post we’ll be looking at building the GraphQL API using Typescript, and how that is used to provide presentational responses to its clients!

About the author

hitherejoe

Add Comment

By hitherejoe