fastapi-controllers


Namefastapi-controllers JSON
Version 0.3.0 PyPI version JSON
download
home_pagehttps://github.com/goraje/fastapi-controllers
SummarySimple Controller implementation for FastAPI
upload_time2023-01-31 23:48:22
maintainer
docs_urlNone
authorJerzy Góra
requires_python>=3.8,<4.0
licenseMIT
keywords fastapi controller cbv routing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p>
    <h1 align="center">fastapi-controllers</h1>
    <p align="center">
        A simple solution for organizing your FastAPI endpoints
    </p>
    <p align="center">
    <img src="https://badgen.net/pypi/v/fastapi-controllers"/>
    <img src="https://badgen.net/pypi/license/fastapi-controllers"/>
    <img src="https://badgen.net/pypi/python/fastapi-controllers"/>
    <img src="https://github.com/goraje/fastapi-controllers/actions/workflows/test.yml/badge.svg">
    </p>
</p>

## Organize your API endpoints

`fastapi-controllers` offers a simple solution for organizing your API endpoints by means of a `Controller` class embracing the concept of class-based views.

## Features

- class-based approach to organizing FastAPI endpoints
- class-scoped definition of APIRouter parameters
- instance-scoped definition of FastAPI dependencies
- it integrates seamlessly with the FastAPI framework
- works with both sync and async endpoints

## Installation

```sh
pip install fastapi-controllers
```

## Minimal working example

```python
import uvicorn
from fastapi import FastAPI, Response, status
from fastapi.websockets import WebSocket

from fastapi_controllers import Controller, get, websocket


class ExampleController(Controller):
    @get("/example", response_class=Response)
    async def get_example(self) -> Response:
        return Response(status_code=status.HTTP_200_OK)

    @websocket("/ws")
    async def ws_example(websocket: WebSocket) -> None:
        await websocket.accept()
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Received: {data}")


if __name__ == "__main__":
    app = FastAPI()
    app.include_router(ExampleController.create_router())
    uvicorn.run(app)
```

FastAPI's `APIRouter` is created and populated with API routes by the `Controller.create_router` method and can be incorporated into the application in the usual way via `app.include_router`.

## Seamless integration

The router-related parameters as well as those of HTTP request-specific and websocket decorators are expected to be the same as those used by `fastapi.APIRouter`, `fastapi.APIRouter.<request_method>` and `fastapi.APIRouter.websocket`. Validation of the provided parameters is performed during initialization via the `inspect` module. This ensures compatibility with the FastAPI framework and prevents the introduction of a new, unnecessary naming convention.

### Available decorators

```python
from fastapi_controllers import delete, get, head, options, patch, post, put, trace, websocket
```

## Use class variables to customize your APIRouter

Class variables can be used to set the commonly used APIRouter parameters: `prefix`, `dependencies` and `tags`.

```python
import uvicorn
from fastapi import Depends, FastAPI, Response, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from pydantic import BaseModel

from fastapi_controllers import Controller, get, post

security = HTTPBasic()


async def authorized_user(credentials: HTTPBasicCredentials = Depends(security)) -> None:
    ...


class ExampleRequest(BaseModel):
    name: str


class ExampleResponse(BaseModel):
    message: str


class ExampleController(Controller):
    prefix = "/example"
    tags = ["example"]
    dependencies = [Depends(authorized_user)]

    @get("", response_class=Response)
    async def get_example(self) -> Response:
        return Response(status_code=status.HTTP_200_OK)

    @post("", response_model=ExampleResponse)
    async def post_example(self, data: ExampleRequest) -> ExampleResponse:
        return ExampleResponse(message=f"Hello, {data.name}!")


if __name__ == "__main__":
    app = FastAPI()
    app.include_router(ExampleController.create_router())
    uvicorn.run(app)
```
### Additional APIRouter parameters
Additional APIRouter parameters can be provided via the `__router_params__` class variable in form of a mapping.

```python
import uvicorn
from fastapi import FastAPI, Response, status

from fastapi_controllers import Controller, get


class ExampleController(Controller):
    prefix = "/example"
    tags = ["example"]
    __router_params__ = {"deprecated": True}

    @get("", response_class=Response)
    async def get_example(self) -> Response:
        return Response(status_code=status.HTTP_200_OK)


if __name__ == "__main__":
    app = FastAPI()
    app.include_router(ExampleController.create_router())
    uvicorn.run(app)
```
> :warning: **Important**: Beware of assigning values to the same parameter twice (directly on class-level and through `__router_params__`). The values stored in `__router_params__` have precedence and will override your other settings if a name conflict arises. E.g. the following `Controller` would create an `APIRouter` with `prefix=/override`, `tags=["override"]` and `dependencies=[Depends(override)]`

```python
from fastapi import Depends

from fastapi_controllers import Controller


class ExampleController(Controller):
    prefix = "/example"
    tags = ["example"]
    dependencies = [Depends(example)]
    __router_params__ = {
        "prefix": "/override",
        "tags": ["override"],
        "dependencies": [Depends(override)],
    }
```


