发布于 2026-01-06 1 阅读
0

FastAPI for Flask Users DEV's Worldwide Show and Tell Challenge Presented by Mux: Pitch Your Projects!

面向 Flask 用户的 FastAPI

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

虽然 Flask 已成为机器学习项目中 API 开发的实际选择,但一个名为 FastAPI 的新框架也获得了社区的广泛关注。

Flask 和 FastAPI 标志

我最近决定尝试一下 FastAPI,方法是将一个生产环境的 Flask 项目移植到 FastAPI 上。由于之前使用过 Flask,所以上手 FastAPI 非常容易,我只用了几个小时就完成了部署和运行。

自动数据验证、文档生成以及内置的最佳实践(如 pydantic schemas 和 python 类型)等附加优势,使其成为未来项目的有力选择。

在这篇文章中,我将通过对比 Flask 和 FastAPI 在各种常见用例中的实现方式来介绍 FastAPI。

版本信息:

截至撰写本文时,Flask 版本为 1.1.2,FastAPI 版本为 0.58.1。

安装

Flask 和 FastAPI 都可以在 PyPI 上找到。对于 conda,你需要使用conda-forge指定的通道来安装 FastAPI,而 Flask 则在默认通道中即可安装。

烧瓶:

pip install flask
conda install flask
Enter fullscreen mode Exit fullscreen mode

FastAPI:

pip install fastapi uvicorn
conda install fastapi uvicorn -c conda-forge
Enter fullscreen mode Exit fullscreen mode

运行“Hello World”

烧瓶:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return {'hello': 'world'}

if __name__ == '__main__':
    app.run()
Enter fullscreen mode Exit fullscreen mode

现在您可以使用以下命令运行开发服务器。它默认运行在 5000 端口。

python app.py
Enter fullscreen mode Exit fullscreen mode

FastAPI

# app.py
import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get('/')
def home():
    return {'hello': 'world'}

if __name__ == '__main__':
    uvicorn.run(app)
Enter fullscreen mode Exit fullscreen mode

FastAPI 将服务交付给一个名为 的生产就绪服务器uvicorn。我们可以在开发模式下运行它,默认端口为 8000。

python app.py
Enter fullscreen mode Exit fullscreen mode

生产服务器

烧瓶:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return {'hello': 'world'}

if __name__ == '__main__':
    app.run()
Enter fullscreen mode Exit fullscreen mode

对于生产服务器而言,gunicorn这是 Flask 中的常见选择。

gunicorn app:app
Enter fullscreen mode Exit fullscreen mode

FastAPI

# app.py
import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get('/')
def home():
    return {'hello': 'world'}

if __name__ == '__main__':
    uvicorn.run(app)
Enter fullscreen mode Exit fullscreen mode

FastAPI 将服务交付给一个名为uvicorn的生产就绪服务器。我们可以这样启动服务器:

uvicorn app:app
Enter fullscreen mode Exit fullscreen mode

您也可以通过运行以下命令以热重载模式启动它:

uvicorn app:app --reload
Enter fullscreen mode Exit fullscreen mode

此外,您还可以更改端口。

uvicorn app:app --port 5000
Enter fullscreen mode Exit fullscreen mode

工人数量也可以加以控制。

uvicorn app:app --workers 2
Enter fullscreen mode Exit fullscreen mode

您可以使用gunicorn以下命令来管理 uvicorn。所有常规的 gunicorn 参数,例如-w工作进程数()都适用。

gunicorn -k uvicorn.workers.UvicornWorker app:app
Enter fullscreen mode Exit fullscreen mode

HTTP 方法

烧瓶:

@app.route('/', methods=['POST'])
def example():
    ...
Enter fullscreen mode Exit fullscreen mode

FastAPI:

@app.post('/')
def example():
    ...
Enter fullscreen mode Exit fullscreen mode

每个HTTP方法都有单独的装饰器方法。

@app.get('/')
@app.put('/')
@app.patch('/')
@app.delete('/')
Enter fullscreen mode Exit fullscreen mode

URL变量

我们想从 URL 中获取用户 ID /users/1,然后将用户 ID 返回给用户。

烧瓶:

@app.route('/users/<int:user_id>')
def get_user_details(user_id):
    return {'user_id': user_id}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

在 FastAPI 中,我们使用 Python 的类型提示来指定所有数据类型。例如,这里我们指定该值user_id应为整数。URL 路径中的变量也以类似于 f-string 的方式进行指定。

@app.get('/users/{user_id}')
def get_user_details(user_id: int):
    return {'user_id': user_id}
Enter fullscreen mode Exit fullscreen mode

查询字符串

我们希望允许用户通过?q=abc在 URL 中使用查询字符串来指定搜索词。

