FastAPI for Flask Users
https://amitness.com/2020/06/fastapi-vs-flask/
虽然 Flask 已成为机器学习项目中 API 开发的实际选择,但有一个名为 FastAPI 的新框架已经获得了很多社区的关注.

我最近决定通过移植一个生产 Flask 项目来尝试一下 FastAPI。 从 Flask 获取 FastAPI 非常容易,我能够在几个小时内启动并运行.
自动数据验证、文档生成和 pydantic 模式和 python 类型等内置最佳实践的额外好处使其成为未来项目的有力选择.
在这篇文章中,我将通过对比 Flask 和 FastAPI 中各种常见用例的实现来介绍 FastAPI.
版本信息:
在撰写本文时,Flask 版本为 1.1.2,FastAPI 版本为 0.58.1
安装永久链接
PyPI 上提供了 Flask 和 FastAPI。 对于 conda,您需要使用 conda-forge 安装 FastAPI 的通道,而它在 Flask 的默认通道中可用.
烧瓶:
pip install flaskconda install flask
快速API:
pip install fastapi uvicornconda install fastapi uvicorn -c conda-forge
运行“Hello World”永久链接
烧瓶:
# app.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def home():return {'hello': 'world'}if __name__ == '__main__':app.run()
现在您可以使用以下命令运行开发服务器。 它默认在 5000 端口上运行.
python app.py
快速API
# app.pyimport uvicornfrom fastapi import FastAPIapp = FastAPI()@app.get('/')def home():return {'hello': 'world'}if __name__ == '__main__':uvicorn.run(app)
FastAPI 将服务推迟到一个生产就绪的服务器,称为 uvicorn. 我们可以在开发模式下使用默认端口运行它 8000.
python app.py
生产服务器永久链接
烧瓶:
# app.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def home():return {'hello': 'world'}if __name__ == '__main__':app.run()
对于生产服务器, gunicorn 是Flask中常见的选择.
gunicorn app:app
快速API
# app.pyimport uvicornfrom fastapi import FastAPIapp = FastAPI()@app.get('/')def home():return {'hello': 'world'}if __name__ == '__main__':uvicorn.run(app)
FastAPI 将服务推迟到一个生产就绪的服务器,称为 优维康. 我们可以启动服务器:
uvicorn app:app
您也可以通过运行以热重载模式启动它
uvicorn app:app --reload
此外,您还可以更改端口.
uvicorn app:app --port 5000
工人数量也可以控制.
uvicorn app:app --workers 2
您可以使用 gunicorn 也可以使用以下命令管理 uvicorn。 所有常规 gunicorn 标志,例如工人数量(-w) 工作.
gunicorn -k uvicorn.workers.UvicornWorker app:app
HTTP 方法永久链接
烧瓶:
@app.route('/', methods=['POST'])def example():...
快速API:
@app.post('/')def example():...
每个 HTTP 方法都有单独的装饰器方法.
@app.get('/')@app.put('/')@app.patch('/')@app.delete('/')
网址变量永久链接
我们想从 URL 中获取用户 ID,例如. /users/1 然后将用户id返回给用户.
烧瓶:
@app.route('/users/<int:user_id>')def get_user_details(user_id):return {'user_id': user_id}
快速API:
在 FastAPI 中,我们利用 Python 中的类型提示来指定所有数据类型。 例如,这里我们指定 user_id 应该是一个整数。 URL 路径中的变量也被指定为类似于 f-strings.
@app.get('/users/{user_id}')def get_user_details(user_id: int):return {'user_id': user_id}
查询字符串永久链接
我们希望允许用户通过使用查询字符串来指定搜索词 ?q=abc 在网址中.
烧瓶:
from flask import request@app.route('/search')def search():query = request.args.get('q')return {'query': query}
快速API:
@app.get('/search')def search(q: str):return {'query': q}
JSON POST 请求永久链接
让我们举一个玩具示例,我们想发送一个 JSON POST 请求,其中包含 text 键并取回小写版本.
# Request{"text": "HELLO"}# Response{"text": "hello"}
烧瓶:
from flask import request@app.route('/lowercase', methods=['POST'])def lower_case():text = request.json.get('text')return {'text': text.lower()}
快速API:
如果您只是从 Flask 复制功能,您可以在 FastAPI 中按照以下方式进行操作.
from typing import Dict@app.post('/lowercase')def lower_case(json_data: Dict):text = json_data.get('text')return {'text': text.lower()}
但是,这正是 FastAPI 引入了一个新概念的地方,即创建映射到正在接收的 JSON 数据的 Pydantic 模式。 我们可以使用 pydantic 重构上面的例子:
from pydantic import BaseModelclass Sentence(BaseModel):text: str@app.post('/lowercase')def lower_case(sentence: Sentence):return {'text': sentence.text.lower()}
正如所见,JSON 数据不是获取字典,而是转换为模式的对象 Sentence. 因此,我们可以使用数据属性访问数据,例如 sentence.text. 这也提供了数据类型的自动验证。 如果用户尝试发送字符串以外的任何数据,他们将收到自动生成的验证错误.
示例无效请求
{"text": null}
自动响应
{"detail": [{"loc": ["body","text"],"msg": "none is not an allowed value","type": "type_error.none.not_allowed"}]}
上传文件永久链接
让我们创建一个 API 来返回上传的文件名。 上传文件时使用的密钥将是 file.
烧瓶
Flask 允许通过请求对象访问上传的文件.
# app.pyfrom flask import Flask, requestapp = Flask(__name__)@app.route('/upload', methods=['POST'])def upload_file():file = request.files.get('file')return {'name': file.filename}
快速API:
FastAPI 使用函数参数指定文件密钥.
# app.pyfrom fastapi import FastAPI, UploadFile, Fileapp = FastAPI()@app.post('/upload')def upload_file(file: UploadFile = File(...)):return {'name': file.filename}
表格提交永久链接
我们想要访问如下所示定义的文本表单字段并回显该值.
<input name='city' type='text'>
烧瓶
Flask 允许通过请求对象访问表单字段.
# app.pyfrom flask import Flask, requestapp = Flask(__name__)@app.route('/submit', methods=['POST'])def echo():city = request.form.get('city')return {'city': city}
快速API:
我们使用函数参数来定义表单字段的键和数据类型.
# app.pyfrom fastapi import FastAPI, Formapp = FastAPI()@app.post('/submit')def echo(city: str = Form(...)):return {'city': city}
我们还可以使表单字段可选,如下所示
from typing import Optional@app.post('/submit')def echo(city: Optional[str] = Form(None)):return {'city': city}
同样,我们可以为表单字段设置一个默认值,如下所示.
@app.post('/submit')def echo(city: Optional[str] = Form('Paris')):return {'city': city}
饼干永久链接
我们想要访问一个名为 name 从请求.
烧瓶
Flask 允许通过请求对象访问 cookie.
# app.pyfrom flask import Flask, requestapp = Flask(__name__)@app.route('/profile')def profile():name = request.cookies.get('name')return {'name': name}
快速API:
我们使用参数来定义 cookie 的键.
# app.pyfrom fastapi import FastAPI, Cookieapp = FastAPI()@app.get('/profile')def profile(name = Cookie(None)):return {'name': name}
模块化视图永久链接
我们希望将视图从单个 app.py 分解为单独的文件.
- app.py- views- user.py
烧瓶:
在 Flask 中,我们使用一个称为蓝图的概念来管理它。 我们首先为用户视图创建一个蓝图,如下所示:
# views/user.pyfrom flask import Blueprintuser_blueprint = Blueprint('user', __name__)@user_blueprint.route('/users')def list_users():return {'users': ['a', 'b', 'c']}
然后,这个视图注册在主 app.py 文件.
# app.pyfrom flask import Flaskfrom views.user import user_blueprintapp = Flask(__name__)app.register_blueprint(user_blueprint)
快速API:
在 FastAPI 中,蓝图的等价物称为路由器。 首先,我们创建一个用户路由器:
# routers/user.pyfrom fastapi import APIRouterrouter = APIRouter()@router.get('/users')def list_users():return {'users': ['a', 'b', 'c']}
然后,我们将此路由器附加到主应用程序对象:
# app.pyfrom fastapi import FastAPIfrom routers import userapp = FastAPI()app.include_router(user.router)
数据验证永久链接
烧瓶
Flask 不提供任何开箱即用的输入数据验证功能。 通常的做法是编写自定义验证逻辑或使用库,例如 棉花糖 或者 Pydantic.
快速API:
FastAPI 将 pydantic 包装到其框架中,并通过简单地使用 pydantic 模式和 python 类型提示的组合来允许数据验证.
from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()class User(BaseModel):name: strage: int@app.post('/users')def save_user(user: User):return {'name': user.name,'age': user.age}
此代码将执行自动验证以确保 name 是一个字符串并且 age 是一个整数。 如果发送任何其他数据类型,它会自动生成带有相关消息的验证错误.
以下是一些常见用例的 pydantic 模式示例.
示例 1:键值对永久链接
{"name": "Isaac","age": 60}
from pydantic import BaseModelclass User(BaseModel):name: strage: int
示例 2:事物的收集永久链接
{"series": ["GOT", "Dark", "Mr. Robot"]}
from pydantic import BaseModelfrom typing import Listclass Metadata(BaseModel):series: List[str]
示例 3:嵌套对象永久链接
{"users": [{"name": "xyz","age": 25},{"name": "abc","age": 30}],"group": "Group A"}
from pydantic import BaseModelfrom typing import Listclass User(BaseModel):name: strage: intclass UserGroup(BaseModel):users: List[User]group: str
您可以从以下位置了解有关 Python 类型提示的更多信息 这里.
自动文档永久链接
烧瓶
Flask 不提供任何用于文档生成的内置功能。 有一些扩展,例如 烧瓶招摇 或者 烧瓶宁静的 填补这一空白,但工作流程相对复杂.
快速API:
FastAPI 自动生成一个交互式 swagger 文档端点 /docs 和参考文档 /redoc.
例如,假设我们有一个下面给出的简单视图,它与用户搜索的内容相呼应.
# app.pyfrom fastapi import FastAPIapp = FastAPI()@app.get('/search')def search(q: str):return {'query': q}
招摇文档永久链接
如果您运行服务器并转到端点 http://127.0.0.1:8000/docs, 你会得到一个自动生成的招摇文档.

您可以从浏览器本身以交互方式试用 API.

ReDoc 文档永久链接
除了招摇,如果你去端点 http://127.0.0.01:8000/redoc, 您将获得自动生成的参考文档。 有关于参数、请求格式、响应格式和状态码的信息.
跨域资源共享(CORS)永久链接
烧瓶
Flask 不提供开箱即用的 CORS 支持。 我们需要使用扩展名,例如 烧瓶-cors 配置 CORS 如下所示.
# app.pyfrom flask import Flaskfrom flask_cors import CORSapp_ = Flask(__name__)CORS(app_)
快速API:
FastAPI 提供了一个 内置中间件 处理 CORS。 我们在下面展示了一个 CORS 示例,我们允许任何来源访问我们的 API.
# app.pyfrom fastapi import FastAPIfrom fastapi.middleware.cors import CORSMiddlewareapp = FastAPI()app.add_middleware(CORSMiddleware,allow_origins=['*'],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)
结论永久链接
因此,FastAPI 是 Flask 的绝佳替代品,用于构建具有最佳实践的健壮 API。您可以参考 文件 了解更多.