## Instance-scoped dependencies

Instance-scoped attributes can be defined in the `__init__` method of the `Controller` and offer an easy way to access common dependencies for all endpoints.

```python
import json

import uvicorn
from fastapi import Depends, FastAPI, Response, status

from fastapi_controllers import Controller, get


class DbSession:
    @property
    def status(self) -> str:
        return "CONNECTED"


async def get_db_session() -> DbSession:
    return DbSession()


class ExampleController(Controller):
    prefix = "/example"

    def __init__(self, session: DbSession = Depends(get_db_session)) -> None:
        self.session = session

    @get("", response_class=Response)
    async def get_status(self) -> Response:
        return Response(
            content=json.dumps({"status": f"{self.session.status}"}),
            status_code=status.HTTP_200_OK,
            media_type="application/json",
        )


if __name__ == "__main__":
    app = FastAPI()
    app.include_router(ExampleController.create_router())
    uvicorn.run(app)
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/goraje/fastapi-controllers",
    "name": "fastapi-controllers",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "fastapi,controller,cbv,routing",
    "author": "Jerzy G\u00f3ra",
    "author_email": "j.gora89@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/76/ed/e9bbbff8a9c83a57d301833e5441e49eb4416785215dca10eae33aad6fe1/fastapi_controllers-0.3.0.tar.gz",
    "platform": null,
    "description": "<p>\n    <h1 align=\"center\">fastapi-controllers</h1>\n    <p align=\"center\">\n        A simple solution for organizing your FastAPI endpoints\n    </p>\n    <p align=\"center\">\n    <img src=\"https://badgen.net/pypi/v/fastapi-controllers\"/>\n    <img src=\"https://badgen.net/pypi/license/fastapi-controllers\"/>\n    <img src=\"https://badgen.net/pypi/python/fastapi-controllers\"/>\n    <img src=\"https://github.com/goraje/fastapi-controllers/actions/workflows/test.yml/badge.svg\">\n    </p>\n</p>\n\n## Organize your API endpoints\n\n`fastapi-controllers` offers a simple solution for organizing your API endpoints by means of a `Controller` class embracing the concept of class-based views.\n\n## Features\n\n- class-based approach to organizing FastAPI endpoints\n- class-scoped definition of APIRouter parameters\n- instance-scoped definition of FastAPI dependencies\n- it integrates seamlessly with the FastAPI framework\n- works with both sync and async endpoints\n\n## Installation\n\n```sh\npip install fastapi-controllers\n```\n\n## Minimal working example\n\n```python\nimport uvicorn\nfrom fastapi import FastAPI, Response, status\nfrom fastapi.websockets import WebSocket\n\nfrom fastapi_controllers import Controller, get, websocket\n\n\nclass ExampleController(Controller):\n    @get(\"/example\", response_class=Response)\n    async def get_example(self) -> Response:\n        return Response(status_code=status.HTTP_200_OK)\n\n    @websocket(\"/ws\")\n    async def ws_example(websocket: WebSocket) -> None:\n        await websocket.accept()\n        while True:\n            data = await websocket.receive_text()\n            await websocket.send_text(f\"Received: {data}\")\n\n\nif __name__ == \"__main__\":\n    app = FastAPI()\n    app.include_router(ExampleController.create_router())\n    uvicorn.run(app)\n```\n\nFastAPI's `APIRouter` is created and populated with API routes by the `Controller.create_router` method and can be incorporated into the application in the usual way via `app.include_router`.\n\n## Seamless integration\n\nThe router-related parameters as well as those of HTTP request-specific and websocket decorators are expected to be the same as those used by `fastapi.APIRouter`, `fastapi.APIRouter.<request_method>` and `fastapi.APIRouter.websocket`. Validation of the provided parameters is performed during initialization via the `inspect` module. This ensures compatibility with the FastAPI framework and prevents the introduction of a new, unnecessary naming convention.\n\n### Available decorators\n\n```python\nfrom fastapi_controllers import delete, get, head, options, patch, post, put, trace, websocket\n```\n\n## Use class variables to customize your APIRouter\n\nClass variables can be used to set the commonly used APIRouter parameters: `prefix`, `dependencies` and `tags`.\n\n```python\nimport uvicorn\nfrom fastapi import Depends, FastAPI, Response, status\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\nfrom pydantic import BaseModel\n\nfrom fastapi_controllers import Controller, get, post\n\nsecurity = HTTPBasic()\n\n\nasync def authorized_user(credentials: HTTPBasicCredentials = Depends(security)) -> None:\n    ...\n\n\nclass ExampleRequest(BaseModel):\n    name: str\n\n\nclass ExampleResponse(BaseModel):\n    message: str\n\n\nclass ExampleController(Controller):\n    prefix = \"/example\"\n    tags = [\"example\"]\n    dependencies = [Depends(authorized_user)]\n\n    @get(\"\", response_class=Response)\n    async def get_example(self) -> Response:\n        return Response(status_code=status.HTTP_200_OK)\n\n    @post(\"\", response_model=ExampleResponse)\n    async def post_example(self, data: ExampleRequest) -> ExampleResponse:\n        return ExampleResponse(message=f\"Hello, {data.name}!\")\n\n\nif __name__ == \"__main__\":\n    app = FastAPI()\n    app.include_router(ExampleController.create_router())\n    uvicorn.run(app)\n```\n### Additional APIRouter parameters\nAdditional APIRouter parameters can be provided via the `__router_params__` class variable in form of a mapping.\n\n```python\nimport uvicorn\nfrom fastapi import FastAPI, Response, status\n\nfrom fastapi_controllers import Controller, get\n\n\nclass ExampleController(Controller):\n    prefix = \"/example\"\n    tags = [\"example\"]\n    __router_params__ = {\"deprecated\": True}\n\n    @get(\"\", response_class=Response)\n    async def get_example(self) -> Response:\n        return Response(status_code=status.HTTP_200_OK)\n\n\nif __name__ == \"__main__\":\n    app = FastAPI()\n    app.include_router(ExampleController.create_router())\n    uvicorn.run(app)\n```\n> :warning: **Important**: Beware of assigning values to the same parameter twice (directly on class-level and through `__router_params__`). The values stored in `__router_params__` have precedence and will override your other settings if a name conflict arises. E.g. the following `Controller` would create an `APIRouter` with `prefix=/override`, `tags=[\"override\"]` and `dependencies=[Depends(override)]`\n\n```python\nfrom fastapi import Depends\n\nfrom fastapi_controllers import Controller\n\n\nclass ExampleController(Controller):\n    prefix = \"/example\"\n    tags = [\"example\"]\n    dependencies = [Depends(example)]\n    __router_params__ = {\n        \"prefix\": \"/override\",\n        \"tags\": [\"override\"],\n        \"dependencies\": [Depends(override)],\n    }\n```\n\n\n## Instance-scoped dependencies\n\nInstance-scoped attributes can be defined in the `__init__` method of the `Controller` and offer an easy way to access common dependencies for all endpoints.\n\n```python\nimport json\n\nimport uvicorn\nfrom fastapi import Depends, FastAPI, Response, status\n\nfrom fastapi_controllers import Controller, get\n\n\nclass DbSession:\n    @property\n    def status(self) -> str:\n        return \"CONNECTED\"\n\n\nasync def get_db_session() -> DbSession:\n    return DbSession()\n\n\nclass ExampleController(Controller):\n    prefix = \"/example\"\n\n    def __init__(self, session: DbSession = Depends(get_db_session)) -> None:\n        self.session = session\n\n    @get(\"\", response_class=Response)\n    async def get_status(self) -> Response:\n        return Response(\n            content=json.dumps({\"status\": f\"{self.session.status}\"}),\n            status_code=status.HTTP_200_OK,\n            media_type=\"application/json\",\n        )\n\n\nif __name__ == \"__main__\":\n    app = FastAPI()\n    app.include_router(ExampleController.create_router())\n    uvicorn.run(app)\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Simple Controller implementation for FastAPI",
    "version": "0.3.0",
    "split_keywords": [
        "fastapi",
        "controller",
        "cbv",
        "routing"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "73380a07a75285ea3a67946cee883ab0541cf5005c361d8926652a26f31b3022",
                "md5": "cd0b9dc48f31c524b0aaad49d5633f71",
                "sha256": "2f031a618238822bb170535ca6c34da1c134a7d7914cbbd16826a94ba19156d5"
            },
            "downloads": -1,
            "filename": "fastapi_controllers-0.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cd0b9dc48f31c524b0aaad49d5633f71",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 7337,
            "upload_time": "2023-01-31T23:48:21",
            "upload_time_iso_8601": "2023-01-31T23:48:21.250117Z",
            "url": "https://files.pythonhosted.org/packages/73/38/0a07a75285ea3a67946cee883ab0541cf5005c361d8926652a26f31b3022/fastapi_controllers-0.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "76ede9bbbff8a9c83a57d301833e5441e49eb4416785215dca10eae33aad6fe1",
                "md5": "1e1810db995965f84aa7be4bcab41bdf",
                "sha256": "9cc652ed41972675e50cd862f31415e6686a0d316c7a7fec583c225924dc69ba"
            },
            "downloads": -1,
            "filename": "fastapi_controllers-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "1e1810db995965f84aa7be4bcab41bdf",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 10999,
            "upload_time": "2023-01-31T23:48:22",
            "upload_time_iso_8601": "2023-01-31T23:48:22.695275Z",
            "url": "https://files.pythonhosted.org/packages/76/ed/e9bbbff8a9c83a57d301833e5441e49eb4416785215dca10eae33aad6fe1/fastapi_controllers-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-01-31 23:48:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "goraje",
    "github_project": "fastapi-controllers",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "fastapi-controllers"
}
        
Elapsed time: 0.03487s