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

FastAPI——优点、缺点和不足。优点 缺点 不足之处 入门指南

FastAPI——优点、缺点和不足之处。

优点

缺点

丑陋的

入门

FastAPI 是一个相对较新的 Python Web 框架,号称是目前速度最快的 Python 框架之一。在本文中,我将根据我短暂的使用经验,探讨该框架的优缺点。我还会提供一些示例和解决方案,以尽量减少其缺点。

优点

1. 这确实是快速API

FastAPIFlask与其他主流 Python 框架(例如和 )相比,它的速度确实很快Django。以下来自Techempower的评分图表显示了这些框架之间的性能差异。

FastAPI、Flask 和 Django 的对比

我自己也做了一个小测试,看看哪个框架速度最快,结果相当有趣。在这个测试中,我为这三个框架都设置了一个简单的“Hello world”API。我通过调用这些API来测试响应时间,并取平均响应时间。结果可以分为两种情况:

a.服务器启动后首次调用的平均时间
b.首次调用后连续调用的平均时间

Django并且FastAPI在首次 API 调用中响应速度比平时慢。Flask在所有 API 调用中,响应速度始终保持一致,但比其他两个 API 慢得多。
以下显示了这三个 API 的平均耗时:

框架 案例 a 案例 b
FastAPI 17毫秒 6.2毫秒
Django 517.2毫秒 5.834毫秒
烧瓶 507.2毫秒 508.9毫秒

值得注意的是,Django 在首次调用后实际上比 FastAPI 的速度略快。但在某些情况下,例如无服务器环境,Django 较高的首次调用和启动时间可能会成为一个问题。需要说明的是,这些测试是在少量数据和特定环境下进行的,而且我对 Flask 和 Django 的经验非常有限,因此结果可能因人而异。

2. 支持异步代码

FastAPI 最令人兴奋的特性是它开箱即用地支持使用async/awaitPython 关键字编写异步代码。以下是一个从 Reddit 异步获取数据的 API 示例。(示例参考:Scott Robinson 的 Python async/await 教程

app = FastAPI()

async def get_json(client: ClientSession, url: str) -> bytes:
    async with client.get(url) as response:
        assert response.status == 200
        return await response.read()

async def get_reddit_top(subreddit: str, client: ClientSession, data: dict):
    data1 = await get_json(client, 'https://www.reddit.com/r/' + subreddit + '/top.json?sort=top&t=day&limit=5')

    j = json.loads(data1.decode('utf-8'))
    subreddit_data = []
    for i in j['data']['children']:
        score = i['data']['score']
        title = i['data']['title']
        link = i['data']['url']
        print(str(score) + ': ' + title + ' (' + link + ')')
        subreddit_data.append(str(score) + ': ' + title + ' (' + link + ')')
    data[subreddit] = subreddit_data
    print('DONE:', subreddit + '\n')


@app.get("/")
async def get_reddit_data_api() -> dict:
    start_time: float = time.time()
    client: ClientSession = aiohttp.ClientSession()
    data: dict = {}

    await asyncio.gather(
        get_reddit_top('python', client, data),
        get_reddit_top('programming', client, data),
        get_reddit_top('compsci', client, data),
    )
    await client.close()

    print("Got reddit data in ---" + str(time.time() - start_time) + "seconds ---")
    return data
Enter fullscreen mode Exit fullscreen mode

异步代码的神奇之处在于,由于get_reddit_top协程并发运行,API 的执行时间相比串行运行的执行时间显著减少。

3. 开发时间非常短

要创建一个基本的“Hello world”API,框架需要以下数量的代码(考虑到整个项目):

框架 代码行数
FastAPI 8行
烧瓶 7行

我没有考虑 Django,因为我认为它的结构与其他两者不同。
如果你想扩展 FastAPI 应用,其工作量与 Flask 类似。两者都采用了模块化设计,Flask 通过 Blueprint,FastAPI 通过 Router。因此,我认为 Flask 和 FastAPI 的开发时间非常接近。

4. 易于测试

测试 FastAPI 端点非常简单,可以使用FastAPI 提供的TestClient来完成。这使得测试驱动开发 (TDD) 变得非常容易。

app = FastAPI()

@app.get("/")
async def read_main():
    return {"msg": "Hello World"}

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"msg": "Hello World"}
Enter fullscreen mode Exit fullscreen mode

