Tutorial

A GraphQL SDL Reference

Published on September 27, 2018
Default avatar

By Alligator.io

A GraphQL SDL Reference

GraphQL schemas for a service are now most often specified using what’s known as the GraphQL SDL (schema definition language), also sometimes referred to as just GraphQL schema language. It’s a language with a very simple syntax that allows to define a schema very succinctly. Once you have a gasp at the different syntax elements of the SDL, you’ll be able to write schemas in no time flat.

The Basics

Here’s what a basic GraphQL schema deffinition for a simple todo app could look like:

# Enumeration type for a level of priority
enum Priority {
  LOW
  MEDIUM
  HIGH
}

# Our main todo type
type Todo {
  id: ID!
  name: String!
  description: String
  priority: Priority!
}

type Query {
  # Get one todo item
  todo(id: ID!): Todo
  # Get all todo items
  allTodos: [Todo!]!
}

type Mutation {
  addTodo(name: String!, priority: Priority = LOW): Todo!
  removeTodo(id: ID!): Todo!
}

schema {
  query: Query
  mutation: Mutation
}

A lot is going on here, so let’s break down some of the most important things:

Object Types

Object types are specific to a GraphQL service, are defined with the type keyword and start with a capital letter by convention. They define the type name and the fields present under that type. Each field in an object type can be resolve to either other object types or scalar types. Scalar types point to actual data and represent the leaves of the graph.

In the above schema deffinition we have the Todo object type as well as the Query and Mutation root object types. Only the Query root type is required in all GraphQL schemas, but the mutation root type will most often also be present when the service allows for updating, adding or deleting data. Additionally, a Subscription root type is also available, to define operations that a client can subscribe to.

Built-In Scalar Types

There are 5 built-in scalar types with GraphQL: Int, Float, String, Boolean and ID. Scalar types, as opposed to object types, point to actual data. The ID type resolves to a string, but expects a unique value.

Enumeration Types

Enumeration types allow to define a specific subset of possible values for a type. In the previous example, the Priority enum type can take a value of LOW, MEDIUM or HIGH and anything else will result in a validation error. On the client strings are used to provide a value for an enum type.

Type Modifiers

As you can also see from the above example, modifiers can be used on the type that a field resolves to by using characters like ! and […]. Here’s a breakdown, using the String scalar type as an example:

  • String: nullable string (the resolved value can be null)
  • String!: Non-nullable string (if the resolved value is null, an error will be raised)
  • [String]: Nullable list of nullable string values. The entire value can be null, or specific list elements can be null.
  • [String!]: Nullable list of non-nullable string values. Then entire value can be null, but specific list elements cannot be null.
  • [String!]!: Non-nullable list of non-nullable string values. Nothing can be null, neither the whole value nor the individual items. An empty list ([]) is still valid because the whole value is not null and there’s no individual null values.

Comments

Comments are added with the # symbol and only single-line comments are allowed.

Custom Scalar Types

It’s also possible to define custom scalar types with a syntax like this:

scalar DateTime

With this though, the GraphQL service will need to define how the custom scalar is to be serialized and validated.

Union Types

Union types define a type that can resolve to a number of possible object types:

# ...

union Vehicule = Car | Boat | Plane

type Query {
  getVehicule(id: ID!): Vehicule!
}

With union types, on the client, inline fragments have to be used to select the desired fields depending on what subtype is being resolved:

query {
  getVehicule {
    ...on Car {
      year
    }
    ...on Boat {
      color
    }
    ...on Plane {
      seating
    }
  }
}

Interfaces

Interfaces are somewhat similar to union types, but they allow multiple object types to share some fields:

interface Vehicule {
  color: String
  make: String
  speed: Int
}

type Car implements Vehicule {
  color: String
  make: String
  speed: Int
  model: String
}

# ...

Each type that implements an interface need to have fields corresponding to all the interface’s fields, but can also have additional fields of their own. This way, on the client, inline fragments can be used to get fields that are unique to certain types:

graphql {
  getVehicule {
    color
    make
    ...on Car {
      model
    }
  }
}

Input Types

When a query or mutation expects multiple arguments, it can be easier to define input types where each field represents an argument:

# ...

input NewTodoInput {
  name: String!
  priority: Priority = LOW
}

type Mutation {
  addTodo(newTodoInput: NewTodoInput!): Todo!
  removeTodo(id: ID!): Todo!
}

Schema Documentation

There’s also a syntax to add human-readable documentation for types and fields, which can become really helpful when using a tool like GraphiQL or GraphQL Playground to browse the documentation for a schema.

Let’s take our initial todo schema example and add some documentation for the types and some of the fields:

"""
Priority level
"""
enum Priority {
  LOW
  MEDIUM
  HIGH
}

type Todo {
  id: ID!
  name: String!
  """
  Useful description for todo item
  """
  description: String
  priority: Priority!
}

"""
Queries available on the todo app service
"""
type Query {
  """
  Get one todo item
  """
  todo(id: ID!): Todo
  """
  List of all todo items
  """
  allTodos: [Todo!]!
}

type Mutation {
  addTodo(
    "Name for the todo item"
    name: String!
    "Priority levl of todo item"
    priority: Priority = LOW): Todo!
  removeTodo(id: ID!): Todo!
}

schema {
  query: Query
  mutation: Mutation
}

As you can see, documentation for types or fields is added by wrapping with the *“”" … “”“* syntax. The *” … "* is used for documentation on arguments.

With this you should be off to the races with defining GraphQL schemas. You can also always refer to the official spec when you’re unsure about some of the syntax.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Alligator.io

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel