Interacting with Github GraphQL API in Ruby

Bishnu Subedi
Devnetwork
Published in
3 min readSep 20, 2017
Source: https://pbs.twimg.com/profile_images/1978599420/electrocat.png

One fine evening, I wanted to collect profile pictures of some of my friends and I thought to crawl through their Github profile.
But at the same time, I thought it would be nice to have their bio and location as well. So, I decided to use Github API to fetch the information.

Github released the new GitHub GraphQL API couple of months ago, I thought to play around with GraphQL API rather than Github’s REST API.
Github has also released a ruby client gem graphql-client to interact with GraphQL APIs. So I quickly setup a working directory for ruby script and initialized with bundler for gem management.

For Github API access, I also needed to have personal access token

Playing with code

Once I had these in place,

I created a Github module like this;

module Github
GITHUB_ACCESS_TOKEN = ENV['GITHUB_ACCESS_TOKEN']
URL = 'https://api.github.com/graphql'
HttpAdapter = GraphQL::Client::HTTP.new(URL) do
def headers(context)
{
"Authorization" => "Bearer #{GITHUB_ACCESS_TOKEN}",
"User-Agent" => 'Ruby'
}
end
end
Schema = GraphQL::Client.load_schema(HttpAdapter)
Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
end

This module, using my personal token, fetches the Github API Schema and then initializes the Clientinstance ready to execute the query.

Now, it’s time to setup my User class which will actually fetch the user detail by Github username.

module Github
class User
UserProfileQuery = Github::Client.parse <<-'GRAPHQL'
query($username: String!) {
user(login: $username) {
id
login
name
avatarUrl
bio
bioHTML
location
}
}
GRAPHQL
def self.find(username)
response = Github::Client.query(UserProfileQuery, variables: { username: username })
if response.errors.any?
raise QueryExecutionError.new(response.errors[:data].join(", "))
else
response.data.user
end
end
end
end

Query

UserProfileQuery = Github::Client.parse <<-'GRAPHQL'
query($username: String!) {
user(login: $username) {
id
login
name
avatarUrl
bio
bioHTML
location
}
}
GRAPHQL

Remember, this section is very important and query has to be assigned to Ruby constant likeUserProfileQuery. Otherwise it raises an exception.

Exception

expected definition to be assigned to a static constant https://git.io/vXXSE

Query Parameters

Whenever is a need to pass parameter in query there is a neat way to pass that via variables. But you have to prepare query with the variable in place. In this example, query($username: String!) declares variable usage and it type. Query is strictly typed so you have to respect the types. Github provides an interactive app to play with GraphQL queries.

response = Github::Client.query(UserProfileQuery, variables: { username: username })

Handling Query Exception

With this in place, it raises error in case the query execution goes wrong which will give us better control in code flow.

class QueryExecutionError < StandardError; endraise QueryExecutionError.new(response.errors[:data].join(", "))

Putting it all together, I had a very nice and simple way to fetch user detail from Github with username like this:

Outcome

user = Github::User.find('username')#< id="DMX6ABClpqr0NVW" login="username" name="Name" avatarUrl="https://avatars3.githubusercontent.com/u/74042?v=4" bio=nil bioHTML="" location="">

One thing to take note of here is that graphql-client library does a weird thing here. You need to access the attributes in under_score format and not in the camelCase as displayed in the instance.

user.avatar_url https://avatars3.githubusercontent.com/u/74042?v=4

In summary

Be prepared to spend good amount of time to get familiar with GraphQL and its queries, once you are comfortable it gives everything you need from single API endpoint. So get started and play with GraphQL APIs.

Bonus

graphql-client ruby library can be used to interact with any GraphQL API so enjoy playing with them.

--

--

Bishnu Subedi
Devnetwork

Technical solution and continuously seeking improvement on development process is great motivation for me. I love to play with code and solving problems.