您可以轻松模拟 API 定义函数中的服务调用或代码read_main,并使用 TestClient 对其进行测试。

5. 无缝集中式异常处理

要在 FastAPI 中进行异常处理,只需使用@app.exception_handler注解或app.add_exception_handler函数注册响应Exception,FastAPI 就会处理它。

app = FastAPI()

@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

async def request_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse: 
return PlainTextResponse(str(exc.detail),status_code=exc.status_code)

app.add_exception_handler(exc_class_or_status_code=SomeOtherException,
handler=request_exception_handler)
Enter fullscreen mode Exit fullscreen mode

6. 优秀的文档

FastAPI 拥有非常详尽且示例丰富的文档,这使得学习和使用更加便捷。如果您需要查找有关 FastAPI 的信息,通常无需再去其他地方查找。

7. 易于部署

您可以使用 FastAPI 提供的Docker 镜像,通过 Docker 轻松部署 FastAPI 应用。您也可以使用Mangum将其部署到 AWS Lambda

缺点

1. 主文件拥挤

在 FastAPI 中,所有内容都与配置文件绑定FastAPI app。因此,您的main.py配置文件很容易变得非常臃肿。以下是一个示例。

app = FastAPI()

app.include_router(users.router)
app.include_router(items.router)
app.include_router(shops.router)
app.include_router(other.router)

@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

@app.exception_handler(SomeOtherException)
async def http_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse:
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
Enter fullscreen mode Exit fullscreen mode

现在想象一下,如果你有 10 个路由器和 20 个异常需要处理,main.py那么配置文件就会变得非常难以维护。幸运的是,这个问题很容易解决。

app = FastAPI()

include_routers(app);
add_exception_handlers(app);
Enter fullscreen mode Exit fullscreen mode

include_routers可以add_exception_handlers保存在单独的文件中。

2. 依赖注入中不存在单例

singleton根据这个GitHub 讨论串的说法, FastAPI 中的依赖注入不支持实例,但它支持每个 HTTP 请求使用单个实例。您要么需要自己创建单例类,要么需要使用其他依赖注入库。

丑陋的

请求验证

我在使用 FastAPI 时最糟糕的经历就是处理请求验证。它使用来自 `<validation>` 的验证,据我所知,没有直接的方法可以将验证消息从验证点传递到响应。你只能使用 `<validation>`通过Pydantic`<validation>` 传递的任何消息,或者编写自定义验证器。例如:PydanticRequestValidationError

app = FastAPI()

class SomeDto(BaseModel):
    data: str = Field(min_length=1, description="Minimum length must be greater than 1",
                      title="Minimum length must be greater than 1")

@app.post(path="/")
async def get_response(request: SomeDto):
    return "some response"

@app.exception_handler(RequestValidationError)
async def handle_error(request: Request, exc: RequestValidationError) -> PlainTextResponse:
    return PlainTextResponse(str(exc.errors()), status_code=400)
Enter fullscreen mode Exit fullscreen mode

exc.errors()返回一个包含硬编码消息的验证违规列表。我查阅了 `get_validate_includes()`Pydantic`get_validate_includes()` 的文档,但没有找到任何修改方法。甚至 `get_validate_includes()`和 `get_validate_includes( )` 的参数值也丢失了。FastAPIPydanticdescriptiontitle

入门

如果您想开始使用 FastAPI,网上有很多非常好的资源。以下是一些您可以参考的资源:

总之,FastAPI 是一个速度很快的 Web 框架,支持异步代码,并且拥有非常完善的文档。FastAPI 的优点远远大于缺点,我强烈建议您了解一下。

文章来源:https://dev.to/fuadrafid/fastapi-the-good-the-bad-and-the-ugly-20ob