Skip to content

Commit

Permalink
Setup basic mkdocs project (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmateusz committed Feb 6, 2025
1 parent 6e2c471 commit 02141aa
Show file tree
Hide file tree
Showing 14 changed files with 935 additions and 56 deletions.
14 changes: 14 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 2
build:
os: ubuntu-24.04
tools:
python: "3.13"
jobs:
post_create_environment:
- pip install poetry
- poetry config virtualenvs.create false
post_install:
- poetry install --with docs

mkdocs:
configuration: mkdocs.yml
8 changes: 4 additions & 4 deletions docs/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ metaprogramming feature.
There are a few requirements regarding the application of the `@endpoint` descriptor.

The descriptor is available in a class that inherits from the abstract class [
`meatie.BaseClient`](../src/meatie/client.py) or [`meatie.BaseAsyncClient`](../src/meatie/aio/client.py). Meatie
`meatie.BaseClient`](https://github.com/pmateusz/meatie/blob/master/src/meatie/client.py) or [`meatie.BaseAsyncClient`](https://github.com/pmateusz/meatie/blob/master/src/meatie/aio/client.py). Meatie
provides implementations of these abstract classes for the
most popular HTTP libraries: [`meatie_httpx.Client`](../src/meatie_httpx/client.py), [
`meatie_requests.Client`](../src/meatie_requests/client.py), and [
`meatie_aiohttp.Client`](../src/meatie_aiohttp/client.py).
most popular HTTP libraries: [`meatie_httpx.Client`](https://github.com/pmateusz/meatie/blob/master/src/meatie_httpx/client.py), [
`meatie_requests.Client`](https://github.com/pmateusz/meatie/blob/master/src/meatie_requests/client.py), and [
`meatie_aiohttp.Client`](https://github.com/pmateusz/meatie/blob/master/tree/src/meatie_aiohttp/client.py).

The methods should be empty. Meatie won't call the method code directly. Leaving any implementation besides a docstring
is a deadcode.
Expand Down
223 changes: 223 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
<img src="https://repository-images.githubusercontent.com/735134836/df6752b8-38fa-4550-968e-cd2eda4adb37" alt="meatie">

[![GitHub Test Badge][1]][2] [![codecov.io][3]][4] [![pypi.org][5]][6] [![versions][7]][8]
[![downloads][9]][10] [![License][11]][12]

[1]: https://github.com/pmateusz/meatie/actions/workflows/ci.yaml/badge.svg "GitHub CI Badge"

[2]: https://github.com/pmateusz/meatie/actions/workflows/ci.yaml "GitHub Actions Page"

[3]: https://codecov.io/gh/pmateusz/meatie/branch/master/graph/badge.svg?branch=master "Coverage Badge"

[4]: https://codecov.io/gh/pmateusz/meatie?branch=master "Codecov site"

[5]: https://img.shields.io/pypi/v/meatie.svg "Pypi Latest Version Badge"

[6]: https://pypi.python.org/pypi/meatie "Pypi site"

[7]:https://img.shields.io/pypi/pyversions/meatie.svg

[8]: https://github.com/pmateusz/meatie

[9]: https://static.pepy.tech/badge/meatie

[10]: https://pepy.tech/project/meatie

[11]: https://img.shields.io/github/license/pmateusz/meatie "License Badge"

[12]: https://opensource.org/license/bsd-3-clause "License"


Meatie is a Python library that simplifies the implementation of REST API clients. The library generates code for
calling REST endpoints based on method signatures annotated with type hints. Meatie takes care of mechanics related to
HTTP communication, such as building URLs, encoding query parameters, and serializing the body in the HTTP requests and
responses. Rate limiting, retries, and caching are available with some modest extra setup.

Meatie works with all major HTTP client libraries (request, httpx, aiohttp) and offers seamless integration with
Pydantic (v1 and v2). The minimum officially supported version is Python 3.9.

## TL;DR

Generate HTTP clients using type annotations.

```python
from typing import Annotated

from aiohttp import ClientSession
from meatie import api_ref, endpoint
from meatie_aiohttp import Client
from pydantic import BaseModel, Field


class Todo(BaseModel):
user_id: int = Field(alias="userId")
id: int
title: str
completed: bool


class JsonPlaceholderClient(Client):
def __init__(self) -> None:
super().__init__(ClientSession(base_url="https://jsonplaceholder.typicode.com"))

@endpoint("/todos")
async def get_todos(self, user_id: Annotated[int, api_ref("userId")] = None) -> list[Todo]: ...

@endpoint("/users/{user_id}/todos")
async def get_todos_by_user(self, user_id: int) -> list[Todo]: ...

@endpoint("/todos")
async def post_todo(self, todo: Annotated[Todo, api_ref("body")]) -> Todo: ...
```

Do you use a different HTTP client library in your project? See the example adapted for [
`requests`](https://github.com/pmateusz/meatie/blob/master/tests/examples/requests/tutorial/test_basics.py) and [
`httpx`](https://github.com/pmateusz/meatie/blob/master/tests/examples/httpx/tutorial/test_basics.py).

### Caching

Cache result for a given TTL.

```python
from typing import Annotated

from meatie import MINUTE, api_ref, cache, endpoint, Cache
from meatie_aiohttp import Client
from pydantic import BaseModel


class Todo(BaseModel):
...


class JsonPlaceholderClient(Client):
def __init__(self) -> None:
super().__init__(
ClientSession(base_url="https://jsonplaceholder.typicode.com"),
local_cache=Cache(max_size=100),
)

@endpoint("/todos", cache(ttl=MINUTE, shared=False))
async def get_todos(self, user_id: Annotated[int, api_ref("userId")] = None) -> list[Todo]:
...
```

A cache key is built based on the URL path and query parameters. It does not include the scheme or the network location.
By default, every HTTP client instance has an independent cache. The behavior can be changed in the endpoint definition
to share cached results across all HTTP client class instances.

You can pass your custom cache to the local_cache parameter. The built-in cache provides a max_size parameter to limit
its size.

### Rate Limiting

Meatie can delay HTTP requests that exceed the predefined rate limit.

```python
from typing import Annotated

from aiohttp import ClientSession
from meatie import Limiter, Rate, api_ref, endpoint, limit
from meatie_aiohttp import Client
from pydantic import BaseModel


class Todo(BaseModel):
...


class JsonPlaceholderClient(Client):
def __init__(self) -> None:
super().__init__(
ClientSession(base_url="https://jsonplaceholder.typicode.com"),
limiter=Limiter(Rate(tokens_per_sec=10), capacity=10),
)

@endpoint("/todos", limit(tokens=2))
async def get_todos(self, user_id: Annotated[int, api_ref("userId")] = None) -> list[Todo]:
...
```

### Retries

Meatie can retry failed HTTP requests following the strategy set in the endpoint definition. The retry strategy is
controlled using third-party functions that specify when a retry should be attempted, how long to wait between
consecutive attempts to call the endpoint, and whether to abort further retries.

```python
from typing import Annotated

from aiohttp import ClientSession
from meatie import (
HttpStatusError,
RetryContext,
after_attempt,
api_ref,
endpoint,
fixed,
jit,
retry,
)
from meatie_aiohttp import Client
from pydantic import BaseModel


class Todo(BaseModel):
...


def should_retry(ctx: RetryContext) -> bool:
if isinstance(ctx.error, HttpStatusError):
return ctx.error.response.status >= 500
return False


class JsonPlaceholderClient(Client):
def __init__(self) -> None:
super().__init__(
ClientSession(base_url="https://jsonplaceholder.typicode.com", raise_for_status=True)
)

@endpoint("/todos", retry(on=should_retry, stop=after_attempt(3), wait=fixed(5) + jit(2)))
async def get_todos(self, user_id: Annotated[int, api_ref("userId")] = None) -> list[Todo]:
...
```

Meatie comes with a built-in set of predefined functions for building retry strategies. See
the [meatie.retry](https://github.com/pmateusz/meatie/blob/master/src/meatie/option/retry_option.py) option for more details.

### Calling Private Endpoints

Meatie can inject additional information into the HTTP request. A typical example is adding the `Authorization` header
with a token or signing the request using API keys.

```python
from typing import Annotated, override

from aiohttp import ClientSession
from meatie import Request, api_ref, endpoint, private
from meatie_aiohttp import Client
from pydantic import BaseModel


class Todo(BaseModel):
...


class JsonPlaceholderClient(Client):
def __init__(self) -> None:
super().__init__(ClientSession(base_url="https://jsonplaceholder.typicode.com"))

@endpoint("/todos", private)
async def get_todos(self, user_id: Annotated[int, api_ref("userId")] = None) -> list[Todo]:
...

@override
async def authenticate(self, request: Request) -> None:
request.headers["Authorization"] = "Bearer bWVhdGll"
```

## More Examples

Need more control over processing the HTTP requests or responses? See the [Meatie Cookbook](./cookbook.md) with
solutions to the most frequently asked questions by the community.
26 changes: 26 additions & 0 deletions docs/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
::: meatie.endpoint
::: meatie.body
options:
filters:
- "!^__call__$"
- "!^priority$"
::: meatie.private
options:
filters:
- "!^__call__$"
- "!^priority$"
::: meatie.limit
options:
filters:
- "!^__call__$"
- "!^priority$"
::: meatie.cache
options:
filters:
- "!^__call__$"
- "!^priority$"
::: meatie.retry
options:
filters:
- "!^__call__$"
- "!^priority$"
26 changes: 26 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
site_name: Meatie
repo_url: https://github.com/pmateusz/meatie
repo_name: GitHub
theme: readthedocs

nav:
- Home: index.md
- Cookbook: cookbook.md
- Reference: references.md

plugins:
- search
- mkdocstrings:
default_handler: python
handlers:
python:
options:
docstring_style: google
show_root_heading: true
members_order: source
annotations_path: brief
separate_signature: true
modernize_annotations: true
show_signature: true
show_signature_annotations: true
line_length: 60
Loading

0 comments on commit 02141aa

Please sign in to comment.