Skip to content

Commit c873e0d

Browse files
committed
httpx client
1 parent ceb0d5c commit c873e0d

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

src/dataclass_rest/http/httpx.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import urllib.parse
2+
from json import JSONDecodeError
3+
from typing import Any, Optional, Tuple
4+
5+
from httpx import AsyncClient, Response, HTTPError, Client
6+
7+
from dataclass_rest.base_client import BaseClient
8+
from dataclass_rest.boundmethod import AsyncMethod, SyncMethod
9+
from dataclass_rest.exceptions import (
10+
ClientError,
11+
ClientLibraryError,
12+
MalformedResponse,
13+
ServerError,
14+
)
15+
from dataclass_rest.http_request import HttpRequest, File
16+
17+
18+
class AsyncHttpxMethod(AsyncMethod):
19+
def _on_error_default(self, response: Response) -> Any:
20+
if 400 <= response.status_code < 500:
21+
raise ClientError(response.status_code)
22+
else:
23+
raise ServerError(response.status_code)
24+
25+
async def _release_raw_response(self, response: Response) -> None:
26+
await response.aclose()
27+
28+
async def _response_body(self, response: Response) -> Any:
29+
try:
30+
return response.json()
31+
except HTTPError as e:
32+
raise ClientLibraryError from e
33+
except JSONDecodeError as e:
34+
raise MalformedResponse from e
35+
36+
async def _response_ok(self, response: Response) -> bool:
37+
return response.is_success
38+
39+
40+
class AsyncHttpxClient(BaseClient):
41+
method_class = AsyncHttpxMethod
42+
43+
def __init__(
44+
self,
45+
base_url: str,
46+
client: Optional[AsyncClient] = None,
47+
):
48+
super().__init__()
49+
self.client = client or AsyncClient()
50+
self.base_url = base_url
51+
52+
def _prepare_file(self, fieldname: str, file: File) -> Tuple:
53+
return (file.filename or fieldname, file.contents, file.content_type)
54+
55+
async def do_request(self, request: HttpRequest) -> Any:
56+
if request.is_json_request:
57+
json = request.data
58+
data = None
59+
else:
60+
json = None
61+
data = request.data
62+
63+
files = {
64+
name: self._prepare_file(name, file)
65+
for name, file in request.files.items()
66+
}
67+
try:
68+
return await self.client.request(
69+
url=urllib.parse.urljoin(self.base_url, request.url),
70+
method=request.method,
71+
json=json,
72+
params=request.query_params,
73+
data=data,
74+
headers=request.headers,
75+
files=files,
76+
)
77+
except HTTPError as e:
78+
raise ClientLibraryError from e
79+
80+
81+
class HttpxMethod(SyncMethod):
82+
def _on_error_default(self, response: Response) -> Any:
83+
if 400 <= response.status_code < 500:
84+
raise ClientError(response.status_code)
85+
else:
86+
raise ServerError(response.status_code)
87+
88+
def _release_raw_response(self, response: Response) -> None:
89+
response.aclose()
90+
91+
def _response_body(self, response: Response) -> Any:
92+
try:
93+
return response.json()
94+
except HTTPError as e:
95+
raise ClientLibraryError from e
96+
except JSONDecodeError as e:
97+
raise MalformedResponse from e
98+
99+
def _response_ok(self, response: Response) -> bool:
100+
return response.is_success
101+
102+
103+
class HttpxClient(BaseClient):
104+
method_class = HttpxMethod
105+
106+
def __init__(
107+
self,
108+
base_url: str,
109+
client: Optional[Client] = None,
110+
):
111+
super().__init__()
112+
self.client = client or Client()
113+
self.base_url = base_url
114+
115+
def _prepare_file(self, fieldname: str, file: File) -> Tuple:
116+
return (file.filename or fieldname, file.contents, file.content_type)
117+
118+
def do_request(self, request: HttpRequest) -> Any:
119+
if request.is_json_request:
120+
json = request.data
121+
data = None
122+
else:
123+
json = None
124+
data = request.data
125+
126+
files = {
127+
name: self._prepare_file(name, file)
128+
for name, file in request.files.items()
129+
}
130+
try:
131+
return self.client.request(
132+
url=urllib.parse.urljoin(self.base_url, request.url),
133+
method=request.method,
134+
json=json,
135+
params=request.query_params,
136+
data=data,
137+
headers=request.headers,
138+
files=files,
139+
)
140+
except HTTPError as e:
141+
raise ClientLibraryError from e

0 commit comments

Comments
 (0)