Getting Started with GraphQL, Part 2: Relations
Tags: graphql, serverless, jamstack, database
Published: 2019-12-04 22:41:57

Author: Chris Anderson
Date: April 11, 2019
[Originally published on the Fauna blog.](https://fauna.com/blog/getting-started-with-graphql-part-2-relations)

---

In the previous post, we explored [how to set up your development environment and query your GraphQL schema](https://fauna.com/blog/getting-started-with-graphql-part-1-importing-and-querying-your-schema). Assuming that you are already connected to your database via Fauna Shell and GraphQL Playground, this article focuses on adding relationships to your GraphQL queries.

*FaunaDB’s GraphQL API automatically turns your schema definition into FaunaDB relations so that relational queries are easy.*

Follow along on your workstation in GraphQL Playground to explore FaunaDB's native GraphQL API.

#The @relation directive#
The @relation directive connects an attribute to another GraphQL type, so that you can model your domain. By default, document references are embedded in the source object, but when the @relation directive is used, indexes are created and queried automatically. In this app, each todo belongs to a particular list. Also, we add a query to find all of the lists including their related todos. Note that FaunaDB’s GraphQL API takes care of connecting the List and Todo types, so the GraphQL you expect to write just works.

```
type Todo {
    title: String!
    completed: Boolean!
    list: List
}

type List {
    title: String!
    todos: [Todo] @relation
}

type Query {
    allTodos: [Todo!]
    todosByCompletedFlag(completed: Boolean!): [Todo!]
    allLists: [List!]
}
```
Import this schema into FaunaDB by creating a database, provisioning a key secret, and uploading it via curl (for detailed instructions see the first article in this series). Alternatively, you can just reuse the secret from the previous article, and your schema will be safely upgraded:
```
curl -u <key-secret>: https://graphql.fauna.com/import --data-binary "@<graphql-schema-filename>"
```
Now you can inspect the schema via Fauna Shell or GraphQL Playground. Remember to configure the Authorization header in your GraphQL Playground for the current database.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/p5llbcnk6yo7lf4efq9x.png)

The generated schema adds some new types for the <code>@relation</code> directive: <code>ListTodosRelation</code> and <code>TodoListRelation</code>. These types correspond to indexes or document references in FaunaDB and are transparently managed by the FaunaDB GraphQL API.
```
input ListTodosRelation {
 create: [TodoInput]
 connect: [ID]
 disconnect: [ID]
}

input TodoListRelation {
 create: ListInput
 connect: ID
 disconnect: Boolean
}
```
When you create an object, you can connect it to existing objects, or create new related objects. Additionally, when modifying an object you can disconnect related objects by id. Continue reading for examples.

#Create a todo list#
The first thing we need to do is create a list and add all of our existing todos to it. Let’s create the list via GraphQL:
```
mutation CreateAList {
   createList(data: {
     title: "Build an awesome app!"
   }) {
     title
     _id
   }
}
```
Note the id from this result, as you'll need it in the Fauna Shell.

#Migrate existing todos to the list#
To migrate the existing todos, it’s easiest to use Fauna Shell and issue a bulk update using the id returned from the above <code>CreateAList</code> query:
```
$ fauna shell graphql # or whatever your database is named
```
In Fauna Shell issue this query (using your id):

```
> Map(
  Paginate(Match(Index("allTodos"))), 
  todoID =>
    Update(todoID, { 
      data: { 
        list: Ref(Class("List"), "228661410636235268") 
      }
    }))
```
And the results should look something like:

```
{ data:
   [ { ref: Ref(Class("Todo"), "228474048686850572"),
       ts: 1554334241180000,
       data:
        { title: 'Build an awesome app!',
          completed: true,
          list: Ref(Class("List"), "228661410636235268") } },
     { ref: Ref(Class("Todo"), "228474165045232141"),
       ts: 1554334241180000,
       data:
        { title: 'Connect the front end.',
          completed: false,
          list: Ref(Class("List"), "228661410636235268") } },
     { ref: Ref(Class("Todo"), "228474207247270411"),
       ts: 1554334241180000,
       data:
        { title: 'Implement RBAC for Access control.',
          completed: false,
          list: Ref(Class("List"), "228661410636235268") } } ] }
```
#Query todos in a list#
This query lists all of the todos in a particular list, as well as the list’s title:
```
query FindAListByID {
    findListByID(id: "228661410636235268") {
        title
        todos {
          data { title completed }
        }
    }
}
```
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/bk5yuvof025ci0tk2q9v.png)

In the screenshot, we can see that all of the todo titles and their completed status have been returned as part of the result set. FaunaDB’s GraphQL API automatically turns your schema definition into FaunaDB relations so that relational queries are easy.

#Move a todo to a new list#
We can move one of our todo items from one list to another list. First create a new list using the <code>CreateAList</code> query above, and copy its id. Then choose a todo to update, and use its id together with the list id, in a query to set the <code>connect</code> field on the list attribute:
```
mutation UpdateATodo {
    updateTodo(id: "228474048686850572", data: {
        title: "Build an awesome app!"
        completed: true,
        list: { connect: "228668866541126147" }
    }) {
        title
        completed
    }
}
```
Note the <code>connect</code> field which is supplied as part of the generated FaunaDB schema. This is how the FaunaDB GraphQL API manages references between documents.

#Query all lists with todos#
The last query is similar to the <code>FindAListByID</code> query above, except instead of finding one list, it finds them all. I like this query because it shows the power of relations in FaunaDB’s GraphQL API. Each list includes the todos, without the developer having to concern themselves with any underlying database design issues like joins or indexes. Here’s the query:
```
query FindAllLists {
    allLists {
      data { 
        _id
        title
        todos { 
          data {
            title 
            completed 
          }
        }
      }
    }
}
```
You can see in the screenshot that our new list has some todo items assigned to it, and their title and completed state are inlined into the response. Thanks GraphQL, for making app development super simple!

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/sfpvnzt7lfuxxw85cuz7.png)

#Create a list with some todos#
Similarly to the ,code>connect</code> field, the <code>create</code> field gives access to the underlying collection. So you can add a list together with a handful of todos in a single GraphQL mutation. Here is a query which does that:
```
mutation CreateListWithTodos {
    createList(data: {
        title: "The Basics",
          todos: { create: [ 
            {completed: false, title: "Water"}, 
            {completed: false, title: "Food"},
            {completed: false, title: "Shelter"}]},
    }) {
        _id
        title
        todos {
          data {
            title
          }
        }
    }
}
```
If you rerun your <code>FindAllLists</code> query, above, you’ll see the new list with its todos. 

#Add todos to an existing list using the create API#
The create capability can also be used in the context of a mutation. One way to add new todos to a list (while changing its other fields if you like) looks like this:
```
 mutation UpdateAList {
    updateList(id: "228833728394166795", data: {
        title: "The Very Basics"
        todos: {
          create : [{title : "Fire", completed: true}]
        }
    }) {
        title
        todos { 
            data {
               title
            }
        }
    }
}
```
In [Part 3](https://fauna.com/blog/getting-started-with-graphql-part-3-the-unique-directive) of this series, we'll look at how to add constraints to our schema using the <code>@unique</code> directive.