Example usage
To use ghgql
in a project:
I’ve designed ghgql
to work on query files rather than pure query strings. This is fully intentional to not get into the habit of putting query strings all around in the code. Instead when the queries live in files we can validate them agains Github’s GraphQL schema.
Long story short, instead of using ghgql.GithubGraphQL.query()
you should use ghgql.GithubGraphQL.query_from_file()
!
Running our first query
Suppose we have the following query to fetch the last three issues kwk/ghgql
repository:
query = """
query ($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
issues(last: 3) {
edges {
node {
title
state
author {
login
}
}
}
totalCount
}
}
}
"""
This is how we can use it with ghgql
:
import os
import ghgql
with ghgql.GithubGraphQL(token=os.getenv("GITHUB_TOKEN")) as ghapi:
result = ghapi.query(query=query, variables={"owner": "kwk", "repo": "ghgql"})
Easy inspection of results
from pprint import pprint
pprint(result)
{'data': {'repository': {'issues': {'edges': [{'node': {'author': {'login': 'tru'},
'state': 'CLOSED',
'title': 'Token not '
'set to the '
'session if '
'not used as '
'a '
'contextmanager'}},
{'node': {'author': {'login': 'tru'},
'state': 'CLOSED',
'title': 'Let '
'result.get() '
'return a '
'Result or '
'provide some '
'other way to '
'use the '
'get() '
'function on '
'sub dicts.'}},
{'node': {'author': {'login': 'kwk'},
'state': 'CLOSED',
'title': 'no local '
'precedence '
'for '
'raise_on_error'}}],
'totalCount': 5}}}}
Notice that result is a dictionary with a top-level "data"
key. This indicates that there are no errors. if there were errors, we would see a top-level errors
element.
Convenient access
The ghgql
library advocates the use of the fnc
library to query nested results. Let’s import fnc
really quick. For your convenience we’ve made fnc
a dependency of ghgql
.
import fnc
Let’s say we want to query for the states of all issues.
issues = fnc.get("data.repository.issues.edges", result)
states = fnc.map("node.state", issues)
pprint(list(states))
['CLOSED', 'CLOSED', 'CLOSED']
Handle errors
God forbid, but there might be errors when you’re writing a GraphQL query. Let’s query github with a completely invalid query and inspect the results:
query="Yes, I'm invalid!"
with ghgql.GithubGraphQL(token=os.getenv("GITHUB_TOKEN")) as ghapi:
result = ghapi.query(query=query, variables={"searchQuery": "llvm/llvm-project"})
pprint(result)
{'errors': [{'locations': [{'column': 1, 'line': 1}],
'message': 'Parse error on "Yes" (IDENTIFIER) at [1, 1]'}]}
Notice that ther no longer is a data
key on the top-level of the result
dictionary. It is your responsibility to query for the errors and then handle it as you like.
if fnc.has("errors", result):
print("ERROR: {}".format(RuntimeError(fnc.get("errors[0]", result))))
ERROR: {'message': 'Parse error on "Yes" (IDENTIFIER) at [1, 1]', 'locations': [{'line': 1, 'column': 1}]}
I you prefer getting an exception, you can tell ghgql
to throw one in case of an error. There are two options:
When constructing the GithubGraphQL object so that all failing queries throw and exception.
Per query
# One for all
query="Yes, I'm invalid!"
with ghgql.GithubGraphQL(token=os.getenv("GITHUB_TOKEN"), raise_on_error=True) as ghapi:
try:
result = ghapi.query(query=query, variables={"searchQuery": "llvm/llvm-project"})
except RuntimeError as ex:
print(f"Caught exception: {str(ex)}")
Caught exception: Parse error on "Yes" (IDENTIFIER) at [1, 1]
# Per query
query="Yes, I'm invalid!"
with ghgql.GithubGraphQL(token=os.getenv("GITHUB_TOKEN")) as ghapi:
try:
result = ghapi.query(query=query, variables={"searchQuery": "llvm/llvm-project"}, raise_on_error=True)
except RuntimeError as ex:
print(f"Caught exception: {str(ex)}")
Caught exception: Parse error on "Yes" (IDENTIFIER) at [1, 1]
Conclusion
ghgql
provides ways to query the Github GraphQL and allows for easy inspection of the resulting objects with the help of fnc
.
TODO(kwk): In the future we can show how mutations work with ghgql
.