arrest


Namearrest JSON
Version 0.1.10 PyPI version JSON
download
home_pagehttps://s-bose.github.io/arrest
SummaryArrest is a wrapper of pydantic and httpx to make your REST api calls type-safe and structured
upload_time2024-11-01 10:51:40
maintainerNone
docs_urlNone
authorshiladitya
requires_python<4.0,>=3.10
licenseMIT
keywords arrest rest pydantic httpx api
VCS
bugtrack_url
requirements argcomplete backoff orjson pyyaml
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Arrest

[![Tests](https://github.com/s-bose/arrest/actions/workflows/tests.yml/badge.svg)](https://github.com/s-bose/arrest/actions/workflows/tests.yml)

[![codecov](https://codecov.io/github/s-bose/arrest/graph/badge.svg?token=VBU3156QHP)](https://codecov.io/github/s-bose/arrest)

[![PyPi](https://img.shields.io/pypi/v/arrest.svg)](https://pypi.python.org/pypi/arrest)

- Documentation: https://s-bose.github.io/arrest/

Enable data validation for REST APIs.

Arrest provides an easy and declarative way of defining, managing, and calling RESTful HTTP APIs with type validation, retries, exception handling, and other batteries included.

Arrest lets you define your RESTful API services in a simple encapsulation that takes care of the following:
1. Type validation for request and response data
2. HTTP request retries
3. Manage your services definitions in one place
4. Exception handling
5. Hooks for custom exceptions
6. Callbacks
7. Automatic code generation from OpenAPI Schema

## Contents

1. [Installation](#installation)
2. [Getting Started](#getting-started)
3. [Examples](#examples)
4. [Contributing](#contributing)

## Installation

### Using pip
```bash
pip install arrest
```

### Using poetry
```bash
poetry add arrest
```

### Using uv
```bash
uv add arrest
```

## Getting Started

Assuming you already have arrest installed in your system, let us create a simple connection.
We have a REST endpoint `htthttps://www.xyz-service.default.local.cluster/api/v1` which has a resource `/users` with method `GET`.

```python
import logging
from arrest import Resource, Service
from arrest.exceptions import ArrestHTTPException


xyz_service = Service(
    name="xyz",
    url="https://www.xyz-service.default.local.cluster/api/v1",
    resources=[
        Resource(
            route="/users",
            handlers=[
                ("GET", "/"),
                ("GET", "/{user_id:int}"),
                ("POST", "/")
            ]
        )
    ]
)

try:
    response = await xyz_service.users.get("/123")
except ArrestHTTPException as exc:
    logging.warning(f"{exc.status_code} {exc.data}")
```

This will make an HTTP GET request to `https://www.xyz-service.default.local.cluster/api/v1/users/123`.

You can also provide a request type for your handlers. This can be done by passing a third entry to your handler tuple containing the pydantic class, or pass it directly to the handler dict or `ResourceHandler` initialization.

```python
from pydantic import BaseModel

class UserRequest(BaseModel):
    name: str
    email: str
    password: str
    role: str

Resource(
    route="/users,
    handlers=[
        ("POST", "/", UserRequest) # or ResourceHandler(method="POST", route="/", request=UserRequest)
                                   # or {"method": "POST", "route": "/", "request": UserRequest}
    ]
)

await service.users.post("/", request={
    "name": "John Doe",
    "email": "john_doe@gmail.com",
    "password": "secret",
    "role": "admin"
    }
)
```

This gets automatically validated and parsed as `UserRequest` before sending the request payload to the server. If any validation error is raised the request won't go.


Similar to request, you can pass an additional fourth argument in the handler tuple for specifying a pydantic model for the handler.
If provided it will automatically deserialize the returned success json response into either a model instance or a list of model instances.

```python
class UserResponse(BaseModel):
    name: str
    email: str
    role: str
    created_at: datetime
    updated_at: datetime
    is_deleted: bool

Resource(
    route="/user",
    handlers=[
        ("GET", "/{user_id}", None, UserResponse), # if no request type to be supplied, leave it as `None`
    ]
)

user_id = "123"
response = await svc.user.get(f"/{user_id}") # type: UserResponse
```

Here, the JSON response from `https://www.xyz-service.default.local.cluster/api/v1/users/123` will be deserialized into `UserResponse` model instance.

For more info, please check the [docs](https://s-bose.github.io/arrest/getting-started)

## Examples

You can check out the `example` folder under the project repository to get a feel of how to use Arrest.

The `example_service` contains a minimal FastAPI application for task management with CRUD endpoints for `users` and `tasks`.

To generate the Arrest boilerplate from the OpenAPI specs, simply run the FastAPI application using `uvicorn` at [http://127.0.0.1:8080/docs](), and run the arrest CLI as followed:

```bash
$ arrest -u http://localhost:8080/openapi.json -d example_service
```
This will generate `models.py`, containing the Pydantic schemas corresponding to the OpenAPI components, a `resources.py` containing the RESTful resource definitions and a `services.py` containing the service definition that includes the resources.

To use the service, simply call `example_service.users.get("")`.


## Contributing

Please see the [CONTRIBUTING.md](CONTRIBUTING.md) for more information.

            

Raw data

            {
    "_id": null,
    "home_page": "https://s-bose.github.io/arrest",
    "name": "arrest",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": "arrest, rest, pydantic, httpx, api",
    "author": "shiladitya",
    "author_email": "shiladitya_basu@live.com",
    "download_url": "https://files.pythonhosted.org/packages/dd/b8/f5ae624bc9e306ed5d926630100463a2bca9cfb46803b2fcc4624e952137/arrest-0.1.10.tar.gz",
    "platform": null,
    "description": "# Arrest\n\n[![Tests](https://github.com/s-bose/arrest/actions/workflows/tests.yml/badge.svg)](https://github.com/s-bose/arrest/actions/workflows/tests.yml)\n\n[![codecov](https://codecov.io/github/s-bose/arrest/graph/badge.svg?token=VBU3156QHP)](https://codecov.io/github/s-bose/arrest)\n\n[![PyPi](https://img.shields.io/pypi/v/arrest.svg)](https://pypi.python.org/pypi/arrest)\n\n- Documentation: https://s-bose.github.io/arrest/\n\nEnable data validation for REST APIs.\n\nArrest provides an easy and declarative way of defining, managing, and calling RESTful HTTP APIs with type validation, retries, exception handling, and other batteries included.\n\nArrest lets you define your RESTful API services in a simple encapsulation that takes care of the following:\n1. Type validation for request and response data\n2. HTTP request retries\n3. Manage your services definitions in one place\n4. Exception handling\n5. Hooks for custom exceptions\n6. Callbacks\n7. Automatic code generation from OpenAPI Schema\n\n## Contents\n\n1. [Installation](#installation)\n2. [Getting Started](#getting-started)\n3. [Examples](#examples)\n4. [Contributing](#contributing)\n\n## Installation\n\n### Using pip\n```bash\npip install arrest\n```\n\n### Using poetry\n```bash\npoetry add arrest\n```\n\n### Using uv\n```bash\nuv add arrest\n```\n\n## Getting Started\n\nAssuming you already have arrest installed in your system, let us create a simple connection.\nWe have a REST endpoint `htthttps://www.xyz-service.default.local.cluster/api/v1` which has a resource `/users` with method `GET`.\n\n```python\nimport logging\nfrom arrest import Resource, Service\nfrom arrest.exceptions import ArrestHTTPException\n\n\nxyz_service = Service(\n    name=\"xyz\",\n    url=\"https://www.xyz-service.default.local.cluster/api/v1\",\n    resources=[\n        Resource(\n            route=\"/users\",\n            handlers=[\n                (\"GET\", \"/\"),\n                (\"GET\", \"/{user_id:int}\"),\n                (\"POST\", \"/\")\n            ]\n        )\n    ]\n)\n\ntry:\n    response = await xyz_service.users.get(\"/123\")\nexcept ArrestHTTPException as exc:\n    logging.warning(f\"{exc.status_code} {exc.data}\")\n```\n\nThis will make an HTTP GET request to `https://www.xyz-service.default.local.cluster/api/v1/users/123`.\n\nYou can also provide a request type for your handlers. This can be done by passing a third entry to your handler tuple containing the pydantic class, or pass it directly to the handler dict or `ResourceHandler` initialization.\n\n```python\nfrom pydantic import BaseModel\n\nclass UserRequest(BaseModel):\n    name: str\n    email: str\n    password: str\n    role: str\n\nResource(\n    route=\"/users,\n    handlers=[\n        (\"POST\", \"/\", UserRequest) # or ResourceHandler(method=\"POST\", route=\"/\", request=UserRequest)\n                                   # or {\"method\": \"POST\", \"route\": \"/\", \"request\": UserRequest}\n    ]\n)\n\nawait service.users.post(\"/\", request={\n    \"name\": \"John Doe\",\n    \"email\": \"john_doe@gmail.com\",\n    \"password\": \"secret\",\n    \"role\": \"admin\"\n    }\n)\n```\n\nThis gets automatically validated and parsed as `UserRequest` before sending the request payload to the server. If any validation error is raised the request won't go.\n\n\nSimilar to request, you can pass an additional fourth argument in the handler tuple for specifying a pydantic model for the handler.\nIf provided it will automatically deserialize the returned success json response into either a model instance or a list of model instances.\n\n```python\nclass UserResponse(BaseModel):\n    name: str\n    email: str\n    role: str\n    created_at: datetime\n    updated_at: datetime\n    is_deleted: bool\n\nResource(\n    route=\"/user\",\n    handlers=[\n        (\"GET\", \"/{user_id}\", None, UserResponse), # if no request type to be supplied, leave it as `None`\n    ]\n)\n\nuser_id = \"123\"\nresponse = await svc.user.get(f\"/{user_id}\") # type: UserResponse\n```\n\nHere, the JSON response from `https://www.xyz-service.default.local.cluster/api/v1/users/123` will be deserialized into `UserResponse` model instance.\n\nFor more info, please check the [docs](https://s-bose.github.io/arrest/getting-started)\n\n## Examples\n\nYou can check out the `example` folder under the project repository to get a feel of how to use Arrest.\n\nThe `example_service` contains a minimal FastAPI application for task management with CRUD endpoints for `users` and `tasks`.\n\nTo generate the Arrest boilerplate from the OpenAPI specs, simply run the FastAPI application using `uvicorn` at [http://127.0.0.1:8080/docs](), and run the arrest CLI as followed:\n\n```bash\n$ arrest -u http://localhost:8080/openapi.json -d example_service\n```\nThis will generate `models.py`, containing the Pydantic schemas corresponding to the OpenAPI components, a `resources.py` containing the RESTful resource definitions and a `services.py` containing the service definition that includes the resources.\n\nTo use the service, simply call `example_service.users.get(\"\")`.\n\n\n## Contributing\n\nPlease see the [CONTRIBUTING.md](CONTRIBUTING.md) for more information.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Arrest is a wrapper of pydantic and httpx to make your REST api calls type-safe and structured",
    "version": "0.1.10",
    "project_urls": {
        "Documentation": "https://s-bose.github.io/arrest",
        "Homepage": "https://s-bose.github.io/arrest",
        "Repository": "https://github.com/s-bose/arrest",
        "changelog": "https://s-bose.github.io/arrest/release-notes"
    },
    "split_keywords": [
        "arrest",
        " rest",
        " pydantic",
        " httpx",
        " api"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fa5b63a7713418a77cdc7a021d9653a04d7ba2a1bdd74a0dec045b1e2e9e5a26",
                "md5": "62fc2b2be42c10dc896e67ac8164f76e",
                "sha256": "9be117b22a67ac4af67028212d7dc545f197973979468c0b842b1fae7e431896"
            },
            "downloads": -1,
            "filename": "arrest-0.1.10-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "62fc2b2be42c10dc896e67ac8164f76e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 29274,
            "upload_time": "2024-11-01T10:51:38",
            "upload_time_iso_8601": "2024-11-01T10:51:38.291384Z",
            "url": "https://files.pythonhosted.org/packages/fa/5b/63a7713418a77cdc7a021d9653a04d7ba2a1bdd74a0dec045b1e2e9e5a26/arrest-0.1.10-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ddb8f5ae624bc9e306ed5d926630100463a2bca9cfb46803b2fcc4624e952137",
                "md5": "84861c927bd7286381563a87d3d0880f",
                "sha256": "896cb241e9028f2988683b32dc98d64c1cdb1e9768e254dc356d457d124d65e7"
            },
            "downloads": -1,
            "filename": "arrest-0.1.10.tar.gz",
            "has_sig": false,
            "md5_digest": "84861c927bd7286381563a87d3d0880f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 23631,
            "upload_time": "2024-11-01T10:51:40",
            "upload_time_iso_8601": "2024-11-01T10:51:40.005128Z",
            "url": "https://files.pythonhosted.org/packages/dd/b8/f5ae624bc9e306ed5d926630100463a2bca9cfb46803b2fcc4624e952137/arrest-0.1.10.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-01 10:51:40",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "s-bose",
    "github_project": "arrest",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "argcomplete",
            "specs": [
                [
                    "==",
                    "3.2.2"
                ]
            ]
        },
        {
            "name": "backoff",
            "specs": [
                [
                    "==",
                    "2.2.1"
                ]
            ]
        },
        {
            "name": "orjson",
            "specs": [
                [
                    "==",
                    "3.9.13"
                ]
            ]
        },
        {
            "name": "pyyaml",
            "specs": [
                [
                    "==",
                    "6.0.1"
                ]
            ]
        }
    ],
    "tox": true,
    "lcname": "arrest"
}
        
Elapsed time: 0.54731s