# Flask Toolkits
[![Downloads](https://static.pepy.tech/personalized-badge/flask-toolkits?period=total&units=international_system&left_color=black&right_color=blue&left_text=Downloads)](https://pepy.tech/project/flask-toolkits)
## Installation
```
pip install flask-toolkits
```
## Description
Flask toolkits implements and provides several features from `FastAPI` like:
- Automatic API documentation (define the function and we'll generate the `swagger`/`openapi` spec for you)
- Passing parameters through `view`/`router` function which is unable in `Flask` before
- Easy Middleware setup
- Parameters and schema validation using `Pydantic`
- Response classes that could return any type of data without worried to get error
- much more..
## Changelogs
- v0.0
- First Upload
- v0.1
- Integration with [flask-http-middleware](https://pypi.org/project/flask-http-middleware)
- [pydantic](https://pypi.org/project/pydantic) support for JSON arguments and validation
- Multiple response type generator
- Added `JSONResponse` class to replace `jsonify` roles in send dictionary data with encoding improvements.
- v0.2
- Supported enumeration API documentation
- Added support for type hint from `typing`'s generic (ex: `Optional`, `Union`, `List`)
- Fixed input parameter validations
- v0.3
- Support `File` and `Form` input parameters validation and automatic swagger.
- Added constraint feature for parameters (ex: limit, max/min length, greater/less than, equals than etc)
- v0.4
- Support `Authorization` header in openapi spec.
- Added `Authorization` processing function for security and can be used as `login` or `auth`.
- v0.5
- Support `add_url_rule` and `route` for endpoint definition
- Support auto swagger for multiple methods in a single endpoints
- v0.6
- Support `alias` on endpoint parameters (path, query, header, etc) to enable
non-pythonic terms of parameter names
- v0.7
- support response structure generator function to helps creating the response schema and examples
## Key Tools inside this `toolkit`
- Automatic API documentation (`swagger`/`openapi`)
- Request-Response direct HTTP middleware (`flask-http-middleware`)
- Automatic parameters validation (`pydantic`)
- Response generator (JSON, Plain Text, HTML)
## Automatic Parameters Validation
The original `Blueprints` class from `flask` can't insert most of arguments inside endpoint.
Here our `APIRouter` allows you to have arguments inside your endpoint
```
from typing import Optional
from flask_toolkits import APIRouter, Body, Header, Query
from flask_toolkits.responses import JSONResponse
router = APIRouter("email", import_name=__name__, static_folder="/routers/email", url_prefix="/email")
@router.post("/read", tags=["Email Router"])
def get_email(
id: int,
name: Optional[str],
):
return JSONResponse({"id": id, "name": name})
```
## Automatic API Documentation
Here our `APIRouter` allows you to auto-documenting your endpoint through `AutoSwagger`.
Define the new router using `APIRouter` class, lets put it in another pyfile
`email_view.py`
```
from typing import Optional
from flask_toolkits import APIRouter, Body, Header, Query
from flask_toolkits.responses import JSONResponse
router = APIRouter("email", import_name=__name__, static_folder="/routers/email", url_prefix="/email")
@router.post("/read", tags=["Email Router"])
def get_email(
id: int = Body(),
name: Optional[str] = Body(None),
token: int = Header(),
race: Optional[str] = Query(None)
):
return JSONResponse({"id":id, "name": name})
```
`main.py`
```
from flask import Flask
from flask_toolkits import AutoSwagger
from email_view import router as email_router
app = Flask(__name__)
auto_swagger = AutoSwagger()
app.register_blueprint(email_router)
app.register_blueprint(auto_swagger)
if __name__ == "__main__":
app.run()
```
then you can go to `http://localhost:5000/docs` and you will found you router is already documented
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auto1.png?raw=true)
---
## Supported Field Parameters
`flask-toolkits` provide multiple field parameters such as `Header`, `Query`, `Body`, `Path`, `File`, `Form`
---
## Easy Security Scheme Setup and Documentation
`flask-toolkits` helps you to define your security scheme for authorization easier than before. In advance this also give you automated documentation.
### Basic Usage
lets assume you have your own bearer security schema. You just have to create a new instance of `HTTPBearerSecurity()` to enable automatic documentation on it.
```
from flask import request
from flask_toolkits import APIRouter
from flask_toolkits.security import HTTPBearerSecurity
router = APIRouter("api", __name__)
@router.get("/home", security=HTTPBearerSecurity())
def home(message: str):
if my_security_scheme(request):
return JSONResponse({"message": message})
return JSONResponse({"message": "invalid authorization"})
```
this is how it looks like
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auth0.png?raw=true)
on you clicked it
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auth1.png?raw=true)
### Define your own security scheme
If you want to define your own security scheme you can follow below guidance
```
from flask import request
from flask_toolkits import APIRouter
from flask_toolkits.security import HTTPBearerSecurity
class JWTBearer(HTTPBearerSecurity):
def __init__(self):
super().__init__()
def __call__(self, req):
data = self.get_authorization_data(req)
if data != "abcdefghij":
raise Exception("This is not good")
return req
router = APIRouter("api", __name__)
@router.get("/home", security=JWTBearer())
def home(message: str):
if my_security_scheme(request):
return JSONResponse({"message": message})
return JSONResponse({"message": "invalid authorization"})
```
Overriding `__call__` method inside the subclass would define your security schema for the routers that are using your security scheme
---
## Define to all endpoints in a router
Just pass it to `APIRouter` and all its endpoint will use that security scheme!
```
router_with_bearer = APIRouter("api", __name__, security=JWTBearer())
```
but don't worries! You can also override it by just defining in the router decorator!
```
@router_with_bearer.get("/home", security=AnotherBearerSecurity())
def home():
return {"message": "hello"}
```
---
## Parameter Alias
In case you have non-pythonic terms with unicode character (-, +, _, =) for your paramter names, you can apply the `alias` into the parameters easily
```
@app.get("/test-alias")
def test_alias(
apikey: str = Header(alias="x-api-key")
):
return JSONResponse({"apikey": apikey})
```
here you will also have your swagger is defined with that `alias`
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/alias1.png?raw=true)
---
## Response Structure
Creating the response example and schema easily by just defining the class and pass it to `create_response_example` or accessing `as_response()` from `BaseSchema` objects
```
from flask_toolkits.responses import response_json_example
class PersonResponse(BaseSchema):
name: str
age: int
class FailedResponse(BaseSchema):
message: str
error_code: int
@router.route(
'/hello_world/<first>/<int:number>', tags=["My Hello"],
responses={
200: response_json_example(PersonResponse(name="Alex", age=20)),
400: FailedResponse(message="Data not found", error_code=101).as_response()
},
)
def hello_world(
name: str = Query(),
age: int = Query()
):
resp = {
"name": name,
"age": age
}
return JSONResponse(resp)
```
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/response_example1.png?raw=true)
![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/response_schema1.png?raw=true)
---
## Multiple HTTP Methods in a single endpoint
`add_url_rule` and `route` method for `Flask`'s App or `Blueprints` object are now supported. This also allows you to have multiple HTTP methods in a single endpoint function
```
@app.route("/test-multiple-method", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def go_multi_method(
name: str = Body()
):
return JSONResponse({"result": name})
```
Here you will get `null` if you hit it using `GET` but you'll get the value on you hit with other methods that support `Body`. You won't loose your validation since it only applied for methods that support that kind of params.
---
## Request-Response direct HTTP middleware
```
import time
from flask import Flask
from flask_toolkits.middleware import MiddlewareManager, BaseHTTPMiddleware
app = Flask(__name__)
class MetricsMiddleware(BaseHTTPMiddleware):
def __init__(self):
super().__init__()
def dispatch(self, request, call_next):
t0 = time.time()
response = call_next(request)
response_time = time.time()-t0
response.headers.add("response_time", response_time)
return response
app.wsgi_app = MiddlewareManager(app)
app.wsgi_app.add_middleware(MetricsMiddleware)
@app.get("/health")
def health():
return {"message":"I'm healthy"}
```
Raw data
{
"_id": null,
"home_page": "https://github.com/Danangjoyoo/flask-toolkits",
"name": "flask-toolkits",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "flask,middleware,http,request,response,swagger,openapi,toolkit",
"author": "danangjoyoo (Agus Danangjoyo)",
"author_email": "<agus.danangjoyo.blog@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/33/0d/665a8e57d4f6d94e14095a852c5e3e3b8d49178d06f3da8121d084389615/flask-toolkits-0.7.10.tar.gz",
"platform": null,
"description": "# Flask Toolkits\n[![Downloads](https://static.pepy.tech/personalized-badge/flask-toolkits?period=total&units=international_system&left_color=black&right_color=blue&left_text=Downloads)](https://pepy.tech/project/flask-toolkits)\n\n\n## Installation\n```\npip install flask-toolkits\n```\n\n## Description\nFlask toolkits implements and provides several features from `FastAPI` like:\n- Automatic API documentation (define the function and we'll generate the `swagger`/`openapi` spec for you)\n- Passing parameters through `view`/`router` function which is unable in `Flask` before\n- Easy Middleware setup\n- Parameters and schema validation using `Pydantic`\n- Response classes that could return any type of data without worried to get error\n- much more..\n\n\n## Changelogs\n- v0.0\n - First Upload\n- v0.1\n - Integration with [flask-http-middleware](https://pypi.org/project/flask-http-middleware)\n - [pydantic](https://pypi.org/project/pydantic) support for JSON arguments and validation\n - Multiple response type generator\n - Added `JSONResponse` class to replace `jsonify` roles in send dictionary data with encoding improvements.\n- v0.2\n - Supported enumeration API documentation\n - Added support for type hint from `typing`'s generic (ex: `Optional`, `Union`, `List`)\n - Fixed input parameter validations\n- v0.3\n - Support `File` and `Form` input parameters validation and automatic swagger.\n - Added constraint feature for parameters (ex: limit, max/min length, greater/less than, equals than etc)\n- v0.4\n - Support `Authorization` header in openapi spec.\n - Added `Authorization` processing function for security and can be used as `login` or `auth`.\n- v0.5\n - Support `add_url_rule` and `route` for endpoint definition\n - Support auto swagger for multiple methods in a single endpoints\n- v0.6\n - Support `alias` on endpoint parameters (path, query, header, etc) to enable\n non-pythonic terms of parameter names\n- v0.7\n - support response structure generator function to helps creating the response schema and examples\n\n## Key Tools inside this `toolkit`\n- Automatic API documentation (`swagger`/`openapi`)\n- Request-Response direct HTTP middleware (`flask-http-middleware`)\n- Automatic parameters validation (`pydantic`)\n- Response generator (JSON, Plain Text, HTML)\n\n## Automatic Parameters Validation\nThe original `Blueprints` class from `flask` can't insert most of arguments inside endpoint.\nHere our `APIRouter` allows you to have arguments inside your endpoint\n```\nfrom typing import Optional\nfrom flask_toolkits import APIRouter, Body, Header, Query\nfrom flask_toolkits.responses import JSONResponse\n\n\nrouter = APIRouter(\"email\", import_name=__name__, static_folder=\"/routers/email\", url_prefix=\"/email\")\n\n\n@router.post(\"/read\", tags=[\"Email Router\"])\ndef get_email(\n id: int,\n name: Optional[str],\n):\n return JSONResponse({\"id\": id, \"name\": name})\n\n```\n\n## Automatic API Documentation\nHere our `APIRouter` allows you to auto-documenting your endpoint through `AutoSwagger`.\nDefine the new router using `APIRouter` class, lets put it in another pyfile\n\n`email_view.py`\n```\nfrom typing import Optional\nfrom flask_toolkits import APIRouter, Body, Header, Query\nfrom flask_toolkits.responses import JSONResponse\n\n\nrouter = APIRouter(\"email\", import_name=__name__, static_folder=\"/routers/email\", url_prefix=\"/email\")\n\n\n@router.post(\"/read\", tags=[\"Email Router\"])\ndef get_email(\n id: int = Body(),\n name: Optional[str] = Body(None),\n token: int = Header(),\n race: Optional[str] = Query(None)\n):\n return JSONResponse({\"id\":id, \"name\": name})\n```\n\n`main.py`\n```\nfrom flask import Flask\nfrom flask_toolkits import AutoSwagger\n\nfrom email_view import router as email_router\n\n\napp = Flask(__name__)\n\nauto_swagger = AutoSwagger()\n\napp.register_blueprint(email_router)\napp.register_blueprint(auto_swagger)\n\n\nif __name__ == \"__main__\":\n app.run()\n```\n\nthen you can go to `http://localhost:5000/docs` and you will found you router is already documented\n\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auto1.png?raw=true)\n\n---\n\n## Supported Field Parameters\n`flask-toolkits` provide multiple field parameters such as `Header`, `Query`, `Body`, `Path`, `File`, `Form`\n\n---\n\n## Easy Security Scheme Setup and Documentation\n`flask-toolkits` helps you to define your security scheme for authorization easier than before. In advance this also give you automated documentation.\n\n### Basic Usage\nlets assume you have your own bearer security schema. You just have to create a new instance of `HTTPBearerSecurity()` to enable automatic documentation on it.\n```\nfrom flask import request\nfrom flask_toolkits import APIRouter\nfrom flask_toolkits.security import HTTPBearerSecurity\n\nrouter = APIRouter(\"api\", __name__)\n\n@router.get(\"/home\", security=HTTPBearerSecurity())\ndef home(message: str):\n if my_security_scheme(request):\n return JSONResponse({\"message\": message})\n return JSONResponse({\"message\": \"invalid authorization\"})\n```\n\nthis is how it looks like\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auth0.png?raw=true)\n\non you clicked it\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/auth1.png?raw=true)\n\n### Define your own security scheme\nIf you want to define your own security scheme you can follow below guidance\n```\nfrom flask import request\nfrom flask_toolkits import APIRouter\nfrom flask_toolkits.security import HTTPBearerSecurity\n\nclass JWTBearer(HTTPBearerSecurity):\n def __init__(self):\n super().__init__()\n\n def __call__(self, req):\n data = self.get_authorization_data(req)\n if data != \"abcdefghij\":\n raise Exception(\"This is not good\")\n return req\n\nrouter = APIRouter(\"api\", __name__)\n\n@router.get(\"/home\", security=JWTBearer())\ndef home(message: str):\n if my_security_scheme(request):\n return JSONResponse({\"message\": message})\n return JSONResponse({\"message\": \"invalid authorization\"})\n\n```\nOverriding `__call__` method inside the subclass would define your security schema for the routers that are using your security scheme\n\n---\n\n## Define to all endpoints in a router\nJust pass it to `APIRouter` and all its endpoint will use that security scheme!\n```\nrouter_with_bearer = APIRouter(\"api\", __name__, security=JWTBearer())\n```\nbut don't worries! You can also override it by just defining in the router decorator!\n```\n@router_with_bearer.get(\"/home\", security=AnotherBearerSecurity())\ndef home():\n return {\"message\": \"hello\"}\n```\n\n---\n\n## Parameter Alias\nIn case you have non-pythonic terms with unicode character (-, +, _, =) for your paramter names, you can apply the `alias` into the parameters easily\n```\n@app.get(\"/test-alias\")\ndef test_alias(\n apikey: str = Header(alias=\"x-api-key\")\n):\n return JSONResponse({\"apikey\": apikey})\n```\nhere you will also have your swagger is defined with that `alias`\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/alias1.png?raw=true)\n\n---\n\n## Response Structure\nCreating the response example and schema easily by just defining the class and pass it to `create_response_example` or accessing `as_response()` from `BaseSchema` objects\n```\nfrom flask_toolkits.responses import response_json_example\n\n\nclass PersonResponse(BaseSchema):\n name: str\n age: int\n\nclass FailedResponse(BaseSchema):\n message: str\n error_code: int\n\n@router.route(\n '/hello_world/<first>/<int:number>', tags=[\"My Hello\"],\n responses={\n 200: response_json_example(PersonResponse(name=\"Alex\", age=20)),\n 400: FailedResponse(message=\"Data not found\", error_code=101).as_response()\n },\n)\ndef hello_world(\n name: str = Query(),\n age: int = Query()\n):\n resp = {\n \"name\": name,\n \"age\": age\n }\n\n return JSONResponse(resp)\n```\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/response_example1.png?raw=true)\n![alt text](https://github.com/Danangjoyoo/flask-toolkits/blob/main/docs/response_schema1.png?raw=true)\n\n---\n\n## Multiple HTTP Methods in a single endpoint\n`add_url_rule` and `route` method for `Flask`'s App or `Blueprints` object are now supported. This also allows you to have multiple HTTP methods in a single endpoint function\n```\n@app.route(\"/test-multiple-method\", methods=[\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"])\ndef go_multi_method(\n name: str = Body()\n):\n return JSONResponse({\"result\": name})\n```\nHere you will get `null` if you hit it using `GET` but you'll get the value on you hit with other methods that support `Body`. You won't loose your validation since it only applied for methods that support that kind of params.\n\n---\n\n## Request-Response direct HTTP middleware\n```\nimport time\nfrom flask import Flask\nfrom flask_toolkits.middleware import MiddlewareManager, BaseHTTPMiddleware\n\napp = Flask(__name__)\n\nclass MetricsMiddleware(BaseHTTPMiddleware):\n def __init__(self):\n super().__init__()\n\n def dispatch(self, request, call_next):\n t0 = time.time()\n response = call_next(request)\n response_time = time.time()-t0\n response.headers.add(\"response_time\", response_time)\n return response\n\napp.wsgi_app = MiddlewareManager(app)\napp.wsgi_app.add_middleware(MetricsMiddleware)\n\n@app.get(\"/health\")\ndef health():\n return {\"message\":\"I'm healthy\"}\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "Flask toolkits to boost your development and simplify flask, its featured with AutoSwagger",
"version": "0.7.10",
"split_keywords": [
"flask",
"middleware",
"http",
"request",
"response",
"swagger",
"openapi",
"toolkit"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3d39f885d5c9365d8786d61d4ecb3cf26accdbc6be128ec47baa68f3451511af",
"md5": "b346859a861de39c5506c73ce8ea4941",
"sha256": "95eec867fc900b27a86d84d616f2cf5eda9b622dce7095d334a6626ce4a87e76"
},
"downloads": -1,
"filename": "flask_toolkits-0.7.10-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b346859a861de39c5506c73ce8ea4941",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 1020490,
"upload_time": "2023-04-10T12:14:33",
"upload_time_iso_8601": "2023-04-10T12:14:33.444353Z",
"url": "https://files.pythonhosted.org/packages/3d/39/f885d5c9365d8786d61d4ecb3cf26accdbc6be128ec47baa68f3451511af/flask_toolkits-0.7.10-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "330d665a8e57d4f6d94e14095a852c5e3e3b8d49178d06f3da8121d084389615",
"md5": "6c899d114766bf4bf000f834fc88f536",
"sha256": "82519db56181ab450f23f1650f4a04e17b268419fce1caa8448c199848dd8fdc"
},
"downloads": -1,
"filename": "flask-toolkits-0.7.10.tar.gz",
"has_sig": false,
"md5_digest": "6c899d114766bf4bf000f834fc88f536",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 1014427,
"upload_time": "2023-04-10T12:14:37",
"upload_time_iso_8601": "2023-04-10T12:14:37.418523Z",
"url": "https://files.pythonhosted.org/packages/33/0d/665a8e57d4f6d94e14095a852c5e3e3b8d49178d06f3da8121d084389615/flask-toolkits-0.7.10.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-04-10 12:14:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "Danangjoyoo",
"github_project": "flask-toolkits",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "flask-toolkits"
}