烧瓶:

from flask import request

@app.route('/search')
def search():
    query = request.args.get('q')
    return {'query': query}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

@app.get('/search')
def search(q: str):
    return {'query': q}
Enter fullscreen mode Exit fullscreen mode

JSON POST 请求

我们来看一个简单的例子,我们想要发送一个带有text键的 JSON POST 请求,并获取返回的小写版本。

# Request
{"text": "HELLO"}

# Response
{"text": "hello"}
Enter fullscreen mode Exit fullscreen mode

烧瓶:

from flask import request

@app.route('/lowercase', methods=['POST'])
def lower_case():
    text = request.json.get('text')
    return {'text': text.lower()}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

如果您只是想复制 Flask 的功能,可以在 FastAPI 中按如下方式操作。

from typing import Dict

@app.post('/lowercase')
def lower_case(json_data: Dict):
    text = json_data.get('text')
    return {'text': text.lower()}
Enter fullscreen mode Exit fullscreen mode

但是,FastAPI 引入了一个新概念,即创建 Pydantic schema,该 schema 可以映射到接收到的 JSON 数据。我们可以使用 Pydantic 重构上面的示例,如下所示:

from pydantic import BaseModel

class Sentence(BaseModel):
    text: str

@app.post('/lowercase')
def lower_case(sentence: Sentence):
    return {'text': sentence.text.lower()}
Enter fullscreen mode Exit fullscreen mode

如您所见,JSON 数据并非以字典形式返回,而是被转换为模式对象Sentence。因此,我们可以使用诸如 `type` 之类的数据属性来访问数据sentence.text。这还实现了数据类型的自动验证。如果用户尝试发送字符串以外的任何数据,系统将自动生成验证错误。

无效请求示例

{"text": null}
Enter fullscreen mode Exit fullscreen mode

自动回复

