The power of GraphQL schema definition language

by Peter Balazs on 11/10/2018

When we started to build Mozaik we wanted to create a headless GraphQL CMS that helps developers a lot. The first step in the process of setting up a headless content management system is creating the content model. Most of the current content management systems allow you to do this either by filling in many forms, for a content type and all of its fields or by using a drag and drop visual editor. This is an entirely viable way to do things. Until you want to set up a staging or different development environment, or just adding a new field, a new type. Then it comes at a price: you have to do the same repetitive task again and again, and probably it's not the best way to spend our time as developers. So there was the obvious question: if it is a headless CMS why we can't manage everything with the API? Why do we, developers need to spend any time on a UI instead of just running an automated task that does everything for us? Even more, why can't we keep our content type schema as part of our code? So we can follow who modified what, we can be sure that it reproduces the same result and we minimise the possibility of human error.

Because of these issues, it was a very clear goal from the very beginning that we want to build Mozaik in a way that enables content type schema management programmatically. The first version made it possible to define content types as JSON objects and to make calls to the API to manage schema. Although it was a safe first step, there were a few issues: on a larger project or when there are multiple content types that are dependent on each other. It was a must to calculate a dependency tree and run the API calls to create the different types and fields in that order. Also with many content types the content type declaration becomes way too verbose and harder to manage or understand. So we turned to the GraphQL Schema Definition Language (SDL) for help.

The GraphQL SDL is expressive but simple and intuitive. Moreover, with custom directive definitions it can be extended easily. Let’s see a simple example:

"""
Author type
"""
type Author {
  avatar: Image
  name: String!
}


"""
Homepage type
"""
type Homepage @singleton {
  headerImage: Image
  title: String @config(label: "Site title")
  topPosts: [Post]
}

"""
Post type
"""
type Post {
  headerImage: Image
  title: String
  content: RichText
  author: Author
}

It’s pretty self-explanatory. The two main concepts of a schema definition are the types and the fields. Also, with custom directives, like the @singleton it is possible to provide additional information for types or fields. It’s much easier to declare a Mozaik content type schema as the example above instead of writing a large JSON file. Also with some not that well-known features of GraphQL, we were able to add some handy features on top of this.

As a project evolves, it is unavoidable to change to content type schema in Mozaik. An additional field, a new content type, a required (or some other validation) for a field. Doing this with a visual editor is just simply not good enough. You would lose the context: why that change was required, who made the change. Also, there is a chance that the change might introduce a breaking change in the code base. One of the main concepts of GraphQL - and probably our favourite one - is that a change in the API should be introduced without breaking existing queries.

The GraphQL reference implementation contains a few utility functions that can help detect breaking (or dangerous) changes in a GraphQL schema. With the help of these methods - and making some changes to them - we were able to implement full migration support: now developers can define the content type schema using the standard GraphQL schema definition language (with some custom types and directives), keep it as part of the project’s code base. If you want to make any change to the schema, Mozaik can check the diff between the existing and the new schema, and we can apply the changes with a simple CLI command.

Another handy feature of defining a content type schema with the GraphQL SDL is that you can create reusable templates. You are a freelancer, building similar websites? Or an agency specialised in ecommerce development? You can easily create a standard template that you can use as the base for your different projects, and add the extra fields or types that are project specific.

Not spending time with visual editors or forms to manage the data models of your project, but having a clear, understandable and trackable source of truth for your content type schema. That is the power of GraphQL SDL.