Interacting with Github GraphQL API in Ruby
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 Client
instance 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.