{
    "detail": [
        {
            "loc": [
                "body",
                "text"
            ],
            "msg": "none is not an allowed value",
            "type": "type_error.none.not_allowed"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

文件上传

让我们创建一个 API 来返回上传的文件名。上传文件时使用的键是file.

Flask

允许通过请求对象访问已上传的文件。

# app.py

from flask import Flask, request
app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files.get('file')
    return {'name': file.filename}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

FastAPI 使用函数参数来指定文件键。

# app.py
from fastapi import FastAPI, UploadFile, File

app = FastAPI()

@app.post('/upload')
def upload_file(file: UploadFile = File(...)):
    return {'name': file.filename}
Enter fullscreen mode Exit fullscreen mode

表格提交

我们想要访问如下所示定义的文本表单字段,并输出其值。

<input name='city' type='text'>
Enter fullscreen mode Exit fullscreen mode

Flask

允许通过请求对象访问表单字段。

# app.py

from flask import Flask, request
app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def echo():
    city = request.form.get('city')
    return {'city': city}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

我们使用函数参数来定义表单字段的键和数据类型。

# app.py
from fastapi import FastAPI, Form
app = FastAPI()

@app.post('/submit')
def echo(city: str = Form(...)):
    return {'city': city}
Enter fullscreen mode Exit fullscreen mode

我们还可以像下面这样将表单字段设为可选字段。

from typing import Optional

@app.post('/submit')
def echo(city: Optional[str] = Form(None)):
    return {'city': city}
Enter fullscreen mode Exit fullscreen mode

同样,我们可以为表单字段设置默认值,如下所示。

@app.post('/submit')
def echo(city: Optional[str] = Form('Paris')):
    return {'city': city}
Enter fullscreen mode Exit fullscreen mode

曲奇饼

我们希望访问name请求中名为“cookie”的 cookie。

Flask

允许通过请求对象访问 cookie。

# app.py

from flask import Flask, request
app = Flask(__name__)

@app.route('/profile')
def profile():
    name = request.cookies.get('name')
    return {'name': name}
Enter fullscreen mode Exit fullscreen mode

FastAPI:

我们使用参数来定义 cookie 的键。

# app.py
from fastapi import FastAPI, Cookie
app = FastAPI()

@app.get('/profile')
def profile(name = Cookie(None)):
    return {'name': name}
Enter fullscreen mode Exit fullscreen mode

模块化视图

我们希望将单个 app.py 文件中的视图分解成单独的文件。

- app.py
- views
  - user.py
Enter fullscreen mode Exit fullscreen mode

Flask:

在 Flask 中,我们使用称为蓝图的概念来管理这一切。我们首先会创建一个用户视图蓝图,如下所示:

# views/user.py
from flask import Blueprint
user_blueprint = Blueprint('user', __name__)

@user_blueprint.route('/users')
def list_users():
    return {'users': ['a', 'b', 'c']}

Enter fullscreen mode Exit fullscreen mode

然后,将此视图注册到主app.py文件中。

# app.py
from flask import Flask
from views.user import user_blueprint

app = Flask(__name__)
app.register_blueprint(user_blueprint)
Enter fullscreen mode Exit fullscreen mode

FastAPI:

在 FastAPI 中,相当于蓝图的东西称为路由器。首先,我们创建一个用户路由器,如下所示:

# routers/user.py
from fastapi import APIRouter
router = APIRouter()

@router.get('/users')
def list_users():
    return {'users': ['a', 'b', 'c']}
Enter fullscreen mode Exit fullscreen mode

然后,我们将此路由器附加到主应用程序对象,如下所示:

# app.py
from fastapi import FastAPI
from routers import user

app = FastAPI()
app.include_router(user.router)
Enter fullscreen mode Exit fullscreen mode

数据验证

Flask

本身并不提供任何开箱即用的输入数据验证功能。通常的做法是编写自定义验证逻辑,或者使用像marshmalllowpydantic这样的库。

FastAPI:

FastAPI 将 pydantic 封装到其框架中,并允许通过简单地结合使用 pydantic schema 和 python 类型提示来进行数据验证。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    name: str
    age: int

@app.post('/users')
def save_user(user: User):
    return {'name': user.name,
            'age': user.age}
Enter fullscreen mode Exit fullscreen mode

这段代码会自动进行验证,确保name参数是字符串或age整数。如果发送了其他数据类型,它会自动生成验证错误信息。

以下是一些常见用例的 pydantic schema 示例。

示例 1:键值对

{
  "name": "Isaac",
  "age": 60
}
Enter fullscreen mode Exit fullscreen mode
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
Enter fullscreen mode Exit fullscreen mode

例2:物品集合

{
  "series": ["GOT", "Dark", "Mr. Robot"]
}
Enter fullscreen mode Exit fullscreen mode
from pydantic import BaseModel
from typing import List

class Metadata(BaseModel):
    series: List[str]
Enter fullscreen mode Exit fullscreen mode

示例 3:嵌套对象

{
  "users": [
    {
      "name": "xyz",
      "age": 25
    },
    {
      "name": "abc",
      "age": 30
    }
  ],
  "group": "Group A"
}
Enter fullscreen mode Exit fullscreen mode
from pydantic import BaseModel
from typing import List

class User(BaseModel):
    name: str
    age: int

class UserGroup(BaseModel):
    users: List[User]
    group: str
Enter fullscreen mode Exit fullscreen mode

您可以点击此处了解更多关于Python类型提示的信息

自动文档

Flask

本身并不提供任何内置的文档生成功能。虽然有flask-swaggerflask-restful等扩展可以弥补这一不足,但工作流程相对复杂。

FastAPI:

FastAPI 会自动生成一个交互式 Swagger 文档端点,/docs以及一个参考文档/redoc

例如,假设我们有一个简单的视图,如下所示,它反映了用户搜索的内容。

# app.py
from fastapi import FastAPI

app = FastAPI()

@app.get('/search')
def search(q: str):
    return {'query': q}
Enter fullscreen mode Exit fullscreen mode

Swagger 文档

如果运行服务器并访问该端点http://127.0.0.1:8000/docs,您将获得自动生成的 Swagger 文档。

FastAPI 中的 OpenAPI Swagger UI

您可以直接通过浏览器以交互方式试用 API。

FastAPI 中的交互式 API 使用

ReDoc 文档

除了 Swagger 之外,如果您访问该端点http://127.0.0.01:8000/redoc,还会获得一份自动生成的参考文档。其中包含有关参数、请求格式、响应格式和状态代码的信息。

FastAPI 中的 ReDoc 功能

跨域资源共享(CORS)

Flask

本身并不提供 CORS 支持。我们需要使用诸如flask-cors之类的扩展来配置 CORS,如下所示。

# app.py

from flask import Flask
from flask_cors import CORS

app_ = Flask(__name__)
CORS(app_)
Enter fullscreen mode Exit fullscreen mode

FastAPI:

FastAPI 提供了一个内置中间件来处理 CORS。下面我们展示一个 CORS 示例,其中我们允许任何来源访问我们的 API。

# app.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
Enter fullscreen mode Exit fullscreen mode

结论

因此,FastAPI 是 Fl​​ask 的绝佳替代方案,它能够构建健壮且内置最佳实践的 API。您可以参考文档了解更多信息。

连接

如果您喜欢这篇博文,欢迎在Twitter上关注我,我每周都会在那里分享新的博文。

文章来源:https://dev.to/amitness/fastapi-for-flask-users-1bg4