<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"
}