How Do I Use My Endpoints? GraphQL Queries and Mutations

Now you’ve set up your schema, but how do you use your GraphQL endpoints?

Note

This tutorial assumes that you’ve set up your GraphQL schema. If you haven’t, please take a look at the 10 minute guide to GraphQL schema

Generated Resolvers

To query or change data in a GraphQL server, you need to call one of the ‘functions’ defined on your server. These functions are names resolvers, and Dgraph automatically generates up to five resolvers for each type defined in your schema.

For example, if we define a Tweet type in the schema, we get the following resolvers:

  • GetTweet (Only if an ID field was defined)
  • QueryTweet
  • AddTweet
  • UpdateTweet
  • DeleteTweet

Accessing your endpoints

The quickest way to start playing around with your endpoint is to download GraphQL Playground. Once one of these is downloaded, point it at your Slash endpoint. Your GraphQL endpoint can be found on the dashboard. It will look something like: https://example.us-west-2.aws.cloud.dgraph.io/cloud.

GraphQL Playground

If you open up the docs tab on the right side, you’ll see that GraphQL playground has pulled all the possible resolvers that our server supports.

Mutations

GraphQL operations can be of two types, queries and mutations. Queries are defined as read-only operations, while mutations are write operations. We’ll start with mutations, so we have something to query in the next step.

The first operation that we want to do is get some data inserted into our database. Let’s add some users, and also create some tweets at the same time. You can copy and paste the following mutation into GraphQL playground.

mutation {
    addUser(input: [
        { handle: "firstuser", name: "First User!", tweets: [
            { text: "This is the first tweet ever!" },
            { text: "This is the second tweet ever!" },
            { text: "I'm getting kind of bored..." },
        ] },
        { handle: "dgraphlover", name: "I LOVE DGRAPH", tweets: [
            { text: "DGRAPH IS GREAT!" },
            { text: "DID I EVER TELL YOU GUYS HOW MUCH I LIKE DGRAPH!" },
        ] },
        { handle: "cooltweeter", name: "Follow for cool tweets", tweets: [
            { text: "Anyone have any cool feeds I can follow?" },
        ] }
    ]) {
        users {
            handle
        }
    }
}

Note that every mutation query must start with mutation, as seen above.

In the above example, we call the addUser resolver on our server, and we are passing in a list of users to the create resolver, as the input parameter. We’re also passing a list of tweets for each user, and Dgraph is smart enough to create all the relationships between the tweets and users.

The second part of the mutation, user { id } is what we want to return from the query.

Now, let’s say firstuser wants to update his name, as he wants to leave his old life behind. Let’s create another query to update their name.

mutation {
    updateUser(
        filter: { handle: { eq: "firstuser" }}, 
        set: { name: "Not First User" }}
    ) {
        user {
            handle
        }
    } 
}

Now we’ve updated the user’s name. Deleting is handled similar to update, but it doesn’t take a ‘set’ parameter.

Queries

We now have some data into our database, so let’s query the data. We’ve actually covered a lot of the basics of querying when updating data in the previous section. First, let’s do a simple query to pull all users.

{
    queryUsers {
        handle
        name
        tweets {
            id
            text
        }
    }
}

Run this query, and you will get a list of users stored in the database, as well as a list of their tweets. By omitting the (filter: ...) parameter, we are asking Dgraph to return all users.

Filtering

Let’s delve a bit deeper into filtering. In the last section, we used some simple filters to update a user.

One important thing to note is that the options available in the filter parameter depend on the @search directives that are defined on this type. For example, adding the @search(by: [fulltext]) directive to Tweet.text allows us to use anyoftext and alloftext filters when filtering on the Tweet.text field. A quick example is searching for all tweets that contain the words “tweet” or “ever”:

mutation {
    queryTweet(filter: { text: { anyoftext: "tweet ever" }} {
        text
        user
    }
}

Each index added to the @search directive unlocks new possibilities for filtering. For more information, take a look at the GraphQL query docs.

Nested filtering

So far, we’ve only been filtering on the top level. What if we want to filter on nested types? For example, we want to pull all users, and a list of their tweets that contain “tweet ever”. We would query as so:

{
    queryUser {
        handle
        name
        tweets(filter: { text: { alloftext: "tweet ever" }}) {
            text
        }
    }
}

As you can see, we can use the same filtering structure as before on nested objects.

Let’s make this query a bit more complex. What if we want to only see users that have at least one of these tweets? For that, we can use the @cascade directive.

{
    queryUser @cascade {
        handle
        name
        tweets(filter: { text: { alloftext: "tweet ever" }}) {
            text
        }
    }
}

Now, we will only get firstuser back, as he is the only one that fulfills our filter criteria.

Ordering

Ordering in GraphQL queries is extremely simple. Simply add an offset param to your query. The offset is provided with asc and desc fields, and then you pass in the field to order by. The example below, which orders tweets from newest to oldest, should be self explanatory:

{
    queryTweet(order: { desc: id }) {
        text
        user {
            handle
            name
        }
    }
}

Pagination

Pagination in GraphQL is also very simple. It’s actually as simple as adding first and offset params. offset is the number of records in the beginning we want to skip, and first is the number of records we want to return. For example, let’s say we’re on the second page of tweets, and each page has 50 tweets. We would query as such:

{
    queryTweet(first: 50, offset: 50) {
        text
        user {
            handle
            name
        }
    }
}

And with that, you should now have the skills to mutate and query to your heart’s content!

Further Reading

GraphQL Query documentation.

GraphQL Mutation documentation.

If you want to send queries and mutation from your frontend, take a look at Apollo client. Apollo client makes sending GraphQL queries easier, as well as including many cool features such as query caching.