# An example to get the remaining rate limit using the Github GraphQL API. | |
import requests | |
headers = {"Authorization": "Bearer YOUR API KEY"} | |
def run_query(query): # A simple function to use requests.post to make the API call. Note the json= section. | |
request = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers) | |
if request.status_code == 200: | |
return request.json() | |
else: | |
raise Exception("Query failed to run by returning code of {}. {}".format(request.status_code, query)) | |
# The GraphQL query (with a few aditional bits included) itself defined as a multi-line string. | |
query = """ | |
{ | |
viewer { | |
login | |
} | |
rateLimit { | |
limit | |
cost | |
remaining | |
resetAt | |
} | |
} | |
""" | |
result = run_query(query) # Execute the query | |
remaining_rate_limit = result["data"]["rateLimit"]["remaining"] # Drill down the dictionary | |
print("Remaining rate limit - {}".format(remaining_rate_limit)) |
This comment has been minimized.
This comment has been minimized.
If you're using a Personal Access Token (PAT), you need to put the word "token" or "bearer" before the actual token: |
This comment has been minimized.
This comment has been minimized.
Very helpful demonstration |
This comment has been minimized.
This comment has been minimized.
Great demo! I only had to tweak the url which, for GitHub Enterprise, seems to have a slightly different scheme: e.g. |
This comment has been minimized.
This comment has been minimized.
Very helpful! Thank you! |
This comment has been minimized.
This comment has been minimized.
Thanks! :D |
This comment has been minimized.
This comment has been minimized.
If you get a 401 code, do what @YakDriver says |
This comment has been minimized.
This comment has been minimized.
Thanks! |
This comment has been minimized.
This comment has been minimized.
Thanks! |
This comment has been minimized.
This comment has been minimized.
we can also do a get request right with python request's module r = requests.get() |
This comment has been minimized.
This comment has been minimized.
i thought there are no status codes returned from GraphQL server other than 200. You may need to inspect the result to contain error field. |
This comment has been minimized.
This comment has been minimized.
How to pass variables? |
This comment has been minimized.
This comment has been minimized.
Same question here. Do you know how to pass variables? |
This comment has been minimized.
This comment has been minimized.
To pass variables---here queryString and maxItems---you can use format, e.g.
|
This comment has been minimized.
This comment has been minimized.
This unfortunately gives me a Any idea why? |
This comment has been minimized.
This comment has been minimized.
Because, you don't need to format the string .. you can pass both query and variables as separate keys in the json and the graphql endpoint can figure out what goes were |
This comment has been minimized.
This comment has been minimized.
For anyone trying to pass variables for these queries, I suggest looking at string.Template in python:
|
This comment has been minimized.
This comment has been minimized.
To pass in variables to the query you need to:
my python is a bit rusty but this works
don't forget to declare the variables in the query itself. |
This comment has been minimized.
This comment has been minimized.
Thankkk youu!!!!!!!!!!!!!! You saved me:) |
This comment has been minimized.
This comment has been minimized.
Here is an example using generators to overcome GitHub's a limit of 100 items/request. from requests import exceptions, request
class GitHubQuery:
BASE_URL = "https://api.github.com/graphql"
ORGANIZATION = "org_name"
def __init__(
self,
github_token=None,
query=None,
query_params=None,
additional_headers=None
):
self.github_token = github_token
self.query = query
self.query_params = query_params
self.additional_headers = additional_headers or dict()
@property
def headers(self):
default_headers = dict(
Authorization=f"token {self.github_token}",
)
return {
**default_headers,
**self.additional_headers
}
def generator(self):
while(True):
try:
yield request(
'post',
GitHubQuery.BASE_URL,
headers=self.headers,
json=dict(query=self.query.format_map(self.query_params))
).json()
except exceptions.HTTPError as http_err:
raise http_err
except Exception as err:
raise err
def iterator(self):
pass import GitHubQuery
class VulnurabilityReport(GitHubQuery):
VULNERABILITY_QUERY = """
{{
organization(login: "org_name") {{
repositories(first: 100, after: {after}) {{
pageInfo{{
hasNextPage
endCursor
}}
totalCount
nodes {{
... on Repository {{
id
name
vulnerabilityAlerts(first: 2) {{
totalCount
nodes {{
id
}}
}}
}}
}}
}}
}}
}}
"""
QUERY_PARAMS = dict(after='')
ADDITIONAL_HEADERS = dict(
Accept="application/vnd.github.vixen-preview+json",
)
def __init__(self, github_token):
super().__init__(
github_token=github_token,
query=VulnurabilityReport.VULNERABILITY_QUERY,
query_params=VulnurabilityReport.QUERY_PARAMS,
additional_headers=VulnurabilityReport.ADDITIONAL_HEADERS
)
def iterator(self):
generator = self.generator()
hasNextPage = True
repos_vulnerabilities = []
while(hasNextPage):
response = next(generator)
endCursor = response["data"]["organization"]["repositories"]["pageInfo"]["endCursor"]
self.query_params = dict(after=endCursor)
repos_vulnerabilities.extend(response["data"]["organization"]["repositories"]["nodes"])
hasNextPage = response["data"]["organization"]["repositories"]["pageInfo"]["hasNextPage"]
return (repos_vulnerabilities) |
This comment has been minimized.
This comment has been minimized.
I just noticed @tatmush use of variables. I used python's format_map, but variables keep the query string simpler. |
This comment has been minimized.
This comment has been minimized.
Hi, same in Python2 (here to check which users as enabled Single Sign-On on an Organization) class GitHubGraphQLQuery(object):
BASE_URL = "https://api.github.com/graphql"
def __init__(self, token, query, variables=None, additional_headers=None):
self._token = token
self._query = query
self._variables = variables or dict()
self._additional_headers = additional_headers or dict()
@property
def headers(self):
default_headers = dict(Authorization="token {}".format(self._token))
return dict(default_headers.items() + self._additional_headers.items())
def generator(self):
while True:
try:
yield requests.request(
"post",
GitHubGraphQLQuery.BASE_URL,
headers=self.headers,
json={"query": self._query, "variables": self._variables},
).json()
except requests.exceptions.HTTPError as http_err:
raise http_err
except Exception as err:
raise err
def iterator(self):
pass
class GithubSAMLIdentityProvider(GitHubGraphQLQuery):
QUERY = """
query($org: String!, $after: String) {
organization(login: $org) {
samlIdentityProvider {
ssoUrl,
externalIdentities(first: 100, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
guid,
samlIdentity {
nameId
}
user {
login
}
}
}
}
}
}
}
"""
ADDITIONAL_HEADERS = dict(Accept="application/vnd.github.vixen-preview+json")
def __init__(self, organization_name, token):
super(GithubSAMLIdentityProvider, self).__init__(
token=token,
query=GithubSAMLIdentityProvider.QUERY,
variables=dict(org=organization_name, after=None),
additional_headers=GithubSAMLIdentityProvider.ADDITIONAL_HEADERS,
)
self._identities = list()
def iterator(self):
generator = self.generator()
hasNextPage = True
saml_identities = list()
while hasNextPage:
response = next(generator)
endCursor = response["data"]["organization"]["samlIdentityProvider"]["externalIdentities"]["pageInfo"]["endCursor"]
self._variables["after"] = endCursor
saml_identities.extend(
response["data"]["organization"]["samlIdentityProvider"]["externalIdentities"]["edges"]
)
hasNextPage = response["data"]["organization"]["samlIdentityProvider"]["externalIdentities"]["pageInfo"]["hasNextPage"]
return saml_identities |
This comment has been minimized.
This comment has been minimized.
Does anyone if it's possible to define variables inside fragments (see example below)?
|
This comment has been minimized.
This comment has been minimized.
Saved me hours of frustration.... Thank you! |
This comment has been minimized.
This comment has been minimized.
Thanks, exactly what I needed! |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
Thank you! |
This comment has been minimized.
This comment has been minimized.
Awesome, thanks! |
This comment has been minimized.
This comment has been minimized.
Thanks! |
This comment has been minimized.
This comment has been minimized.
Hey, thanks for this post. Can we enable auto completion or graphiql like features while making these kinds of requests from notebook? |
This comment has been minimized.
This comment has been minimized.
Mutations are the same. May I mention that the part where it says |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
This is just what I needed - thanks! |
This comment has been minimized.
This comment has been minimized.
so cool, exactly what I need, thank you! |
This comment has been minimized.
This comment has been minimized.
Easy to read, flexible and still works in 2021, thanks for this!!!! |
This comment has been minimized.
Very helpful, thank you!