GraphQL

This topic describes how Grafbase leverages GraphQL to define your data model. For information about Grafbase schema support, see the Reference.

GraphQL gives you the ability to define your data model in a straightforward schema.

For example, the schema for the GraphQL Todo template looks like:

type TodoList @model {
  id: ID!
  title: String!
  todos: [Todo]
}

type Todo @model {
  id: ID!
  list: TodoList
  title: String!
  complete: Boolean
}

The exclamation mark (!) indicates that the field is required.

The @model annotation tells Grafbase to create queries and mutations for instances of that type. See Directives for further information about Grafbase directives.

You can plug any of these queries and mutations into the playground for the todo project we created in the Grafbase Tutorial.

The following query lists the IDs of up to 10 of your TodoList objects:

{
  todoListCollection(first: 10) {
    edges {
      node {
        id
      }
    }
  }
}

The following mutation creates a TodoList object and returns the id of the new object:

mutation {
  todoListCreate(input: { title: "Next week" }) {
    todoList {
      id
    }
  }
}

The following mutation creates a new Todo entry, and links it to the TodoList entry with the ID todo_list_01a23bcdefgh4i5jkl67mnop89. We then return the id and title of the newly created object:

mutation {
  todoCreate(
    input: {
      complete: false
      title: "My first todo item"
      list: { link: "todo_list_01a23bcdefgh4i5jkl67mnop89" }
    }
  ) {
    todo {
      id
      title
    }
  }
}

Let's retrieve to 10 of our TodoList objects, and show their id and title, as well as the id, title, and complete status for the Todo objects for each list:

{
  todoListCollection(first: 10) {
    edges {
      node {
        id
        title
        todos {
          id
          title
          complete
        }
      }
    }
  }
}

So if you have one TodoList object with one Todo object, this query returns a JSON blob like the following, whereLIST-ID is the ID of the TodoList object and ITEM-ID is the ID of the Todo object:

{
  "data": {
    "todoListCollection": {
      "edges": [
        {
          "node": {
            "id": "LIST-ID",
            "todos": [
              {
                "id": "ITEM-ID"
              }
            ]
          }
        }
      ]
    }
  }
}

Contrast that with a typical REST API sequence:

  1. Get the list of to-do lists
  2. For each list:
    1. Get the list id and title
    2. Get the list items
    3. For each list item:
      1. Get the item id, title, and completion status

So at least (# lists) X (# items/list) calls versus one call.

Of course there is more work on the server side to resolve the query, but that's likely where the data is anyway.

We give you two paths to using GraphQL to define your data: using one of our templates, or using a GraphQL schema that you have already defined.

To use your GraphQL schema, you must have it defined in a file called schema.graphql within the directory grafbase at the root of your main branch in a GitHub repository.

You might wonder how we store your data based on a GraphQL schema.

Once we know what the GraphQL schema looks like, we provision a database for you that maps to your schema.

We also provide queries and mutations that support create, read, update, and delete (CRUD) operations for all of the types in your schema that you have annotated with a @model directive.

For example, if you define a TodoList type as shown previously, we provide a mutation to create a new list, which requires you supply a title.

If the mutation succeeds, we create a new TodoList object entry in the database. We do all of the heavy lifting to manage the interface between the queries and mutations and the database; you simply write code using the queries and mutations.

  • We have a naming convention for the default CRUD queries and mutations we create from your schema. For example, for the TodoList type:

    • todoListCreate creates a TodoList object
    • todoList returns data about a specific TodoList object
    • todoListCollection returns data about all TodoList objects
    • todoListUpdate updates a TodoList object
    • todoListDelete deletes a TodoList object

For example, to create a TodoList object, with the title "Wednesday meeting", and display its id:

mutation {
  todoListCreate(input: { title: "Wednesday meeting" }) {
    todoList {
      id
    }
  }
}

Which returns:

{
  "data": {
    "todoListCreate": {
      "todoList": {
        "id": "todo_list_01g63sfhj662trz7y5dcetsxy4"
      }
    }
  }
}

You can create a TodoList object at the same time you create a Todo object. Here we create an unfinished Todo object with the title "Call vet", add it to a new TdoList object with the title "Monday to-do list", and return the id of the title of the new list, and id, title, and completion status of the new item:

mutation {
  todoCreate(
    input: {
      title: "Call vet"
      complete: false
      list: { create: { title: "Monday to-do list" } }
    }
  ) {
    todo {
      id
      title
      complete
      list {
        id
        title
      }
    }
  }
}

This returns something like:

{
  "data": {
    "todoCreate": {
      "todo": {
        "id": "todo_01g63w6k9r33e4p9pftee0r8nw",
        "title": "Call vet",
        "complete": false,
        "list": {
          "id": "todo_list_01g63w6k9r33e4p9pftee0r8nw",
          "title": "Monday to-do list"
        }
      }
    }
  }
}

This ability to create a new object when the schema calls for an object ID is further described in Relations.