An utility for writing simple clients for REST like APIs
Project description
Dataclass REST
A modern and simple way to create clients for REST like APIs
Quickstart
Step 1. Install
pip install dataclass_rest requests
Step 2. Declare models
@dataclass
class Todo:
id: int
user_id: int
title: str
completed: bool
Step 3. Create and configure client
from requests import Session
from dataclass_rest.http.requests import RequestsClient
class RealClient(RequestsClient):
def __init__(self):
super().__init__("https://example.com/api", Session())
Step 4. Declare methods using get
/post
/delete
/patch
/put
decorators.
Type hints are required. Body of method is ignored.
Use any method arguments to format URL.
body
argument is sent as request body with json. Other arguments, not used in URL are passed as query parameters.
get
and delete
does not have body.
from typing import Optional, List
from requests import Session
from dataclass_rest import get, post, delete
from dataclass_rest.http.requests import RequestsClient
class RealClient(RequestsClient):
def __init__(self):
super().__init__("https://example.com/api", Session())
@get("todos/{id}")
def get_todo(self, id: str) -> Todo:
pass
@get("todos")
def list_todos(self, user_id: Optional[int]) -> List[Todo]:
pass
@delete("todos/{id}")
def delete_todo(self, id: int):
pass
@post("todos")
def create_todo(self, body: Todo) -> Todo:
pass
You can use Callable (...) -> str
as the url source,
all parameters passed to the client method can be obtained inside the Callable
from requests import Session
from dataclass_rest import get
from dataclass_rest.http.requests import RequestsClient
def url_generator(todo_id: int) -> str:
return f"/todos/{todo_id}/"
class RealClient(RequestsClient):
def __init__(self):
super().__init__("https://dummyjson.com/", Session())
@get(url_generator)
def todo(self, todo_id: int) -> Todo:
pass
client = RealClient()
client.todo(5)
Asyncio
To use async client insted of sync:
- Install
aiohttp
(instead ofrequests
) - Change
dataclass_rest.http.requests.RequestsClient
todataclass_rest.http.aiohttp.AiohttpClient
- Add
async
keyword to your methods
Configuration
Parsing and serialization
All parsing and serialization is done using instances of FactoryProtocol
.
They are create by client object during its initialization. Default implementation creates Retort
from adaptix
There are 3 of them:
- Request body factory. Created using
_init_request_body_factory
. It is used to convert body object to simple python classes before senging to the server - Request args factory. Created using
_init_request_args_factory
. It is used to convert other parameters of method. All parameters are passed as a single object. Type of that object is generated and can be retrieved from your client methods using.methodspec.query_params_type
- Response body factory. Created using
_init_response_body_factory
. It is used to parse a server response.
Error handling
You can attach error handler to single method using @yourmethod.on_error
decorator in your class.
To set same behavior for all methods inherit from BoundMethod class, override _on_error_default
method and set that class as Client.method_class
Other params
You can use different body argument name if you want. Just pass body_name
to the decorator.
Special cases
None
in query params
By default, AioHTTP doesn't skip query params, you can customize that overriding _pre_process_request
in Method class
class NoneAwareAiohttpMethod(AiohttpMethod):
async def _pre_process_request(self, request: HttpRequest) -> HttpRequest:
request.query_params = {
k: v for k, v in request.query_params.items() if v is not None
}
return request
class Client(AiohttpClient):
method_class = NoneAwareAiohttpMethod
Handling No content
By default, en each method json response is expected. Sometime you expect no content from server. Especially for 204.
You can handle it by overriding _response_body
method, e.g.:
class NoneAwareRequestsMethod(RequestsMethod):
def _response_body(self, response: Response) -> Any:
if response.status_code == http.HTTPStatus.NO_CONTENT:
return None
return super()._response_body(response)
class Client(RequestsClient):
method_class = NoneAwareRequestsMethod
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for dataclass_rest-0.5.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1774cbe4a2845d619ac1dbfdddfc610bb037cf6402e0498b8e9c90e724a38dad |
|
MD5 | 460752abb441534b7432b1512225f2ab |
|
BLAKE2b-256 | b70716a9fe151563262b03194a9c605284d8f7f4a86ea0ba97451c233fbb7537 |