How to Connect to a GraphQL API

How to use an existing GraphQL API as a data source for your project

StepZen provides different custom directives for connecting to various kinds of data sources such as the @dbquery directive for connecting to databases and the @rest directive for connecting to REST endpoints. StepZen also provides an @graphql directive for connecting to GraphQL APIs.

Connecting to Public APIs

In this example see how to connect to the public Rick and Morty GraphQL API with the @graphql directive. Later we will see how to connect to an API that requires authorization.

Create project structure

Our project is called rick-and-morty and has a single directory called schema for our types.

mkdir -p rick-and-morty/schema
cd rick-and-morty

Create an index.graphql file

The index.graphql file tells StepZen how to assemble the various type definition files into a complete GraphQL schema.

touch index.graphql

Our example only has a single file for now called characters.graphql.

schema
  @sdl(
    files: [
      "schema/characters.graphql"
    ]
  ) {
  query: Query
}

Create a characters.graphql file

Create a file for our Character object called characters.graphql.

touch schema/characters.graphql

The Character object has three types:

  • id with the type ID
  • name for the character's name with the type String
  • image of the character with the type String. The image is a URL to a .jpeg file contained within the string.
type Character {
  id: ID
  name: String
  image: String
}

To match the Rick and Morty API schema, return a results array containing the Character objects and call the type Characters.

type Characters {
  results: [Character]
}

Our Query type has a characters query that returns the Characters as specified in our previous types. The @graphql directive takes the endpoint of the GraphQL API, which in this case is https://rickandmortyapi.com/graphql with the URL placed in between quotation marks.

type Query {
  characters: Characters
    @graphql(
      endpoint: "https://rickandmortyapi.com/graphql"
    )
}

Run CHARACTERS_QUERY test query

To test our new endpoint, run the following query called CHARACTERS_QUERY. This executes the characters query and returns an array of Character objects with their id, name, and image.

query CHARACTERS_QUERY {
  characters {
    results {
      id
      name
      image
    }
  }
}

This returns a data object containing the id, name, and image of the characters contained within a results array.

{
  "data": {
    "characters": {
      "results": [
        {
          "id": "1",
          "image": "https://rickandmortyapi.com/api/character/avatar/1.jpeg",
          "name": "Rick Sanchez"
        },
        {
          "id": "2",
          "image": "https://rickandmortyapi.com/api/character/avatar/2.jpeg",
          "name": "Morty Smith"
        }
      ]
    }
  }
}

Connecting to Authenticated APIs

Let's try a slightly more complex example now. The Rick and Morty API is public, meaning that it does not require an API token to access. What if we wanted to use a headless CMS with the @graphql directive?

If you want to follow along with your own example, you can see how to authentication with the Storyblok GraphQL API at the following link.

Create a config.yaml file

Much like the @rest directive, pass our query a configuration contained in a config.yaml file.

touch config.yaml

Our config.yaml file contains our token provided by Storyblok. Give it a name called storyblok_config and a token provided by Storyblok and use it in place of xxxx in the example below.

configurationset:
  - configuration:
      name: storyblok_config
      token: xxxx

Create a storyblok.graphql file

The storyblok.graphql file has our content types and queries.

touch schema/storyblok.graphql

Define a PostItem type with a name of type String, and PostItems type returning the items in an array of PostItem objects.

type PostItem {
  name: String
}

type PostItems {
  items: [PostItem]
}

Our Query type has a postItems query that returns the PostItems as specified in our previous types. The @graphql directive takes:

  • The endpoint of the GraphQL API, which in this case is https://gapi.storyblok.com/v1/api with the URL placed in between quotation marks.
  • The configuration, which is named storyblok_config contained in quotation marks
  • The headers, which is an object containing the name and value of the headers.
type Query {
  postItems: PostItems
    @graphql(
      endpoint: "https://gapi.storyblok.com/v1/api"
      headers: [
        { name:"Token" value:"$token" }
      ]
      configuration: "storyblok_config"
    )
}

Add schema/storyblok.graphql to your index.graphql file inside the files array.

schema
  @sdl(
    files: [
      "schema/characters.graphql"
      "schema/storyblok.graphql"
    ]
  ) {
  query: Query
}

Run POSTS_QUERY test query

To test our new endpoint, run the following query called POSTS_QUERY. This executes the PostItems query and return an array of PostItem objects with their name.

query POSTS_QUERY {
  PostItems {
    items {
      name
    }
  }
}

This returns a data object containing the name of the PostItems contained within an items array.

{
  "data": {
    "PostItems": {
      "items": [
        {
          "name": "my-super-awesome-post"
        }
      ]
    }
  }
}

What else can I do with the @graphql directive?

The @graphql directive provides a variety of extra functionality not explored in this simple example.

Mutations

So far we have only seen how to run queries. But you can also use the @graphql directive with mutations as well. You can find examples for how to use mutations in the GraphQL Mutation Basics section.

Fragments

Let's say we have a relatively complicated page in our app that looks at two characters side by side, along with their friends. For more complicated queries, GraphQL includes reusable units called fragments.

Fragments let you construct sets of fields to include in your queries. This is useful for queries where you need to repeat the fields. The GraphQL docs include the following example:

{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}

This results in the following output:

{
  "data": {
    "leftComparison": {
      "name": "Luke Skywalker",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ],
      "friends": [
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        },
        {
          "name": "C-3PO"
        },
        {
          "name": "R2-D2"
        }
      ]
    },
    "rightComparison": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ],
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

Prefixes

As your project grows you may end up connecting to multiple APIs with name collisions for the types and queries. If you have multiple characters query, you may want to specifcy that you want the characters from the Rick and Morty API and not the Star Wars API, for example.

In this example we append the prefix value rick_ to the types and queries. Instead of Character, write rick_Character, and so on.

type rick_Character {
  id: ID
  name: String
  image: String
}

type rick_Characters {
  results: [rick_Character]
}

Append a prefix by including an object containing a value with that prefix.

type Query {
  rick_characters: rick_Characters
    @graphql(
      endpoint: "https://rickandmortyapi.com/graphql"
      prefix: { value: "rick_", includeRootOperations: true }
    )
}

This site uses cookies: By using this website, you consent to our use of cookies in accordance with our Website Terms of Use and Cookie Policy.