Hi, I am Nicolas

I'm a software engineer who fell in love with UI and UX design. After years of freelancing, I am currently working for PSPDFKit and build industry leading frameworks.

← Back to see all posts

Test your GraphQL API in Elixir

I recently started developing a new Phoenix application that uses GraphQL. We decided to use the Absinthe GraphQL Library and it was the right decision so far. The maintainers are super nice and actively help with problems in the Elixir Slack channel. If you haven’t used GraphQL and want to learn about it, I can recommend you to go through How to GraphQL and I promise you, you will never want to go back and build a REST API again!

How a GraphQL Query looks like

GraphQL APIs work by sending a POST HTTP requests to the GraphQL endpoint (e.g. /api/graphql) with a query and a variables as parameter. As a response, you get an HTTP Success Status with a data or an error JSON Object. This, of course, is abstracted away by the GraphQL client libraries like Apollo or Relay. However, when you want to test your API, it becomes important to know how you form such a request. Normally, when testing APIs, you have controllers that are bounded to certain routes, with GraphQL you only have one single endpoint - so I asked myself what’s the best approach to test this?

Building GraphQL Queries

We assume, to have the following GraphQL User Type:

1
2
3
4
5
# Type definition of a User
type User {
  id: ID!
  name: String!
}

And our queries and mutations are the following:

1
2
3
4
5
6
7
8
9
# Query to get all users
type Query {
  users: [User!]!
}

# Mutation to update a user's name
type Mutation {
  updateUserName(id: ID!, name: String!): User!
}

As we already know, the HTTP request of a GraphQL query is relatively easy to build. For our users query, we don’t need any variables, so we can just add a query attribute to our payload.

1
2
3
4
5
6
7
8
9
10
11
test "returns all users" do
  build_conn()
  |> post("api/graphql", %{
    "query" => """
      users {
        id
        name
      }
    """
  })
end

However, repeating this every time would be annoying and I wanted to have a much nicer API.

Create a GraphQL test helper

Because most of the time I just want to create a GraphQL query and immediately send it, my idea for the API looked like this:

1
build_conn() |> graphql_query(query: @query) # => Returns result

So I built a GraphQLHelper to do so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# test/support/graphql_helper.ex
defmodule MyApp.GraphqlHelper do
  use Phoenix.ConnTest
  # We need to set the default endpoint for ConnTest
  @endpoint MyApp.Web.Endpoint

  def graphql_query(conn, options) do
    conn
    |> post("/api/graphql", build_query(options[:query], options[:variables]))
    |> json_response(200)
  end

  defp build_query(query, variables) do
    %{
      "query" => query,
      "variables" => variables
    }
  end
end

To make this helper accessible per default in your tests you need to import it in ConnCase.

1
2
3
4
5
6
7
# test/support/conn_case.ex
defmodule MyApp.DataCase
  # ...
  using do
    # ...
    import MyApp.GraphqlHelper
  end

Authentication

The request alone wouldn’t work, we also need to add authentication. Because we use a token-based authentication in our API I also added a small AuthenticationHelper that creates a new user session and adds the token to the HTTP Header.

1
2
3
4
5
6
7
defmodule MyApp.AuthenticationHelper do
  def authenticate_user(conn, user) do
    token = MyApp.Accounts.create_user_session(user).token
    conn
    |> Plug.Conn.put_req_header("authorization", "Session #{token}")
  end
end

We also import this helper in our ConnCase and now have an easy way to test our GraphQL API.

The result

With all those helpers, we now can easily test our GraphQL API. Here is an example how to update the name of a user. This is a mutation that requires the user ID and his new name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
defmodule MyApp.UserResolverTest do
  use DocFlow.Web.ConnCase

  setup do
    user = Fixtures.create(:user, name: "Jon Snow")
    {:ok,  user}
  end

  @query """
  mutation UpdateUserName($id: ID!, $name: String!) {
    updateUserName(id: $id, name: $name) {
      name
    }
  }
  """

  test "Updates the name of the bastard", %{user: user} do
    response = conn
    |> authenticate_user(user)
    |> graphql_query(
      query: @query,
      variables: %{
        id: user.id,
        name: "Aegon Tagaryen",
      }
    )

    assert response["data"]["updateUserName"]["name"] == "Aegon Targaryen"
  end
end

I hope this helps you when you want to test your GraphQL API. If you have any better ideas or improvements, please ping me 🙂.