QZQ的小世界!

  • 首页
你好!
这里是QZQ的博客站!
  1. 首页
  2. 未分类
  3. 正文

Fastapi-超快 api 构建

2025年4月4日 89点热度 0人点赞 0条评论

FastAPI (tiangolo.com)

Pydantic

pydantic是一个数据验证的库,FastAPI使用它来做模型校验。

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

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

app = FastAPI()

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

Item是个入参模型,它的name必须str类型,price必须float类型,is_offer是可选的,可以为bool类型或不传。像下图这样是可以通过验证的。

PUT <http://127.0.0.1:8000/items/6>
{
    "name": "dongfanger",
    "price": 2.3,
    "is_offer":  true
}

请求体

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


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item

继承于BaseModel来自定义Model,FastAPI会自动转换为JSON。

参数设置

路径参数

把路径参数传递给函数,可以指定参数类型:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

效果是访问 http://127.0.0.1:8000/items/foo 会返回{"item_id":"foo"}。指定了Python类型后,FastAPI会强制检查,比如传str会报错,传float也会报错

匹配先后顺序

代码定义的先后顺序会决定匹配结果,比如正常来说,下面的/users/me会返回{"user_id": "the current user"}:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

假如这2个path定义顺序反过来,那么/users/me就会匹配到/users/{user_id}而返回{"user_id": me}了。

枚举路径

借助于Enun类,可以实现枚举路径:

from enum import Enum
from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

这样在docs界面就可以看到一个可以选择的参数输入口了

path匹配

FastAPI提供了一个path类型,可以用来对文件路径进行格式匹配:

from fastapi import FastAPI

app = FastAPI()

@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}

路径参数数字校验

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000),
    q: str,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

路径参数永远都是必填的,因为它是url一部分。...表示必填,就算设置为None也没有用,仍然是必填。

  • ge表示大于等于,greater equal。

  • le表示小于等于,less equal。

  • gt表示大于,greater than。

  • lt表示小于,less than。

查询参数

查询参数是跟在路径参数后面,用?分隔用&连接的参数,比如http://127.0.0.1:8000/items/?skip=0&limit=10。

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]

参数是可选的并且设置了默认值:limit: int = 10

参数是可选的,无默认值:limit: Optional[int] = None

是否可选是由None来决定的,而Optional只是为编译器提供支持,跟FastAPI没有关系。

参数是必填的:limit: int

Query参数校验

Query Parameters and String Validations - FastAPI (tiangolo.com)

FastAPI提供了Query来支持对入参的字符串校验,比如最小长度和最大长度,甚至其中也能包含正则表达式:regex="^fixedquery$"。:

from typing import Optional
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Query的第一个参数可以为该参数指定一个默认值,此处传None即为不指定默认值。而如果传 ... 的话,则意味必须填写这个参数。

实战

利用fastapi返回文件

from starlette.responses import FileResponse
from fastapi import FastAPI

app = FastAPI()

async def get_transfer(file_path):
    if not os.path.exists(filepath):
        return 'no such files!'
    headers = {
        "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    }
    return FileResponse(filepath, filename='{}.csv'.format(file_name), headers=headers)

Fastapi文档的编写

fastapi提供两种api文档,:

  • 交互式API文档:

在浏览器中请求 http://127.0.0.1:8000/docs即可(由 Swagger UI 提供)

  • 备用API文档

在浏览器中请求 http://127.0.0.1:8000/redoc,显示备用API文档(由 ReDoc提供)

FastAPI接口文档注释

  • title 标题

  • description 描述,用以详细介绍api

  • summary 注释,用以简单介绍api

  • tags 标签,用以将api分类排列

from fastapi import FastAPI
app = FastAPI(title='第一个Fast API应用程序', description='整体描述')
@app.get(path='/', summary='接口注释', description='接口描述', tags=['Root'])
async def read_root():    
    return {"Hello": "World"}

显示效果如下:

Untitled.png

也可以不使用summary进行接口注释,用多行注释取而代之,格式为markdown

from fastapi import FastAPI
app = FastAPI()
@app.get(path='/items/{item_id}', summary='接口注释', tags=['Items'])
async def read_item(item_id: int, q: str = None):    
    '''    
    项目    
    - param item_id: 项目ID    
    - param q: 查询参数    
    - return: 以给定项目ID和参数为数据的对象,字段为item_id,q    
    '''    
    return {"item_id": item_id, "q": q}

显示效果如下:

Untitled.png

其他零碎的整理

fastapi传输文件

Content-Type用来定义用户的浏览器或其他设备如何显示将要加载的数据,或将要如何处理将要加载的数据。

Content-Type 一般以下面的形式出现:

Content-Type:[type]/[subtype];parameter

type 有以下的类型:

  • Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的

  • Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据

  • Application:用于传输应用程序数据或者二进制数据

  • Message:用于包装一个E-mail消息

  • Image:用于传输静态图片数据

  • Audio:用于传输音频或者音声数据

  • Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式

subtype 用于指定type的详细形式。下面是常用到MIME类型:

  • text/html(HTML 文档)

  • text/plain(纯文本)

  • text/css(CSS 样式表)

  • image/gif(GIF 图像)

  • image/jpeg(JPG 图像)

  • application/x-javascript(JavaScript 脚本)

  • application/x-shockwave-flash(Flash)

  • application/x- www-form-urlencoded(使用 HTTP 的 POST方法提交的表单)

  • multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)

因此最开始遇到的那个问题是因为浏览器没有正确处理excel文件,因为Content-Type为text/plain。手动为接口添加能处理excel文件的Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

import fastapi import FastApi
From starlette.responses import FileResponse

app = FastApi()

@app.get("/File")
async def get_file():
    filepath = "./data/demo.xlsx"
    filename = "demo.xlsx"
    headers = {
        "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    }
    return FileResponse(filepath, filename=filename, headers=headers)

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000, debug=True)

更多拓展名可以看这个网站 MIME 参考手册 (w3school.com.cn)

[文章导入自 http://qzq-go.notion.site/683d71c90aac436dbdfef9c3ad31df48 访问原文获取高清图片]

本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: IT技术 Python Python库介绍 Python第三方库
最后更新:2025年4月3日

QZQ

一只涉猎广泛的技术爱好者,绝赞养猫中~

点赞
< 上一篇
下一篇 >

归档

  • 2025 年 4 月
  • 2025 年 3 月
  • 2025 年 2 月
  • 2025 年 1 月
  • 2024 年 12 月
  • 2024 年 11 月

分类

  • 技术
  • 未分类

COPYRIGHT © 2024 QZQ的小世界!. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang