Source code for aiosnow.request.response
from typing import Any, Iterable, Union
from aiohttp import ClientResponse, client_exceptions, http_exceptions, web_exceptions
from marshmallow import EXCLUDE
from aiosnow.exceptions import (
ErrorResponse,
InvalidContentMethod,
RequestError,
UnexpectedResponseContent,
)
from .schemas import ContentSchema
[docs]class Response(ClientResponse):
"""Aiosnow Response class
The Response object holds information about the ServiceNow HTTP response.
Subclass of aiohttp.ClientResponse, its base reference documentation can be found here:
https://docs.aiohttp.org/en/latest/client_reference.html#aiohttp.ClientResponse
Attributes:
- data: Deserialized (ContentSchema) response content
- status: HTTP status code of response (int), e.g. 200
- reason: HTTP status reason of response (str), e.g. "OK"
- url: Request URL
"""
def __init__(self, *args: Any, **kwargs: Any):
super(Response, self).__init__(*args, **kwargs)
self.data: Union[list, dict, bytes, None] = None
def __repr__(self) -> str:
return (
f"<{self.__class__.__name__} {hex(id(self))} {self.url.path} "
f"[{self.status} {self.reason}]>"
)
def __getitem__(self, name: Any) -> Any:
if isinstance(self.data, dict):
return self.data.get(name)
return None
def __iter__(self) -> Iterable:
if isinstance(self.data, list):
yield from self.data
elif isinstance(self.data, dict):
yield from self.data.keys()
else:
raise InvalidContentMethod(f"Cannot iterate over type: {type(self.data)}")
def __len__(self) -> int:
if isinstance(self.data, list):
return len(self.data)
return 1
[docs] async def load_document(self) -> None:
"""Deserialize and set response content
Raises:
RequestError: If there was an error in the request-response content
"""
data = await self.json()
if not isinstance(data, dict):
if self.status == 204:
self.data = {}
return
await self._handle_error()
content = ContentSchema(unknown=EXCLUDE, many=False).load(data)
if "error" in content:
err = content["error"]
msg = (
f"{err['message']}: {err['detail']}"
if err["detail"]
else err["message"]
)
raise RequestError(msg, self.status)
self.data = content["result"]
async def _handle_error(self) -> None:
"""Something went seriously wrong.
This method interprets the error-response and raises the appropriate exception.
Raises:
- ServerError: If the error was interpreted as an unhandled server error
- UnexpectedResponseContent: If the request was successful, but the request-response contains
unexpected data
"""
try:
# Something went wrong, most likely out of the ServiceNow application's control:
# Raise exception if we got a HTTP error status back.
self.raise_for_status()
except (
client_exceptions.ClientResponseError,
http_exceptions.HttpProcessingError,
) as exc:
raise ErrorResponse(exc.message, exc.code)
except web_exceptions.HTTPException as exc:
raise ErrorResponse(exc.text or "", exc.status)
else:
# Non-JSON content along with a HTTP 200 returned: Unexpected.
text = await self.text()
raise UnexpectedResponseContent(
f"Unexpected response received from server: {text}", 200
)