Apr 30, 2019


Blog Categories

Categories

Blog Categories

Part 3

Getting Started with GraphQL, Part 3: The Unique Directive

In the previous two articles we explored how to set up your development environment and query your GraphQL schema, then added relationships to your GraphQL queries. In this article we’ll look at the @unique directive, which allows you to add constraints to your GraphQL schema.

To define a simple user type with a uniqueness constraint on the username, you simply add the @unique directive to the username field, and FaunaDB handles creating the index to enforce this constraint.

type User {
 username: String! @unique
}

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 extended with a User type:

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.

You can list the classes and indexes in your database by launching the shell and issuing this query. To launch the shell directly into your current database, use the --secret command line flag:

fauna shell --secret=<key-secret>

If you started with an empty database, you’ll only have one class and one index:

> Paginate(Union(Classes(), Indexes()))
{ data: [ Class("User"), Index("unique_User_username") ] }

Now let’s inspect the index with the following query:

> Get(Index("unique_User_username"))
{ ref: Index("unique_User_username"),
  ts: 1556578547300000,
 active: true,
 partitions: 1,
 name: 'unique_User_username',
 source: Class("User"),
 data: { gql: {} },
 values: [],
 terms: [ { field: [ 'data', 'username' ] } ],
 unique: true }

We can see in this response that the FaunaDB index is maintaining a uniqueness constraint on the username field. Trying to create users with duplicate usernames will result in an error.

Now let’s switch to the GraphQL Playground (make sure you configure it with the correct Authorization header), and inspect the generated schema. Here are the relevant domain objects (inspect the schema yourself to see some additional boilerplate):

type Mutation {
 createUser(data: UserInput!): User!
 updateUser(
   id: ID!
   data: UserInput!
 ): User
 deleteUser(id: ID!): User
}

type Query {
 findUserByID(id: ID!): User
}

type User {
 _db: _DBMeta!
 username: String!
}

input UserInput {
 username: String!
}

In the next article in this series we’ll see how to create a findUserByUsername GraphQL query that utilizes the generated FaunaDB unique index, as well as learn some additional schema management tricks.

If you enjoyed this topic and want to work on systems and challenges just like this, Fauna is hiring!