- Declarative API controller syntax
- Type-safe request/response handling
- Support for multiple HTTP clients (
wreq,aiohttp, or custom) - Comprehensive error handling
- Support for path parameters, query parameters, headers, body, JSON, form data, and file uploads
- Built on top of
msgspexfor fast serialization andkungfufor functional types (optional)
# Base installation
pip install saronia
# With wreq client
pip install saronia[wreq]
# With aiohttp client
pip install saronia[aiohttp]import asyncio
from dataclasses import dataclass
from uuid import UUID
from http import HTTPStatus
from kungfu import Error, Ok
from msgspex import Model
from saronia import API, APIError, APIResult, HTTPBearer, ModelStatusError, get, post
from wreq import Client
from saronia import WreqClient
Token = HTTPBearer
@dataclass
class Auth:
token: Token
cool_api = API.endpoint("/coolapi/v1").bind_auth(Auth)
class ValidationError(Model, ModelStatusError[HTTPStatus.INTERNAL_SERVER_ERROR]):
message: str
class NotFoundError(Model, ModelStatusError[HTTPStatus.NOT_FOUND]):
message: str
class Book(Model):
id: UUID
name: str
class CreateBookDTO(Model, kw_only=True):
book_id: UUID
name: str
@cool_api("/books", auth=Token)
class BooksController:
@get("/{book_id}", ValidationError, NotFoundError)
async def get_book_by_id(self, book_uuid: UUID) -> Book:
...
@post("/create", CreateBookDTO) # or as a Result
async def create_book(self) -> APIResult[Book, ValidationError | NotFoundError]:
...
books = BooksController()
async def main() -> None:
client = Client()
cool_api.build(WreqClient(client, base_url="https://api.example.com", request_timeout=45.0))
cool_api.auth(token=Token("abc123..."))
try:
book = await books.get_book_by_id(book_uuid=UUID("12345678-1234-5678-1234-567812345678"))
print("Book:", book)
except APIError as error:
print("API error:", error)
return
match await books.create_book(book_id=UUID("87654321-4321-8765-4321-876543218765"), name="New Book"):
case Ok(new_book):
print("New book:", new_book)
case Error(error):
print("API error:", error)
asyncio.run(main())saronia is MIT licensed