Getting Started with GraphQL, Part 4: Updating your Schema
Tags: graphql, serverless, database
Published: 2019-12-05 20:36:05

Author: Leo Regnier
Date: August 1, 2019
[Originally posted on the Fauna blog.](https://fauna.com/blog/getting-started-with-graphql-part-4-updating-your-schema)

---

In previous articles, 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), how to [add relationships to your GraphQL queries](https://fauna.com/blog/getting-started-with-graphql-part-2-relations), and lastly, how to [add unique constraints to your GraphQL schema](https://fauna.com/blog/getting-started-with-graphql-part-3-the-unique-directive). In this article, we’ll look at different ways you can update your current schema, and explore what you can do with Fauna’s built-in @embedded directive when it comes to schema design.

The schema is a key piece of any GraphQL API and its correct definition determines a successful interaction between clients and servers. Unlike other APIs, GraphQL uses a strong type system to define the data and the operations that can be performed. Once established, this schema is what enables, among other things, the extensive querying flexibility distinctive of a GraphQL API.

As most pieces of software, the schema needs to evolve over time, and, sooner or later, we will face a scenario in which it needs to be updated. As in other areas, GraphQL offers great flexibility when it comes to schema updates.

Let’s continue our exploration with how we can extend an existing schema through Fauna’s GraphQL API!

#Updating your schema#
In the last article, we defined a simple <code>User</code> object type with a unique <code>username</code> field:
```
type User {
  username: String! @unique
}
```
Now, we’re going to extend the <code>User</code> object by adding a new <code>Address</code> object type field to it. If you are familiar with Domain-Driven Design, we want to model the new <code>Address</code> object type as a *value object*. That is, we don’t care about an <code>Address</code>’s particular identity; we just want it to be part of the <code>User</code> object. From the API perspective, this means that we don’t need to query an <code>Address</code> on its own, but we will always do it through the <code>User</code> object. 

During the import process, unless defined otherwise, all object types are considered *entities* by default. This means that an <code>ID</code> field, as well as top-level CRUD operations, is created automatically for the given object. At the database layer, a Collection, as well as an Index, is associated for the imported object. 

In order to tell to the import process to not create all of these elements automatically, we need to use Fauna’s built-in <code>@embedded</code> directive. If annotated with the <code>@embedded</code> directive, no ID field nor CRUD operations are generated for the given object. At the database layer, the annotated type is an embedded object within the document associated with the parent object type. All of the necessary metadata for the embedded object is stored in this document as well. 

Let’s create a file with the updated schema using the <code>@embedded</code> directive for defining our new <code>Address</code> object type:
```
type User {
  username: String! @unique
  address: Address
}

type Address @embedded {
  street: String!
  city: String!
  state: String!
  zipCode: String!
}
```
Import this schema into FaunaDB by logging into the Cloud Console. Select the database you created in previous articles and go to the <code>GRAPHQL</code> section from the left menu bar. Click on the <code>UPDATE SCHEMA</code> button and select the file containing the updated schema.

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

At the database layer, the update process creates any missing collections, indexes, and functions. If any of those elements already exist, the API overrides its metadata with the new GraphQL schema information. If no new schema information is provided for elements already containing GraphQL metadata, they remain the same.

At this point, it is important to remember that the GraphQL schema information is stored in the form of metadata among the different database elements. During the update process, only this metadata might be overridden with the new given schema definition while the actual data always remains unmodified. This means that the GraphQL schema can be updated safely without worrying about data loss.

Now, let’s create a new User, along with its Address information, by running the following query from Console’s GraphQL Playground:

```
mutation CreateUser {
  createUser(data: {
    username: "jerry"
    address: {
      street: "129 West 81st Street Apt 5A",
      city: "New York"
      state: "NY"
      zipCode: "10024"
    }
  }) {
    username
    address {
      street
      city
      state
      zipCode
    }
  }
}
```
As a result, you should see the following response:

```
{
  "data": {
    "createUser": {
      "username": "jerry",
      "address": {
        "street": "129 West 81st Street Apt 5A",
        "city": "New York",
        "state": "NY",
        "zipCode": "10024"
      }
    }
  }
}
```
If you query information on any pre-existing user, you should notice that everything works as expected, and that previous data has remained unchanged. We have successfully updated the GraphQL schema definition without affecting any pre-existing data! 

#Overriding your schema#
In this section, we look at how you can override an existing schema. Overriding a schema works very differently from the update process we have described above, and it’s very important to learn the differences between these two types of operations.

When overriding a schema, all previous GraphQL metadata is removed. All database elements, such as collections, indexes and functions, which were previously annotated with GraphQL metadata, are also removed. Unlike the update operation, when overriding a schema, actual data might be erased from the database. Any other elements that do not have GraphQL metadata won’t be affected. Since this is an operation that might cause data loss, you must be careful and understand its effects.

Now, let’s create a new database to explore how the override schema process works. From the Cloud Console home page, click on the <code>NEW DATABASE</code> button:

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

Give a name for the new database and save it:

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

Once the new database is ready, let’s reuse the previous file in order to import the GraphQL schema we have used before:

```
type User {
  username: String! @unique
  address: Address
}

type Address @embedded {
  street: String!
  city: String!
  state: String!
  zipCode: String!
}
```

From the Cloud Console, select <code>GRAPHQL</code> from the left menu bar, click the <code>IMPORT SCHEMA</code> button, and choose the GraphQL schema file listed above:

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

Once the schema is imported, let’s create a new <code>User</code> as follows:

```
mutation CreateUser {
  createUser(data: {
    username: "george"
    address: {
      street: "1344 Queens Blvd",
      city: "Long Island City"
      state: "NY"
      zipCode: "11101"
    }
  }) {
    username
    address {
      street
      city
      state
      zipCode
    }
  }
}

```
You should see the following response:
```
{
  "data": {
    "createUser": {
      "username": "george",
      "address": {
        "street": "1344 Queens Blvd",
        "city": "Long Island City",
        "state": "NY",
        "zipCode": "11101"
      }
    }
  }
}
```
Now that we have an initial schema and some data already loaded into the database, let’s see what happens when we override the current GraphQL schema.

Create a new file containing the following schema, which does not include the <code>User</code> nor the <code>Address</code> object type:
```
type Todo {
  title: String!
  completed: Boolean
}

type Query {
  allTodos: [Todo!]
  todosByCompletedFlag(completed: Boolean!): [Todo!]
}
```

From the <code>GRAPHQL</code> view in the Cloud Console, select the <code>OVERRIDE SCHEMA</code> button. You should see a warning message explaining the effects of the override operation:

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

Select <code>OVERRIDE</code> and choose the schema file mentioned above. The operation takes around one minute to complete; this extra time is necessary to allow all cluster nodes to process the deletions.

Once the override is finished, let’s try to create a new <code>User</code> again:
```
mutation CreateUser {
  createUser(data: {
    username: "elaine"
    address: {
      street: "16 West 75th Street Apt 2G",
      city: "New York"
      state: "NY"
      zipCode: "10023"
    }
  }) {
    username
    address {
      street
      city
      state
      zipCode
    }
  }
}
```

Since the <code>User</code> and <code>Address</code> objects are no longer present in the overridden schema, you should get an error response:

```
{
  "data": null,
  "errors": [
    {
      "message": "Cannot query field 'createUser' on type 'Mutation'. Did you mean 'createTodo'? (line 2, column 3):\n  createUser(data: {username: \"george\", address: {street: \"1344 Queens Blvd\", city: \"Long Island City\", state: \"NY\", zipCode: \"11101\"}}) {\n  ^",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}
```
If you try to find the <code>User</code> collection, you will notice that it has been removed along with all of its documents:

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

We have now learned how the data is affected when overriding a GraphQL schema!

#Conclusion#
In this post, we have explored the two different ways that a GraphQL schema can be updated. We have learned the important differences between these two methods, as well as how Fauna’s built-in <code>@embedded</code> directive can help you to model the schema in more advanced ways.

Stay tuned for more about GraphQL and FaunaDB, as we explore how to import a schema for an existing database, how to write custom mutations, how to paginate over a list of objects, and much more!