Using JSON Schema to build cross-platform forms

Marton Bodonyi
Behind the genes at Eugene
3 min readFeb 5, 2021

Our member facing forms at Eugene are custom build using a system we called April which allows multiple front-end forms to be built using a single unified schema.

At Eugene we collect a variety of information from our members throughout the testing process, from when they first reach our website to providing detailed family history and consent for testing. From our very first form, we decided to to build form structures that are defined by our back-end and remain consistent across all our platforms.

So why share form structure across platforms?

In a many consumer facing apps there isn’t a lot of pressure to sync up form structure across different platforms, especially true if you’re using GraphQL. In fact in a lot of products it’s better if the web and app experiences don’t mirror each other field for field. For Eugene however, being consistent in how we ask questions and when we ask questions is critical because we’re dealing with health data. The copy of a question or the placeholder of an input could affect the accuracy of the health information being provided to us.

The same question asked on each platform.

JSON Schema to the rescue

I’ve written a few different form structure libraries in the last few years in PHP and JavaScript, and every one of them has ended up flawed and messy. They all start neat, perfect well oiled machines. Then the exceptions come. You realise you need a little bit of extra validation, maybe you need to support a new widget type or you need to implement dependencies. Before you know it that neat beautiful form structure code is a web of chaos that only you can understand … on a good day. Instead of coming up with our own custom data structures we decided to use JSON Schema.

Validating our forms twice

One of the neat benefits of using JSON Schema is that we can validate our forms on both the front-end and back-end using the same source of truth. Before the data gets sent, it’s validated in the browser using the same form schema used to build the ui via ajv (aka another json validator) so the likelihood of it being bounced by the server is next to nil anyway. Because we ask questions one-by-one, we can validate an answer before letting the customer proceed, so they don’t need to go back and clear up validation messages after they’ve finished the form.

Outsourcing the chaos to UI Schema

There’s only so far you can go with JSONSchema defined forms before your UI will look like it was written by a robot. To define our UI definitions we borrowed a supplementary data structure from react-jsonschema-form, the uiSchema file. The idea is that the form schema is a pure, standards based and validate-able file and the ui-schema json file is a wild west of experimental UI enhancements, widget definitions and dependency calculations. It keeps our data layer tight whilst allowing us to experiment with our UI.

The downsides to centralised form structure storage

JSONSchema is pretty stable and unlikely to change however our UI schema gets regular updates, new widgets etc. Keeping them up to date means sometimes having to time back-end and front-end deploys, and needing to have sensible ui fallbacks for when a widget isn’t available on a platform yet. For our iOS app we have the ability to remotely force users to update their app if there’s been a significant schema change to a crucial form.

Interested in building forms that make a difference and adding a few more lines to that ui.json file? Head over to https://angel.co/company/eugenelabs and get in contact with us.

--

--