class-based-fastapi


Nameclass-based-fastapi JSON
Version 1.0.4 PyPI version JSON
download
home_pagehttps://github.com/XDeepZeroX/class-based-fastapi
SummaryClass based routing for FastAPI
upload_time2025-01-21 07:31:15
maintainerNone
docs_urlNone
authorXDeepZeroX
requires_python<4,>=3.8
licenseMIT
keywords fastapi class instance routing
VCS
bugtrack_url
requirements fastapi pydantic
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
    <em>Class based routing for FastAPI</em>
</p>
<p align="center">
<img src="https://img.shields.io/github/last-commit/XDeepZeroX/class-based-fastapi.svg">
<br />
<a href="https://pypi.org/project/class-based-fastapi" target="_blank">
    <img src="https://img.shields.io/pypi/v/class-based-fastapi?label=class-based-fastapi" alt="Package version">
</a>
    <img src="https://img.shields.io/badge/python-3.6%20--%203.10-blue">
    <img src="https://img.shields.io/github/license/XDeepZeroX/class-based-fastapi">
</p>

---

**Documentation**:
<a href="https://XDeepZeroX.github.io/class-based-fastapi" target="_blank">https://XDeepZeroX.github.io/class-based-fastapi</a>

**Source Code**:
<a href="https://github.com/XDeepZeroX/class-based-fastapi" target="_blank">https://github.com/XDeepZeroX/class-based-fastapi</a>

---

<a href="https://fastapi.tiangolo.com">FastAPI</a> is a modern, fast web framework for building APIs with Python 3.6+.

---

## Features

Write Fast API Controllers (Classes) that can inherit route information from it's parent.

- This also allows to create a path prefix from a template and add api version information in the template.
- You don't need to duplicate the code, you can inherit it.
- To generate OpenAPI documentation, you do not need to explicitly specify the type of the return value, use Generics !

> Do the same with API methods as before, only more convenient.

