Skip to content

Feature/httpx #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions src/dataclass_rest/http/httpx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import urllib.parse
from json import JSONDecodeError
from typing import Any, Optional, Tuple

from httpx import AsyncClient, Response, HTTPError, Client

from dataclass_rest.base_client import BaseClient
from dataclass_rest.boundmethod import AsyncMethod, SyncMethod
from dataclass_rest.exceptions import (
ClientError,
ClientLibraryError,
MalformedResponse,
ServerError,
)
from dataclass_rest.http_request import HttpRequest, File


class AsyncHttpxMethod(AsyncMethod):
def _on_error_default(self, response: Response) -> Any:
if 400 <= response.status_code < 500:
raise ClientError(response.status_code)
else:
raise ServerError(response.status_code)

async def _release_raw_response(self, response: Response) -> None:
await response.aclose()

async def _response_body(self, response: Response) -> Any:
try:
return response.json()
except HTTPError as e:
raise ClientLibraryError from e
except JSONDecodeError as e:
raise MalformedResponse from e

async def _response_ok(self, response: Response) -> bool:
return response.is_success


class AsyncHttpxClient(BaseClient):
method_class = AsyncHttpxMethod

def __init__(
self,
base_url: str,
client: Optional[AsyncClient] = None,
):
super().__init__()
self.client = client or AsyncClient()
self.base_url = base_url

def _prepare_file(self, fieldname: str, file: File) -> Tuple:
return (file.filename or fieldname, file.contents, file.content_type)

async def do_request(self, request: HttpRequest) -> Any:
if request.is_json_request:
json = request.data
data = None
else:
json = None
data = request.data

files = {
name: self._prepare_file(name, file)
for name, file in request.files.items()
}
try:
return await self.client.request(
url=urllib.parse.urljoin(self.base_url, request.url),
method=request.method,
json=json,
params=request.query_params,
data=data,
headers=request.headers,
files=files,
)
except HTTPError as e:
raise ClientLibraryError from e


class HttpxMethod(SyncMethod):
def _on_error_default(self, response: Response) -> Any:
if 400 <= response.status_code < 500:
raise ClientError(response.status_code)
else:
raise ServerError(response.status_code)

def _release_raw_response(self, response: Response) -> None:
response.aclose()

def _response_body(self, response: Response) -> Any:
try:
return response.json()
except HTTPError as e:
raise ClientLibraryError from e
except JSONDecodeError as e:
raise MalformedResponse from e

def _response_ok(self, response: Response) -> bool:
return response.is_success


class HttpxClient(BaseClient):
method_class = HttpxMethod

def __init__(
self,
base_url: str,
client: Optional[Client] = None,
):
super().__init__()
self.client = client or Client()
self.base_url = base_url

def _prepare_file(self, fieldname: str, file: File) -> Tuple:
return (file.filename or fieldname, file.contents, file.content_type)

def do_request(self, request: HttpRequest) -> Any:
if request.is_json_request:
json = request.data
data = None
else:
json = None
data = request.data

files = {
name: self._prepare_file(name, file)
for name, file in request.files.items()
}
try:
return self.client.request(
url=urllib.parse.urljoin(self.base_url, request.url),
method=request.method,
json=json,
params=request.query_params,
data=data,
headers=request.headers,
files=files,
)
except HTTPError as e:
raise ClientLibraryError from e
Loading