EXPEDIA GROUP TECHNOLOGY — SOFTWARE

Schema Driven UIs

How to design a data-driven UI using schemas

Nazim Jamil-Mir
Expedia Group Technology

--

Photo by Caspar Camille Rubin on Unsplash

Problem

Not all UI’s need to be dynamic, but when you’re building an application where almost every option or visual element exposed to a user is underpinned by a level of permissions or real time data, where do you start?

What is responsible for managing this effect? You could take a straight forward approach of wrapping every possible thing in a condition but is that maintainable?

Given a green field project, could we control what is exposed to the user without any conditional logic, or without any logic at all on the client side.

Does the UI need to know anything it doesn’t need to know?

Theory

By providing a complete schema (configuration) of the user interface, the UI could create appropriate elements as per the schema.

By putting in place the structural components, we can recursively build everything from the given schema. The application would need to make an initial call to a service which would return the schema in JSON format.

Elements drawn would mirror the hierarchy of the schema e.g.

[{
"home": {
"header": {
"h1": "This is a page title",
"h2": "This is the sub title"
},
"block": {
"p": "This is a paragraph and there may be many of them."
}
}
}, {
"functions": ["read", "copy"]
}]

The keys could contain far more detailed values and types, it would be different based on each use case.

The expectation is that the service generating the schema will do so on a user access basis. A token identifying the user on the schema request would contain a username and the schema service would fetch that users permissions.

The permissions would describe things like if the user has access to home, or another page, or if a user has access to the edit user interface.

In the case of exposing a UI, all permutations must exist in the code, but it is only rendered based on the permissions. e.g.

const buttonsToRender = ["read", "copy"]; // from schema

buttonsToRender.map(
buttonText => <button type="button">`${buttonText}`</button>
);

Use cases

Sure

Sure is an internal Expedia Group™ Data Analytics Exploration Tool, it exposes datasets on a granular level and manages this using permissions. Each user can be assigned groups e.g Finance, Business Dev etc.

Groups describe which data points (Metrics, Dimensions etc.) are available to a user as well. This also limits the view of data down to a field level.

We produced a dynamic schema which would only return the datasets available to a user. Within those datasets, the additional metadata for the fields is available to render the UI appropriately.

{
"datasets": [
{
"dataSetName": "pageViews",
"description": "Page views for site",
"fields": [
{
"category": "Pages",
"description": "Pages on site",
"fieldName": "homepage",
"fieldType": {
type: "TEXT"
},
"isAggregatable": true,
"isSearchable": false,
}
]
}
]
}

This gives us a complete list of all the fields for a given dataset the user is allowed to interact with. These fields can be represented in any way we want on the UI e.g. as buttons or a drop down menu.

Other domain specific information is also provided, eg. isAggregatable can be used to let the UI know that a given field can be used to call an aggregate function, or defining a range for example T28 which defines a timestamp for the last 28 days and is rendered on this occasion as options.

Schema example
Schema example
Schema driven UI example
Schema driven UI example

Offline Support App

Offline Support is an app which represents a configuration, it is full of input fields over four tabs. There are no granular permissions in this app like in the Sure example above so it was a good candidate to try another schema driven UI.

{
"data": [
{
"children": [
{
"children": [
{
"fieldData": {
"fieldId": "emailAddress",
"fieldLabel": "Email Address",
"fieldType": "textInput",
"fieldValue": null
},
"type": "field"
}
],
"sectionLabel": "Customer service details",
"type": "section"
}
],
"tabLabel": "Contacts",
"type": "tab"
}
]
}

Each tab is represented by an object in the data array, all attributes are described within those and so on.

The result pictured below is produced with a main recursive function that takes the schema and based on the type will call the appropriate function, there is one for creating tabs, sections and fields.

Schema driven UI example
Schema driven UI example

Conclusion

Where appropriate, having a schema driven UI is fantastic, changes only need to be made in a single location — the schema. It is driven by data and can be changed by simply modifying permissions or a database. We found it incredibly easy to maintain, testing was also simplified and we leaned heavily on end to end tests to verify that the things are rendered correctly and worked as expected by altering the schema.

It also meant, specially in the case of Sure, that there wasn’t any limitation on how fast we could expose newly ingested datasets as they are represented with a schema so they’re immediately available.

It hasn’t always been possible in both the use cases described above to drive the UI 100% with the schema, an example would be half way through development of a component that is driven by the schema, a new requirement would be introduced which bucks the trend of being able to be generated recursively.

We navigated one occasion in Sure by enriching the schema on the client side with the required flag / description to do this edge case. Another occasion in Offline Support we decided not to render a type of element recursively as it only appeared once and had unique behaviour, it wasn’t binary and relied on the user input to effect the state of related elements.

What I would recommend is that where the context of an element is underpinned by a dynamic source that is a prime candidate for a schema driven UI and to not limit the source of a schema to an API, I wouldn’t recommend bundling the schema with the artifact, not in the long term at least as it mitigates one of the benefits of being able to update the UI without a full deployment.

Another key point that stands out is that the complexity of the UI has been reduced, in both cases the applications are Single Page Apps (SPA) which carry a lot of scaffolding for state management, routing etc so it was refreshing to have a UI that would render based on a schema only known at runtime.

More about Expedia Group Tech: https://lifeatexpediagroup.com/technology

--

--