Sending graphql queries using http.Client in Go

by Kyriakos Chatzidimitriou | Oct 15, 2019 05:30 | tutorials

gogolanggraphqljsonmarshalencodegithub v4

Background: I wanted to test quickly, different, complex GraphQL queries to the GitHub v4 API especially wrt to error messages produced. At the same time I didn't want to create complex Go types to match the GitHub schema using a library like shurcooL/githubv4, it seemed like a lot of hassle for my purpose, especially since I didn't want to decode the response and use it.

Prerequisites: Create a personal access token with the scopes related to the queries you want to do and put it in the environmental variable GITHUB_TOKEN.

According to the GitHub documentation on forming calls:

The string value of "query" must escape newline characters or the schema will not parse it correctly. For the POST body, use outer double quotes and escaped inner double quotes.

So in order not to do the encoding myself, I will use the go json library to take care of the json encoding/marshaling.

In addition one must take care of putting extra braces like explained in this StackOverflow answer.

So let's start by creating an OAuth2 client since you cannot have non-authenticated queries to the v4 API:

client := oauth2.NewClient(
        context.TODO(),
        oauth2.StaticTokenSource(
            &oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
        ))

then a query:

    query := `query {
            repository(owner:"octocat", name:"Hello-World") {
              issues(last:20, states:CLOSED) {
                edges {
                  node {
                    title
                    url
                    labels(first:5) {
                      edges {
                        node {
                          name
                        }
                      }
                    }
                  }
                }
              }
            }
          }`

then marshal (or encode) the basic struct into JSON:

gqlMarshalled, err := json.Marshal(graphQLRequest{Query: query})

and finally POST:

resp, err := client.Post("https://api.github.com/graphql", "application/json", strings.NewReader(string(gqlMarshalled)))

and dump the response:

b, _ := httputil.DumpResponse(resp, true)
fmt.Println(string(b))

The complete gist that includes a query with variables can be found below:

package main
import (
"context"
"encoding/json"
"fmt"
"net/http/httputil"
"os"
"strings"
"golang.org/x/oauth2"
)
type graphQLRequest struct {
Query string `json:"query"`
Variables string `json:"variables"`
}
func main() {
client := oauth2.NewClient(
context.TODO(),
oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
))
query := `query {
repository(owner:"octocat", name:"Hello-World") {
issues(last:20, states:CLOSED) {
edges {
node {
title
url
labels(first:5) {
edges {
node {
name
}
}
}
}
}
}
}
}`
gqlMarshalled, err := json.Marshal(graphQLRequest{Query: query})
if err != nil {
panic(err)
}
resp, err := client.Post("https://api.github.com/graphql", "application/json", strings.NewReader(string(gqlMarshalled)))
if err != nil {
panic(err)
}
b, _ := httputil.DumpResponse(resp, true)
fmt.Println(string(b))
query = `query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}`
variables := `variables {
"number_of_repos": 3
}`
gqlMarshalled, err = json.Marshal(graphQLRequest{Query: query, Variables: variables})
if err != nil {
panic(err)
}
b, _ = httputil.DumpResponse(resp, true)
fmt.Println(string(b))
}

Execute it with:

GITHUB_TOKEN=<your token> go run graphqlclient.go

PreviousNext

Comments