Python-web框架 fastapi

目录

简介

性能

api 文档

类型检查

蓝图APIRouter

自定义的tags与responses

注册 APIRouter


简介

官网教程(中文版)FastAPI

python语言下的Web框架有很多,比如:

  • 从大而全的Django。

  • 小而且美的Flask。

  • 很早就支持异步的 Tornado。

  • 性能更进一步的异步框架 sanic。

  • ......

fastapi在如何把后端api做好的这件事情上,做的比sanic更全面,更彻底。fastapi的安装也非常简单,如下:

安装FastAPI
pip install fastapi

安装uvicorn来作为服务器
pip install uvicorn

Ps:若要一次性安装所有的可选依赖及对应功能:
pip install fastapi[all]

fastapi的优点很多,比如:性能、api文档、高效的类型检查等

性能

先做个简单的性能对比:

  • flask

# flask==2.0.1
from flask import Flask
from flask import jsonify

app = Flask(__name__)


@app.route("/")
def hello_world():
    return jsonify({"hello": "world"})
  • fastapi

# fastapi==0.65.1
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"Hello": "World"}

虽然两个框架都支持异步(flask 2.0 支持异步),但我们使用的都是同步代码。

JMeter配置:并发(500)* 循环(100)* 启动时间(1s) = 总请求数(50000)

结果flaskfastapigin
运行时长67s28s5s
最大值37197ms641ms270ms
平均值582ms266ms40ms
吞吐量751.s/sec1798.3/sec9817.4/sec

虽然是简单的对比,fastapi 在各项性能指标,都有非常明显的性能优势。

Ps:

在相同的环境上开启了gin(go语言) 服务又跑了一遍。gin 在go 主流的几款 web框架下性能表现都是很强的,碾压python Web框架简直太容易了。最后一列是gin的数据。

api 文档

fastapi直接支持OpenAPI(前身是Swagger) 和redoc 两种文档格式。

fastapi_demo.py

# -*- coding: UTF-8 -*-
# fastapi==0.65.1

import time
import uvicorn
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel


app = FastAPI()


class Item(BaseModel):
    name: str
    price: float
    is_offer: Optional[bool] = None


@app.get("/")
def read_root():
    return {"hello": "world"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
    return {"item_id": item_id, "q": q}


@app.put("/items/{item_id}")
async def read_item(item_id: int, item: Item):
    return {"item_name": item.name, "item_id": item_id}


if __name__ == '__main__':   
     # 使用uvicorn启动服务,指定端口8099
	 uvicorn.run(app='fastapi_demo:app', host="0.0.0.0", port=8099, reload=True, debug=True)    

代码即文档,压根不用写接口文档。试问:是不是很爽?

类型检查

python是弱类型的语言,直到python 3.5 才加入类型系统。而我们在做接口参数校验的时候,必定要写大量代码验证参数是否为空,类型是否正确。

  • flask
import json
from flask import Flask
from flask import jsonify
from flask import request

app = Flask(__name__)

@app.route('/items/<int:item_id>', methods=['GET', 'POST', "PUT", "DELETE"])
def update_item(item_id):
    if request.method == "PUT":
        try:
            data = json.loads(request.get_data())
        except json.decoder.JSONDecodeError:
            return jsonify({"code":10101, "msg": "format error"})
        try:
            name = data["name"]
            price = data["price"]
            is_offer = data["is_offer"]
        except KeyError:
            return jsonify({"code": 10102, "msg": "key null"})

        if not isinstance(name, str):
            return jsonify({"code": 10103, "msg": "name not is str"})

        if not isinstance(price, float):
            return jsonify({"code": 10104, "msg": "price not is float"})

        if not isinstance(is_offer, bool):
            return jsonify({"code": 10105, "msg": "is_offer not is bool"})

        return jsonify({"item_name": name, "item_id": item_id})

在flask中为了验证参数是否为空,以及参数的类型,必须要写大量的异常和类型判断的代码。

  • fastapi

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    price: float
    is_offer: Optional[bool] = None


@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
    return {"item_name": item.name, "item_id": item_id}

fastapi 通过 pydantic 检查参数类型,有一点像go的结构体,简直不要太简单。

Ps:Pydantic库简介:Python笔记:Pydantic库简介_codename_cys的博客-CSDN博客_pydantic

蓝图APIRouter

我们都知道在大型的应用程序或者 web api 中, 我们很少在一个文件中写入多个路由,将所有的请求方法写在同一个处理文件下面的话,会导致我们的代码显得很没有逻辑性,这样既不利于程序的扩展,也不利于程序日后的维护。在 Flask 中,我们一般用蓝图 Blueprint 来处理,那么在FastApi 中如何处理呢?

当然可以,在 FastApi 中使用 APIRouter 处理这种多程序分类,即类似 Flask 中的蓝图。可以直接参考:更大的应用 - 多个文件 - FastAPI

假设我们的系统有2个模块:users和items

  • users模块

假设专门用于处理用户的文件是的子模块/app/routers/users.py

您希望将与用户相关的路径操作与其余代码分开,使其看起来简洁明了。

可以使用来为该模块创建路径操作 APIRouter。

./route/users.py

from fastapi import APIRouter

router = APIRouter()


@router.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]


@router.get("/users/me", tags=["users"])
async def read_user_me():
    return {"username": "fakecurrentuser"}


@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
    return {"username": username}

web 服务中还有另外一个应用模块,items。

同样的通过APIRouter来对其路由进行注册,代码如下:./router/items.py

from typing import Optional
from fastapi import APIRouter, Depends, HTTPException

router = APIRouter(
    prefix="/items",
    tags=["items"],
    responses={403: {"description": "Operation forbidden"}}
)

@router.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
    if item_id != 123:
        raise HTTPException(status_code=403)
    return {"item_id": item_id, "q": q}

@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id != "123":
        raise HTTPException(status_code=404, detail="Item not found")
    return {"name": "rongsong", "item_id": item_id}

这样就将两个功能模块 item, user 给分离开来了,后期我们想更新或扩展 user 模块的功能,并不会对 item 造成影响!

上面便是 APIRouter 最最基础也是最强大之处,还有其他功能吗?当然有!

自定义的tags与responses

细心的朋友应该发现了,在上述 item.py 中实例化 router的时候,传了好几个参数

一起来看看分别代表什么含义!

prefix 参数,路由的前缀

tags 将应用于特定路径操作的内容

responses 指特定于该路径下的响应内容,如上述便指定 404 的返回信息

注册 APIRouter

最后一个步骤就是要将我们的 APIRouter 注册到核心对象上去

和之前我们创建主文件一样导入 FastApi,以及声明的 APIRouter 实例。

main.py

import uvicorn
from fastapi import Depends, FastAPI
from router import items, users

app = FastAPI()

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


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}


if __name__ == '__main__':   
    # 使用uvicorn启动服务,端口8099
    uvicorn.run(app='main:app', host="0.0.0.0", port=8099, reload=True, debug=True)  

其中 include_router() 函数就是上面说的注册。这时候就完成了,使用该 app 来启动服务即可

更多的内容可以参考官网教程(中文版)FastAPI

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rs勿忘初心

您的鼓励将是我的最大创动原动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值