See the [docs](https://XDeepZeroX.github.io/class-based-fastapi) for more details and examples.

## Requirements

This package is intended for use with any recent version of FastAPI (depending on `pydantic>=1.8.2`), and Python 3.6+.

## Installation

```sh
pip install class-based-fastapi
```

## Example


```python
import uuid
from typing import List, Generic, TypeVar  # 0. Import

import sqlalchemy
import uvicorn
from class_based_fastapi import Routable, get, put, post, delete
from fastapi import FastAPI, Depends
from sqlalchemy import select
from sqlmodel import Session, create_engine

from database import run_async_upgrade
from models.models import Category, CategoryPUT, Book, BookPUT

app = FastAPI(debug=True)

engine = create_engine('postgresql://postgres:123456@localhost:5432/fastapi_example', echo=True)


@app.on_event("startup")
def on_startup():
    print("Start migration")
    run_async_upgrade()
    print("DB success upgrade !")


def get_session() -> Session:
    with Session(engine) as conn:
        yield conn


T = TypeVar('T')  # 1. Create generic type
TPut = TypeVar('TPut')  # 1. Create generic type


class BaseAPI(Routable, Generic[T, TPut]):  # 2. Create generic base API controller
    conn: Session = Depends(get_session)

    def __init__(self):
        self._type_db_model = self._get_type_generic(T)

    def _get_type_generic(self, tvar: TypeVar):
        return next(filter(lambda x: x['name'] == tvar.__name__, self.__class__.__generic_attribute__))['type']

    @get("")
    def get_list_categories(self) -> List[T]:  # 3. Specifying  generic types
        items = self.conn.execute(select(self._type_db_model)).scalars().all()
        return items

    @post("")
    def add_category(self, model: T) -> T:
        self.conn.add(model)
        self.conn.commit()
        return model

    @delete("{guid}")
    def delete_category(self, guid: str) -> bool:
        self.conn.execute(
            sqlalchemy.delete(self._type_db_model).filter(self._type_db_model.guid == uuid.UUID(guid))
        )
        self.conn.commit()
        return True

    @put("{guid}")
    def update_category(self, guid: str, model: TPut) -> T:  # 3. Specifying  generic types
        model_db = self.conn.execute(
            select(self._type_db_model).filter(self._type_db_model.guid == uuid.UUID(guid))
        ).scalar()
        # Update fields
        for name, val in model.dict(exclude_unset=True).items():
            setattr(model_db, name, val)
        self.conn.commit()
        self.conn.refresh(model_db)
        return model_db


# Categories
class CategoryAPI(BaseAPI[Category, CategoryPUT]):  # 4. Inheriting the base controller
    NAME_MODULE = Category.__name__


# Books
class BookAPI(BaseAPI[Book, BookPUT]):  # 4. Inheriting the base controller
    NAME_MODULE = Book.__name__


app.include_router(CategoryAPI.routes())  # 5. Include routes
app.include_router(BookAPI.routes())  # 5. Include routes

if __name__ == "__main__":
    uvicorn.run('main:app', host="localhost", port=8001, reload=True, debug=True)

```

![Class base API OpenAPI Docs](https://github.com/XDeepZeroX/class-based-fastapi/raw/main/docs/img/generics/Class_based_API.png)

[Next steps >>>](https://XDeepZeroX.github.io/class-based-fastapi)

## License

This project is licensed under the terms of
the [MIT](https://github.com/XDeepZeroX/class-based-fastapi/blob/main/LICENSE) license.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/XDeepZeroX/class-based-fastapi",
    "name": "class-based-fastapi",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4,>=3.8",
    "maintainer_email": null,
    "keywords": "FastAPI, Class, Instance, Routing",
    "author": "XDeepZeroX",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/b3/74/687f5178c81098685856b4d96ebca9d4dbd1717256c7481cf1286781f659/class_based_fastapi-1.0.4.tar.gz",
    "platform": "all",
    "description": "<p align=\"center\">\r\n    <em>Class based routing for FastAPI</em>\r\n</p>\r\n<p align=\"center\">\r\n<img src=\"https://img.shields.io/github/last-commit/XDeepZeroX/class-based-fastapi.svg\">\r\n<br />\r\n<a href=\"https://pypi.org/project/class-based-fastapi\" target=\"_blank\">\r\n    <img src=\"https://img.shields.io/pypi/v/class-based-fastapi?label=class-based-fastapi\" alt=\"Package version\">\r\n</a>\r\n    <img src=\"https://img.shields.io/badge/python-3.6%20--%203.10-blue\">\r\n    <img src=\"https://img.shields.io/github/license/XDeepZeroX/class-based-fastapi\">\r\n</p>\r\n\r\n---\r\n\r\n**Documentation**:\r\n<a href=\"https://XDeepZeroX.github.io/class-based-fastapi\" target=\"_blank\">https://XDeepZeroX.github.io/class-based-fastapi</a>\r\n\r\n**Source Code**:\r\n<a href=\"https://github.com/XDeepZeroX/class-based-fastapi\" target=\"_blank\">https://github.com/XDeepZeroX/class-based-fastapi</a>\r\n\r\n---\r\n\r\n<a href=\"https://fastapi.tiangolo.com\">FastAPI</a> is a modern, fast web framework for building APIs with Python 3.6+.\r\n\r\n---\r\n\r\n## Features\r\n\r\nWrite Fast API Controllers (Classes) that can inherit route information from it's parent.\r\n\r\n- This also allows to create a path prefix from a template and add api version information in the template.\r\n- You don't need to duplicate the code, you can inherit it.\r\n- To generate OpenAPI documentation, you do not need to explicitly specify the type of the return value, use Generics !\r\n\r\n> Do the same with API methods as before, only more convenient.\r\n\r\nSee the [docs](https://XDeepZeroX.github.io/class-based-fastapi) for more details and examples.\r\n\r\n## Requirements\r\n\r\nThis package is intended for use with any recent version of FastAPI (depending on `pydantic>=1.8.2`), and Python 3.6+.\r\n\r\n## Installation\r\n\r\n```sh\r\npip install class-based-fastapi\r\n```\r\n\r\n## Example\r\n\r\n\r\n```python\r\nimport uuid\r\nfrom typing import List, Generic, TypeVar  # 0. Import\r\n\r\nimport sqlalchemy\r\nimport uvicorn\r\nfrom class_based_fastapi import Routable, get, put, post, delete\r\nfrom fastapi import FastAPI, Depends\r\nfrom sqlalchemy import select\r\nfrom sqlmodel import Session, create_engine\r\n\r\nfrom database import run_async_upgrade\r\nfrom models.models import Category, CategoryPUT, Book, BookPUT\r\n\r\napp = FastAPI(debug=True)\r\n\r\nengine = create_engine('postgresql://postgres:123456@localhost:5432/fastapi_example', echo=True)\r\n\r\n\r\n@app.on_event(\"startup\")\r\ndef on_startup():\r\n    print(\"Start migration\")\r\n    run_async_upgrade()\r\n    print(\"DB success upgrade !\")\r\n\r\n\r\ndef get_session() -> Session:\r\n    with Session(engine) as conn:\r\n        yield conn\r\n\r\n\r\nT = TypeVar('T')  # 1. Create generic type\r\nTPut = TypeVar('TPut')  # 1. Create generic type\r\n\r\n\r\nclass BaseAPI(Routable, Generic[T, TPut]):  # 2. Create generic base API controller\r\n    conn: Session = Depends(get_session)\r\n\r\n    def __init__(self):\r\n        self._type_db_model = self._get_type_generic(T)\r\n\r\n    def _get_type_generic(self, tvar: TypeVar):\r\n        return next(filter(lambda x: x['name'] == tvar.__name__, self.__class__.__generic_attribute__))['type']\r\n\r\n    @get(\"\")\r\n    def get_list_categories(self) -> List[T]:  # 3. Specifying  generic types\r\n        items = self.conn.execute(select(self._type_db_model)).scalars().all()\r\n        return items\r\n\r\n    @post(\"\")\r\n    def add_category(self, model: T) -> T:\r\n        self.conn.add(model)\r\n        self.conn.commit()\r\n        return model\r\n\r\n    @delete(\"{guid}\")\r\n    def delete_category(self, guid: str) -> bool:\r\n        self.conn.execute(\r\n            sqlalchemy.delete(self._type_db_model).filter(self._type_db_model.guid == uuid.UUID(guid))\r\n        )\r\n        self.conn.commit()\r\n        return True\r\n\r\n    @put(\"{guid}\")\r\n    def update_category(self, guid: str, model: TPut) -> T:  # 3. Specifying  generic types\r\n        model_db = self.conn.execute(\r\n            select(self._type_db_model).filter(self._type_db_model.guid == uuid.UUID(guid))\r\n        ).scalar()\r\n        # Update fields\r\n        for name, val in model.dict(exclude_unset=True).items():\r\n            setattr(model_db, name, val)\r\n        self.conn.commit()\r\n        self.conn.refresh(model_db)\r\n        return model_db\r\n\r\n\r\n# Categories\r\nclass CategoryAPI(BaseAPI[Category, CategoryPUT]):  # 4. Inheriting the base controller\r\n    NAME_MODULE = Category.__name__\r\n\r\n\r\n# Books\r\nclass BookAPI(BaseAPI[Book, BookPUT]):  # 4. Inheriting the base controller\r\n    NAME_MODULE = Book.__name__\r\n\r\n\r\napp.include_router(CategoryAPI.routes())  # 5. Include routes\r\napp.include_router(BookAPI.routes())  # 5. Include routes\r\n\r\nif __name__ == \"__main__\":\r\n    uvicorn.run('main:app', host=\"localhost\", port=8001, reload=True, debug=True)\r\n\r\n```\r\n\r\n![Class base API OpenAPI Docs](https://github.com/XDeepZeroX/class-based-fastapi/raw/main/docs/img/generics/Class_based_API.png)\r\n\r\n[Next steps >>>](https://XDeepZeroX.github.io/class-based-fastapi)\r\n\r\n## License\r\n\r\nThis project is licensed under the terms of\r\nthe [MIT](https://github.com/XDeepZeroX/class-based-fastapi/blob/main/LICENSE) license.\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Class based routing for FastAPI",
    "version": "1.0.4",
    "project_urls": {
        "Homepage": "https://github.com/XDeepZeroX/class-based-fastapi"
    },
    "split_keywords": [
        "fastapi",
        " class",
        " instance",
        " routing"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b374687f5178c81098685856b4d96ebca9d4dbd1717256c7481cf1286781f659",
                "md5": "107bc318f88fb334580f609ff2f6d6fb",
                "sha256": "8ac30dcea70f5fa2228f14b271cf8fdf6c87bcd3cc2851e78f302d34e2eccdf4"
            },
            "downloads": -1,
            "filename": "class_based_fastapi-1.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "107bc318f88fb334580f609ff2f6d6fb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4,>=3.8",
            "size": 19763,
            "upload_time": "2025-01-21T07:31:15",
            "upload_time_iso_8601": "2025-01-21T07:31:15.739196Z",
            "url": "https://files.pythonhosted.org/packages/b3/74/687f5178c81098685856b4d96ebca9d4dbd1717256c7481cf1286781f659/class_based_fastapi-1.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-21 07:31:15",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "XDeepZeroX",
    "github_project": "class-based-fastapi",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "fastapi",
            "specs": [
                [
                    ">=",
                    "0.115.6"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    ">=",
                    "2.10.5"
                ]
            ]
        }
    ],
    "lcname": "class-based-fastapi"
}
        
Elapsed time: 1.90635s