Quantcast
Channel: Active questions tagged python - Stack Overflow
Viewing all articles
Browse latest Browse all 13921

How to send and receive queries with a custom gql transport

$
0
0

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?


Viewing all articles
Browse latest Browse all 13921

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>