My question is closely related to the following topic. The difference is that I want to send and receive queries instead of subscribing.
Basically, I want to send the following:
GET /?hash=3510361693 HTTP/2Host: btec-http.services.imgarena.comSec-Ch-Ua: "Chromium";v="109", "Not_A Brand";v="99"X-Request-From: 5.1.108Gql-Op-Name: GetGolfTournamentInfoSec-Ch-Ua-Mobile: ?0X-Amzn-Trace-Id: X-Request-Id=8c078936-394b-4c51-8827-0b8c06d4d04f;X-Request-From=5.1.108User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36Operator: europeantourSport: GOLFEc-Version: 5.1.108Event-Id: 857X-Request-Id: 8c078936-394b-4c51-8827-0b8c06d4d04fSec-Ch-Ua-Platform: "macOS"Accept: */*Origin: https://europeantour.apps.imgarena.comSec-Fetch-Site: same-siteSec-Fetch-Mode: corsSec-Fetch-Dest: emptyReferer: https://europeantour.apps.imgarena.com/Accept-Encoding: gzip, deflateAccept-Language: en-GB,en-US;q=0.9,en;q=0.8
Based on the answer of @leszek.hanusz I write the following modified aiohttp.AIOHTTPTransport
class
import jsonimport loggingimport asynciofrom aiohttp import ClientResponse, ClientResponseErrorfrom typing import Any, AsyncGenerator, Dict, Optional, Tuplefrom graphql import DocumentNode, ExecutionResult, print_astfrom gql import Client, gqlfrom gql.transport.exceptions import TransportProtocolError, TransportServerErrorfrom gql.transport.aiohttp import AIOHTTPTransportlogging.basicConfig(level=logging.INFO)class CustomAIOHTTPTransport(AIOHTTPTransport): def _hash(self, e): t = 5381 r = len(e) while r: r -= 1 t = t * 33 ^ ord(e[r]) return t & 0xFFFFFFFF def _calc_id(self, operation_name, variables): obj = {"operationName": operation_name,"variables": variables, } obj_stringified = json.dumps( obj, separators=(",", ":"), sort_keys=True, ) hashed_value = self._hash(obj_stringified) return hashed_value async def execute( self, document: DocumentNode, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, ) -> ExecutionResult: # Calculate the id by hashing the subscription name and the variables query_id = self._calc_id(operation_name, variable_values) # Creating the payload for the full subscription payload: Dict[str, Any] = {"query": print_ast(document)} if variable_values: payload["variables"] = variable_values if operation_name: payload["operationName"] = operation_name args = {"json": payload,"headers": self.headers } async with self.session.get(f'{self.url}?hash={query_id}', **args) as r: # saving latest response headers in the transport self.response_headers = r.headers async def raise_response_error(resp: ClientResponse, reason: str): # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases try: # Raise a ClientResponseError if response status is 400 or higher resp.raise_for_status() except ClientResponseError as e: raise TransportServerError(str(e), e.status) from e result_text = await resp.text() raise TransportProtocolError( f"Server did not return a GraphQL result: " f"{reason}: " f"{result_text}" ) try: result = await r.json() except Exception: await raise_response_error(r, "Not a JSON answer") if result is None: await raise_response_error(r, "Not a JSON answer") if "errors" not in result and "data" not in result: await raise_response_error(resp, 'No "data" or "errors" keys in answer') return ExecutionResult( errors=result.get("errors"), data=result.get("data"), extensions=result.get("extensions"), )
I believe that I need to rewrite aiohttp.AIOHTTPTransport.execute
because according to the docs it performs a HTTP POST request. In addition, we need to include the hash into the endpoint.
I run the code using
async def main(): transport = CustomAIOHTTPTransport( url=f"https://btec-http.services.imgarena.com", headers={"accept-language": "en","ec-version": "5.1.88","operator": "europeantour","referrer": "https://www.europeantour.com/","sport": "GOLF" } ) async with Client( transport=transport, fetch_schema_from_transport=False ) as session: query = gql("""query GetGolfTournament($input: GetGolfTournamentInput!) { getGolfTournament(input: $input) { id format tour name startDate endDate year }}""" ) variables = {"input": {"tournamentId": 857, }, } result = await session.execute( query, operation_name="GetGolfTournamentInfo", variable_values=variables ) print(result)asyncio.run(main())
When I run this I get a 204
-error; 'No Content'. What am I doing wrong?