From 8dfd261d4a9407ae6b7e6b1a052f04031966fe8f Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Sat, 20 Feb 2021 00:28:20 +0530 Subject: [PATCH 1/9] Fix 4xx error handling --- gql/transport/aiohttp.py | 34 +++++++++++++++++++--------------- gql/transport/exceptions.py | 4 ++++ gql/transport/requests.py | 32 +++++++++++++++++++++----------- tests/test_client.py | 5 ++++- 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index b1a33ad2..7bc33d8f 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -1,15 +1,16 @@ -import io -import json -import logging from ssl import SSLContext -from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Type, Union import aiohttp +import io +import json +import logging from aiohttp.client_exceptions import ClientResponseError from aiohttp.client_reqrep import Fingerprint from aiohttp.helpers import BasicAuth from aiohttp.typedefs import LooseCookies, LooseHeaders from graphql import DocumentNode, ExecutionResult, print_ast +from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Type, Union +from json.decoder import JSONDecodeError from ..utils import extract_files from .async_transport import AsyncTransport @@ -152,7 +153,8 @@ async def execute( # If we upload files, we will extract the files present in the # variable_values dict and replace them by null values nulled_variable_values, files = extract_files( - variables=variable_values, file_classes=self.file_classes, + variables=variable_values, + file_classes=self.file_classes, ) # Save the nulled variable values in the payload @@ -207,22 +209,24 @@ async def execute( async with self.session.post(self.url, ssl=self.ssl, **post_args) as resp: try: - result = await resp.json() + if resp.content_type == 'application/json': + result = await resp.json() - if log.isEnabledFor(logging.INFO): - result_text = await resp.text() - log.info("<<< %s", result_text) - except Exception: # 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 + if resp.content_type != 'application/json' or (result is not None and "errors" not in result): resp.raise_for_status() - except ClientResponseError as e: - raise TransportServerError(str(e)) from e + if log.isEnabledFor(logging.INFO): + result_text = await resp.text() + log.info("<<< %s", result_text) + except ClientResponseError as e: + # Check if the received response text is json pareable + # use the parsed text or str(e) as the exception message + + raise TransportServerError(str(e), e.status) from e + except Exception: result_text = await resp.text() raise TransportProtocolError( f"Server did not return a GraphQL result: {result_text}" diff --git a/gql/transport/exceptions.py b/gql/transport/exceptions.py index 4df2ec43..899d5d66 100644 --- a/gql/transport/exceptions.py +++ b/gql/transport/exceptions.py @@ -18,6 +18,10 @@ class TransportServerError(TransportError): This exception will close the transport connection. """ + def __init__(self, message=None, code=None): + super(TransportServerError, self).__init__(message) + self.code = code + class TransportQueryError(Exception): """The server returned an error for a specific query. diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 5eb2a36c..0ed888f1 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -1,12 +1,12 @@ import json import logging -from typing import Any, Dict, Optional, Union - import requests from graphql import DocumentNode, ExecutionResult, print_ast from requests.adapters import HTTPAdapter, Retry from requests.auth import AuthBase from requests.cookies import RequestsCookieJar +from typing import Any, Dict, Optional, Union +from json.decoder import JSONDecodeError from gql.transport import Transport @@ -151,21 +151,31 @@ def execute( # type: ignore self.method, self.url, **post_args # type: ignore ) try: - result = response.json() + type = response.headers.get('Content-Type', None) + if 'application/json' in type: + result = response.json() - if log.isEnabledFor(logging.INFO): - log.info("<<< %s", response.text) - except Exception: # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases - - try: - # Raise a requests.HTTPerror if response status is 400 or higher + # Raise a requests.HTTPerror if response status is 400 or higher + if 'application/json' not in type or (result is not None and "errors" not in result): response.raise_for_status() - except requests.HTTPError as e: - raise TransportServerError(str(e)) + if log.isEnabledFor(logging.INFO): + log.info("<<< %s", response.text) + except requests.HTTPError as e: + + # Check if the received response text is json pareable + # use the parsed text or str(e) as the exception message + try: + message = response.json() + return ExecutionResult(errors=message.get("errors"), data=message.get("data")) + except JSONDecodeError: + message = str(e) + + raise TransportServerError(message, e.response.status_code) from e + except Exception: raise TransportProtocolError("Server did not return a GraphQL result") if "errors" not in result and "data" not in result: diff --git a/tests/test_client.py b/tests/test_client.py index f2a7ecf8..c85d92b4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -7,6 +7,9 @@ from gql import Client, gql from gql.transport import Transport +from gql.transport.exceptions import ( + TransportQueryError, +) with suppress(ModuleNotFoundError): from urllib3.exceptions import NewConnectionError @@ -105,7 +108,7 @@ def test_execute_result_error(): """ ) - with pytest.raises(Exception) as exc_info: + with pytest.raises(TransportQueryError) as exc_info: client.execute(failing_query) assert 'Cannot query field "id" on type "Continent".' in str(exc_info.value) From 25347badbedbd5c52ce4224eaadd03d47f34805d Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Sat, 20 Feb 2021 01:03:17 +0530 Subject: [PATCH 2/9] Fix linting issues --- gql/transport/aiohttp.py | 7 ++++--- gql/transport/requests.py | 14 +++++++++----- tests/test_client.py | 21 +++++++++++---------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index 7bc33d8f..ebea306b 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -10,7 +10,6 @@ from aiohttp.typedefs import LooseCookies, LooseHeaders from graphql import DocumentNode, ExecutionResult, print_ast from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Type, Union -from json.decoder import JSONDecodeError from ..utils import extract_files from .async_transport import AsyncTransport @@ -209,12 +208,14 @@ async def execute( async with self.session.post(self.url, ssl=self.ssl, **post_args) as resp: try: - if resp.content_type == 'application/json': + if resp.content_type == "application/json": result = await resp.json() # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases - if resp.content_type != 'application/json' or (result is not None and "errors" not in result): + if resp.content_type != "application/json" or ( + result is not None and "errors" not in result + ): resp.raise_for_status() if log.isEnabledFor(logging.INFO): diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 0ed888f1..8104c2e4 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -2,11 +2,11 @@ import logging import requests from graphql import DocumentNode, ExecutionResult, print_ast +from json.decoder import JSONDecodeError from requests.adapters import HTTPAdapter, Retry from requests.auth import AuthBase from requests.cookies import RequestsCookieJar from typing import Any, Dict, Optional, Union -from json.decoder import JSONDecodeError from gql.transport import Transport @@ -151,14 +151,16 @@ def execute( # type: ignore self.method, self.url, **post_args # type: ignore ) try: - type = response.headers.get('Content-Type', None) - if 'application/json' in type: + type = response.headers.get("Content-Type", None) + if "application/json" in type: result = response.json() # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases # Raise a requests.HTTPerror if response status is 400 or higher - if 'application/json' not in type or (result is not None and "errors" not in result): + if "application/json" not in type or ( + result is not None and "errors" not in result + ): response.raise_for_status() if log.isEnabledFor(logging.INFO): @@ -170,7 +172,9 @@ def execute( # type: ignore try: message = response.json() - return ExecutionResult(errors=message.get("errors"), data=message.get("data")) + return ExecutionResult( + errors=message.get("errors"), data=message.get("data") + ) except JSONDecodeError: message = str(e) diff --git a/tests/test_client.py b/tests/test_client.py index c85d92b4..416929a5 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,15 +1,12 @@ -import os -from contextlib import suppress - import mock +import os import pytest +from contextlib import suppress from graphql import build_ast_schema, parse from gql import Client, gql from gql.transport import Transport -from gql.transport.exceptions import ( - TransportQueryError, -) +from gql.transport.exceptions import TransportQueryError with suppress(ModuleNotFoundError): from urllib3.exceptions import NewConnectionError @@ -54,7 +51,8 @@ def test_retries_on_transport(execute_mock): "Should be HTTPConnection", "Fake connection error" ) transport = RequestsHTTPTransport( - url="http://127.0.0.1:8000/graphql", retries=expected_retries, + url="http://127.0.0.1:8000/graphql", + retries=expected_retries, ) client = Client(transport=transport) @@ -135,7 +133,8 @@ def test_http_transport_verify_error(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", verify=False, + url="https://countries.trevorblades.com/", + verify=False, ) ) as client: with pytest.warns(Warning) as record: @@ -150,7 +149,8 @@ def test_http_transport_specify_method_valid(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", method="POST", + url="https://countries.trevorblades.com/", + method="POST", ) ) as client: result = client.execute(http_transport_query) @@ -163,7 +163,8 @@ def test_http_transport_specify_method_invalid(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", method="GET", + url="https://countries.trevorblades.com/", + method="GET", ) ) as client: with pytest.raises(Exception) as exc_info: From e383b379790b1e5843159cf89463db68b70c0378 Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Sat, 20 Feb 2021 10:36:44 +0530 Subject: [PATCH 3/9] Fix linting import-order --- gql/transport/aiohttp.py | 8 ++++---- gql/transport/requests.py | 5 +++-- tests/test_client.py | 5 +++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index ebea306b..5cf548f8 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -1,15 +1,15 @@ -from ssl import SSLContext - -import aiohttp import io import json import logging +from ssl import SSLContext +from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Type, Union + +import aiohttp from aiohttp.client_exceptions import ClientResponseError from aiohttp.client_reqrep import Fingerprint from aiohttp.helpers import BasicAuth from aiohttp.typedefs import LooseCookies, LooseHeaders from graphql import DocumentNode, ExecutionResult, print_ast -from typing import Any, AsyncGenerator, Dict, Optional, Tuple, Type, Union from ..utils import extract_files from .async_transport import AsyncTransport diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 8104c2e4..bace9a79 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -1,12 +1,13 @@ import json +from json.decoder import JSONDecodeError import logging +from typing import Any, Dict, Optional, Union + import requests from graphql import DocumentNode, ExecutionResult, print_ast -from json.decoder import JSONDecodeError from requests.adapters import HTTPAdapter, Retry from requests.auth import AuthBase from requests.cookies import RequestsCookieJar -from typing import Any, Dict, Optional, Union from gql.transport import Transport diff --git a/tests/test_client.py b/tests/test_client.py index 416929a5..b2240329 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,7 +1,8 @@ -import mock import os -import pytest from contextlib import suppress + +import mock +import pytest from graphql import build_ast_schema, parse from gql import Client, gql From d1ff3914a4b6121fde9421d5a21c6a3391cc26de Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Sat, 20 Feb 2021 17:20:49 +0530 Subject: [PATCH 4/9] 4XX should be wrapped around TransportServerError --- gql/transport/requests.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gql/transport/requests.py b/gql/transport/requests.py index bace9a79..3e651c32 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -173,9 +173,10 @@ def execute( # type: ignore try: message = response.json() - return ExecutionResult( - errors=message.get("errors"), data=message.get("data") - ) + if "errors" in "message": + return ExecutionResult( + errors=message.get("errors"), data=message.get("data") + ) except JSONDecodeError: message = str(e) From 31beed8dcd1b7f8a14ea69528821af621919a5d7 Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Tue, 23 Feb 2021 15:41:45 +0530 Subject: [PATCH 5/9] Add 401 Tests and Lint Fix --- gql/transport/requests.py | 2 +- tests/test_aiohttp.py | 31 +++++++++++++++++++++++++++++++ tests/test_requests.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 3e651c32..474f71d8 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -1,6 +1,6 @@ import json -from json.decoder import JSONDecodeError import logging +from json.decoder import JSONDecodeError from typing import Any, Dict, Optional, Union import requests diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index 0bf8c1ba..d8c27182 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -69,6 +69,37 @@ async def handler(request): assert africa["code"] == "AF" +@pytest.mark.asyncio +async def test_aiohttp_error_code_401(event_loop, aiohttp_server): + from aiohttp import web + from gql.transport.aiohttp import AIOHTTPTransport + + async def handler(request): + # Will generate http error code 401 + return web.Response( + text='{"error":"Unauthorized","message":"401 Client Error: Unauthorized"}', + content_type="application/json", + status=401, + ) + + app = web.Application() + app.router.add_route("POST", "/", handler) + server = await aiohttp_server(app) + + url = server.make_url("/") + + sample_transport = AIOHTTPTransport(url=url) + + async with Client(transport=sample_transport,) as session: + + query = gql(query1_str) + + with pytest.raises(TransportServerError) as exc_info: + await session.execute(query) + + assert "401, message='Unauthorized'" in str(exc_info.value) + + @pytest.mark.asyncio async def test_aiohttp_error_code_500(event_loop, aiohttp_server): from aiohttp import web diff --git a/tests/test_requests.py b/tests/test_requests.py index 99d40bf1..a37ea368 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -64,6 +64,41 @@ def test_code(): await run_sync_test(event_loop, server, test_code) +@pytest.mark.aiohttp +@pytest.mark.asyncio +async def test_requests_error_code_401(event_loop, aiohttp_server, run_sync_test): + from aiohttp import web + from gql.transport.requests import RequestsHTTPTransport + + async def handler(request): + # Will generate http error code 401 + return web.Response( + text='{"error":"Unauthorized","message":"401 Client Error: Unauthorized"}', + content_type="application/json", + status=401, + ) + + app = web.Application() + app.router.add_route("POST", "/", handler) + server = await aiohttp_server(app) + + url = server.make_url("/") + + def test_code(): + sample_transport = RequestsHTTPTransport(url=url) + + with Client(transport=sample_transport,) as session: + + query = gql(query1_str) + + with pytest.raises(TransportServerError) as exc_info: + session.execute(query) + + assert "401 Client Error: Unauthorized" in str(exc_info.value) + + await run_sync_test(event_loop, server, test_code) + + @pytest.mark.aiohttp @pytest.mark.asyncio async def test_requests_error_code_500(event_loop, aiohttp_server, run_sync_test): From 870be272a50861fa3fb6c422534e5aea357537cd Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Tue, 23 Feb 2021 18:30:55 +0530 Subject: [PATCH 6/9] Remove unnecessary code --- gql/transport/aiohttp.py | 7 +------ gql/transport/requests.py | 16 +--------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index 5cf548f8..756fdefd 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -152,8 +152,7 @@ async def execute( # If we upload files, we will extract the files present in the # variable_values dict and replace them by null values nulled_variable_values, files = extract_files( - variables=variable_values, - file_classes=self.file_classes, + variables=variable_values, file_classes=self.file_classes, ) # Save the nulled variable values in the payload @@ -222,10 +221,6 @@ async def execute( result_text = await resp.text() log.info("<<< %s", result_text) except ClientResponseError as e: - - # Check if the received response text is json pareable - # use the parsed text or str(e) as the exception message - raise TransportServerError(str(e), e.status) from e except Exception: result_text = await resp.text() diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 474f71d8..78d08ba3 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -1,6 +1,5 @@ import json import logging -from json.decoder import JSONDecodeError from typing import Any, Dict, Optional, Union import requests @@ -167,20 +166,7 @@ def execute( # type: ignore if log.isEnabledFor(logging.INFO): log.info("<<< %s", response.text) except requests.HTTPError as e: - - # Check if the received response text is json pareable - # use the parsed text or str(e) as the exception message - - try: - message = response.json() - if "errors" in "message": - return ExecutionResult( - errors=message.get("errors"), data=message.get("data") - ) - except JSONDecodeError: - message = str(e) - - raise TransportServerError(message, e.response.status_code) from e + raise TransportServerError(str(e), e.response.status_code) from e except Exception: raise TransportProtocolError("Server did not return a GraphQL result") From 6b46a1b76c14f663689083fe14ecd2379c77eb6f Mon Sep 17 00:00:00 2001 From: Abhishek Shekhar Date: Tue, 23 Feb 2021 19:06:33 +0530 Subject: [PATCH 7/9] Fix black issue --- tests/test_client.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index b2240329..1521eac7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -52,8 +52,7 @@ def test_retries_on_transport(execute_mock): "Should be HTTPConnection", "Fake connection error" ) transport = RequestsHTTPTransport( - url="http://127.0.0.1:8000/graphql", - retries=expected_retries, + url="http://127.0.0.1:8000/graphql", retries=expected_retries, ) client = Client(transport=transport) @@ -134,8 +133,7 @@ def test_http_transport_verify_error(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", - verify=False, + url="https://countries.trevorblades.com/", verify=False, ) ) as client: with pytest.warns(Warning) as record: @@ -150,8 +148,7 @@ def test_http_transport_specify_method_valid(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", - method="POST", + url="https://countries.trevorblades.com/", method="POST", ) ) as client: result = client.execute(http_transport_query) @@ -164,8 +161,7 @@ def test_http_transport_specify_method_invalid(http_transport_query): with Client( transport=RequestsHTTPTransport( - url="https://countries.trevorblades.com/", - method="GET", + url="https://countries.trevorblades.com/", method="GET", ) ) as client: with pytest.raises(Exception) as exc_info: From 554b9134a871e108642878ceb7ca94a7592e59a1 Mon Sep 17 00:00:00 2001 From: Hanusz Leszek Date: Sat, 24 Apr 2021 11:56:40 +0200 Subject: [PATCH 8/9] Refactor raising errors without checking content_type --- gql/transport/aiohttp.py | 37 +++++++++++++++++++------------------ gql/transport/requests.py | 35 +++++++++++++++++++++-------------- tests/test_aiohttp.py | 2 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index 756fdefd..9769ab30 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -206,35 +206,36 @@ async def execute( raise TransportClosed("Transport is not connected") async with self.session.post(self.url, ssl=self.ssl, **post_args) as resp: - try: - if resp.content_type == "application/json": - result = await resp.json() + async def raise_response_error(resp: aiohttp.ClientResponse, reason: str): # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases - if resp.content_type != "application/json" or ( - result is not None and "errors" not in result - ): + + 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 resp.json() if log.isEnabledFor(logging.INFO): result_text = await resp.text() log.info("<<< %s", result_text) - except ClientResponseError as e: - raise TransportServerError(str(e), e.status) from e + except Exception: - result_text = await resp.text() - raise TransportProtocolError( - f"Server did not return a GraphQL result: {result_text}" - ) + await raise_response_error(resp, "Not a JSON answer") if "errors" not in result and "data" not in result: - result_text = await resp.text() - raise TransportProtocolError( - "Server did not return a GraphQL result: " - 'No "data" or "error" keys in answer: ' - f"{result_text}" - ) + await raise_response_error(resp, 'No "data" or "error" keys in answer') return ExecutionResult(errors=result.get("errors"), data=result.get("data")) diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 78d08ba3..2f5ea451 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -38,7 +38,7 @@ def __init__( verify: bool = True, retries: int = 0, method: str = "POST", - **kwargs: Any + **kwargs: Any, ): """Initialize the transport with the given request parameters. @@ -150,28 +150,35 @@ def execute( # type: ignore response = self.session.request( self.method, self.url, **post_args # type: ignore ) - try: - type = response.headers.get("Content-Type", None) - if "application/json" in type: - result = response.json() + def raise_response_error(resp: requests.Response, reason: str): # We raise a TransportServerError if the status code is 400 or higher # We raise a TransportProtocolError in the other cases - # Raise a requests.HTTPerror if response status is 400 or higher - if "application/json" not in type or ( - result is not None and "errors" not in result - ): - response.raise_for_status() + + try: + # Raise a HTTPError if response status is 400 or higher + resp.raise_for_status() + except requests.HTTPError as e: + raise TransportServerError(str(e), e.response.status_code) from e + + result_text = resp.text + raise TransportProtocolError( + f"Server did not return a GraphQL result: " + f"{reason}: " + f"{result_text}" + ) + + try: + result = response.json() if log.isEnabledFor(logging.INFO): log.info("<<< %s", response.text) - except requests.HTTPError as e: - raise TransportServerError(str(e), e.response.status_code) from e + except Exception: - raise TransportProtocolError("Server did not return a GraphQL result") + raise_response_error(response, "Not a JSON answer") if "errors" not in result and "data" not in result: - raise TransportProtocolError("Server did not return a GraphQL result") + raise_response_error(response, 'No "data" or "error" keys in answer') return ExecutionResult(errors=result.get("errors"), data=result.get("data")) diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index d8c27182..bae454d7 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -167,7 +167,7 @@ async def handler(request): { "response": "qlsjfqsdlkj", "expected_exception": ( - "Server did not return a GraphQL result: " "qlsjfqsdlkj" + "Server did not return a GraphQL result: Not a JSON answer: qlsjfqsdlkj" ), }, { From c179127f2e87a3214772b385d04764f6d7091eeb Mon Sep 17 00:00:00 2001 From: Hanusz Leszek Date: Sat, 24 Apr 2021 15:08:05 +0200 Subject: [PATCH 9/9] fix typo error->errors --- gql/transport/aiohttp.py | 2 +- gql/transport/requests.py | 2 +- tests/test_aiohttp.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index 9769ab30..79684d6d 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -235,7 +235,7 @@ async def raise_response_error(resp: aiohttp.ClientResponse, reason: str): await raise_response_error(resp, "Not a JSON answer") if "errors" not in result and "data" not in result: - await raise_response_error(resp, 'No "data" or "error" keys in answer') + await raise_response_error(resp, 'No "data" or "errors" keys in answer') return ExecutionResult(errors=result.get("errors"), data=result.get("data")) diff --git a/gql/transport/requests.py b/gql/transport/requests.py index 2f5ea451..350525fc 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -178,7 +178,7 @@ def raise_response_error(resp: requests.Response, reason: str): raise_response_error(response, "Not a JSON answer") if "errors" not in result and "data" not in result: - raise_response_error(response, 'No "data" or "error" keys in answer') + raise_response_error(response, 'No "data" or "errors" keys in answer') return ExecutionResult(errors=result.get("errors"), data=result.get("data")) diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index bae454d7..d0443aaa 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -161,7 +161,7 @@ async def handler(request): "response": "{}", "expected_exception": ( "Server did not return a GraphQL result: " - 'No "data" or "error" keys in answer: {}' + 'No "data" or "errors" keys in answer: {}' ), }, { @@ -174,7 +174,7 @@ async def handler(request): "response": '{"not_data_or_errors": 35}', "expected_exception": ( "Server did not return a GraphQL result: " - 'No "data" or "error" keys in answer: {"not_data_or_errors": 35}' + 'No "data" or "errors" keys in answer: {"not_data_or_errors": 35}' ), }, ]