Accessing the result of GraphQL queries with variables in Python

You might already be familiar with how responses can be generated from the Bitquery GraphQL API using python. The article for the same is under BITQUERY BLOG in our website as follows: Bitquery - How to use GraphQL with Python, Javascript, and Ruby

The python code below is what has been shown in the Blog. Notice, that the below query is successfully able to send a POST request to the Bitquery GraphQL API and is able to fetch the appropriate response.

import requests


def run_query(query):  # A simple function to use requests. post to make the API call.
    headers = {'X-API-KEY': 'YOUR API KEY'}
    request = requests.post('https://graphql.bitquery.io/',
                            json={'query': query}, headers=headers)
    if request.status_code == 200:
        return request.json()
    else:
        raise Exception('Query failed and return code is {}.      {}'.format(request.status_code,
                        query))


# The GraphQL query

query = """
query{
  bitcoin{
    blocks{
      count
    }
   }
}
"""
result = run_query(query)  # Execute the query
print 'Result - {}'.format(result)

The GraphQL query in the above code seems to have no variables in it. But what if we use variables while making the same POST request to the API. Let us take an example of a query with variables.

GraphQL Query

query ($network: EthereumNetwork!, $address: String!, $limit: Int!, $offset: Int!, $from: ISO8601DateTime, $till: ISO8601DateTime) {
  ethereum(network: $network) {
    smartContractCalls(
      options: {desc: "block.timestamp.time", limit: $limit, offset: $offset}
      date: {since: $from, till: $till}
      smartContractAddress: {is: $address}
    ) {
      block {
        timestamp {
          time(format: "%Y-%m-%d %H:%M:%S")
        }
        height
      }
      smartContractMethod {
        name
        signatureHash
      }
      address: caller {
        address
        annotation
      }
      transaction {
        hash
      }
      gasValue
      external
    }
  }
}

Variables

{
  "limit": 10,
  "offset": 0,
  "network": "bsc_testnet",
  "address": "0x2d4ee064ebb491b1e6db6ea1962db59d1d0e0741",
  "from": null,
  "till": null,
  "dateFormat": "%Y-%m"
}

If you simply run this query in python, you would get an error like the one shown below.

Result - {'errors': [{'message': 'Variable $network of type EthereumNetwork! was provided invalid value', 'locations': [{'line': 2, 'column': 8}], 'extensions': {'value': None, 'problems': [{'path': [], 'explanation': 'Expected value to not be null'}]}}, {'message': 'Variable $address of type String! was provided invalid value', 'locations': [{'line': 2, 'column': 36}], 'extensions': {'value': None, 'problems': [{'path': [], 'explanation': 'Expected value to not be null'}]}}, {'message': 'Variable $limit of type Int! was provided invalid value', 'locations': [{'line': 2, 'column': 55}], 'extensions': {'value': None, 'problems': [{'path': [], 'explanation': 'Expected value to not be null'}]}}, {'message': 'Variable $offset of type Int! was provided invalid value', 'locations': [{'line': 2, 'column': 69}], 'extensions': {'value': None, 'problems': [{'path': [], 'explanation': 'Expected value to not be null'}]}}]}

Implementating variables in the GraphQL query

To ignore the above error, you can create a “variables” variable in the function on which the API call is taking place as shown below

 variables = {'limit': 10, 'offset': 0, 'network': 'bsc_testnet', 'address': '0x2d4ee064ebb491b1e6db6ea1962db59d1d0e0741', 'from': '2021-08-23', 'till': '2021-08-26', 'dateFormat': '%Y-%m'}

and then, add a “variables” parameter to the request.post( ) method as shown below.

request = requests.post('https://graphql.bitquery.io/', json={'query': query, 'variables': variables}, headers=headers)

Finally, the code must look like the one shown below

import requests

# The GraphQL query

query = """
query ($network: EthereumNetwork!, $address: String!, $limit: Int!, $offset: Int!, $from: ISO8601DateTime, $till: ISO8601DateTime) {
  ethereum(network: $network) {
    smartContractCalls(
      options: {desc: "block.timestamp.time", limit: $limit, offset: $offset}
      date: {since: $from, till: $till}
      smartContractAddress: {is: $address}
    ) {
      block {
        timestamp {
          time(format: "%Y-%m-%d %H:%M:%S")
        }
        height
      }
      smartContractMethod {
        name
        signatureHash
      }
      address: caller {
        address
        annotation
      }
      transaction {
        hash
      }
      gasValue
      external
    }
  }
}

"""

def run_query(query):  # A simple function to use requests.post to make the API call.
    headers = {'X-API-KEY': 'YOUR API KEY'}
    variables = {'limit': 10, 'offset': 0, 'network': 'bsc_testnet', 'address': '0x2d4ee064ebb491b1e6db6ea1962db59d1d0e0741', 'from': '2021-08-23', 'till': '2021-08-26', 'dateFormat': '%Y-%m'}
    request = requests.post('https://graphql.bitquery.io/', json={'query': query, 'variables': variables}, headers=headers)
    if request.status_code == 200:
        return request.json()
    else:
        raise Exception('Query failed and return code is {}.      {}'.format(request.status_code, query))

result = run_query(query)  # Execute the query
print ("Result - {}".format(result['data']))

NOTICE that in order to get the data, you need to pass the ‘data’ attribute to the result variable like this result['data']

If you face any issues regarding the same, feel free to comment below in the same thread.