写在前面

本文为学习官网教程的总结和概括,并结合实际应用给出一些例子,建议结合官网教程阅读。

本小节主要是请求参数的使用方法,下一小节是响应模型和其他。


快速开始

1. 创建virtualenv环境

virtualenv venv
source venv/bin/activate

2. 安装所需依赖

  • 安装所有的可选依赖及对应功能(开发环境推荐
pip install "fastapi[all]"
  • 选装依赖(生产环境推荐) 安装fastapi并且安装uvicorn来作为服务器:
pip install fastapi
pip install "uvicorn[standard]" 

3. 基本代码

新建main.py,复制以下内容

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "你好,世界"}

4.运行服务

  • 方式一:终端直接运行

uvicorn main:app 命令含义如下:

main:main.py 文件(一个 Python「模块」)。
app:在 main.py 文件中通过 app = FastAPI() 创建的对象。
--reload:让服务器在更新代码后重新启动。仅在开发时使用该选项。

uvicorn main:app --reload
  • 方式二:在main文件中添加运行代码

修改main.py文件如下,设置好基本参数hostport

from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "你好,世界"}
    
if __name__ == '__main__':
    uvicorn.run(app=app,host="127.0.0.1",port=8000)
    # 使用reload可以在修改代码时自动刷新,注意必须要 `main:app` 这样配置,其中main是文件名,app是实例化FastAPI的应用名称。
    # uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True) 

在终端运行

python main.py

文档

fastapi自动生成文档,可以通过http://127.0.0.1:8000/docs访问可交互式文档,也可以通过http://127.0.0.1:8000/redoc访问另外一个类型的文档。


基本HTTP请求参数

基本HTTP请求参数包括:路径参数查询参数请求体

requests.post('http://example.com/article/123456/?page=10&limit=20',data={'a':1,'b':2})

在上述例子中,123456为路径参数,pagelimit为查询参数,data为请求体。

路径参数

以下例子为未指定类型的路径参数请求方法。

from fastapi import FastAPI
import uvicorn

app = FastAPI()


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

可以通过请求http://127.0.0.1:8000/items/foo获得如下结果。
{"item_id":"foo"}

有类型的路径参数

可以使用标准的 Python 类型标注为函数中的路径参数声明类型。

from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

数据转换和数据校验

当指定参数类型,fastapi会自动完成数据类型的转换,如果不能转换,也会自动校验并指出了校验未通过的具体原因。

预设值(枚举,为参数提供选项)

导入 Enum 并创建一个继承自 strEnum 的子类。

通过从 str 继承,API 文档将能够知道这些值必须为 string 类型并且能够正确地展示出来。

然后创建具有固定值的类属性,这些固定值将是可用的有效值:

from enum import Enum

from fastapi import FastAPI
import uvicorn


class ModelName(str, Enum):
    student1 = "张三"
    student2 = "李四"
    student3 = "王五"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.student1:
        return {"model_name": model_name, "message": "这是张三!"}

    if model_name.value == "李四":
        return {"model_name": model_name, "message": "这是李四"}

    return {"model_name": model_name, "message": "是王五呀"}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

包含路径的路径参数

你可以使用直接来自 Starlette 的选项来声明一个包含路径的路径参数:

/files/{file_path:path}

比如可以通过以下代码:

from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

查询参数

声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数

from fastapi import FastAPI
import uvicorn

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

查询字符串是键值对的集合,这些键值对位于 URL 的 ? 之后,并以 & 符号分隔。

例如,在以下 url 中:

http://127.0.0.1:8000/items/?skip=0&limit=10

查询参数为:

- skip:对应的值为 0
- limit:对应的值为 10

可选参数

通过同样的方式,你可以将它们的默认值设置为 None 来声明可选查询参数:

from typing import Union

from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: str, q: Union[str, None] = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

在这个例子中,函数参数 q 将是可选的,并且默认值为 None

查询参数类型转换

你还可以声明 bool 类型,1 True true on yes 或任何其他的变体形式(大写,首字母大写等等),将被自动转换为 True 。对于值为 False 的情况也是一样的。

必须查询参数

  • 当你为非路径参数声明了默认值时(目前而言,我们所知道的仅有查询参数),则该参数不是必需的。
  • 如果你不想添加一个特定的值,而只是想使该参数成为可选的,则将默认值设置为 None
  • 但当你想让一个查询参数成为必需的,不声明任何默认值就可以。

请求体

我们使用 Pydantic 模型来声明请求体,并能够获得它们所具有的所有能力和优点。

from typing import Union,List

from fastapi import FastAPI
import uvicorn
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

如果你不想使用 Pydantic 模型,你还可以使用 Body 参数。

from typing import Union

from fastapi import Body, FastAPI
import uvicorn
from pydantic import BaseModel

app = FastAPI()


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


class User(BaseModel):
    username: str
    full_name: Union[str, None] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User, importance: int = Body()):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

这个例子中, importance 字段用 Body 指示 FastAPI 将其作为请求体的另一个键进行处理。

总结

  • 如果在路径中也声明了该参数,它将被用作路径参数。
  • 如果参数属于单一类型(比如 int、float、str、bool 等)它将被解释为查询参数。
  • 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体。

查询参数和字符串校验

from typing import Union

from fastapi import FastAPI, Query
import uvicorn

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=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
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)
  • 使用 Query 指示参数为查询参数,并通过这个方法进行约束,比如 regex 参数为正则表达式。

声明为必需参数

  • 不指定 default 参数,则声明为必须参数。
  • 使用省略号(...)声明必需参数
from fastapi import FastAPI, Query
import uvicorn

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(default=..., min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

如果你之前没见过 ... 这种用法:它是一个特殊的单独值,它是 Python 的一部分并且被称为「省略号」。 Pydantic 和 FastAPI 使用它来显式的声明需要一个值。

  • 使用Pydantic中的Required代替省略号(...
from fastapi import FastAPI, Query
import uvicorn
from pydantic import Required

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(default=Required, min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

查询参数列表/多个值

from typing import List, Union

from fastapi import FastAPI, Query
import uvicorn

app = FastAPI()

@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
    query_items = {"q": q}
    return query_items
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

可以用以下网址请求,那么q获取到的是一个列表。

http://localhost:8000/items/?q=foo&q=bar

声明更多元数据

from typing import List, Union

from fastapi import FastAPI, Query
import uvicorn

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        title="q参数的标题", #设置标题
        description="这是q查询参数", #查询参数的描述
        alias="item-query", # 可以用来重命名传参名称,一般可以用来避免参数在python中不规范,或者前端特别要求。
        min_length=3,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

路径参数和数值校验

与使用 Query 为查询参数声明更多的校验和元数据的方式相同,你也可以使用 Path 为路径参数声明相同类型的校验和元数据。

from typing import Union

from fastapi import FastAPI, Path, Query
import uvicorn

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: int = Path(title="The ID of the item to get"),
    q: Union[str, None] = Query(default=None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

数值校验

  • ge : 大于或等于
  • gt : 大于
  • le : 小于或等于
  • lt : 小于

你可以像定义 Query 参数和 Path 参数一样来定义 Cookie 参数。

from typing import Union

from fastapi import Cookie, FastAPI
import uvicorn

app = FastAPI()


@app.get("/items/")
async def read_items(ads_id: Union[str, None] = Cookie(default=None)):
    return {"ads_id": ads_id}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

因为自带的swagger测试不了,下面提供requests中的cookiejar方法的代码。

import requests

# 创建会话
s = requests.Session()
# 创建一个Cookie Jar对象
jar = requests.cookies.RequestsCookieJar()
# 向Cookie Jar对象中添加cookie值
jar.set("ads_id", "my_test_cookie")
# 把cookies追加到Session中
s.cookies.update(jar)

r = s.get('https://test.percy.fun/items/')
print(r.json())

Header 参数

你可以使用定义 Query, PathCookie 参数一样的方法定义 Header 参数。

from typing import Union

from fastapi import FastAPI, Header
import uvicorn

app = FastAPI()


@app.get("/items/")
async def read_items(user_agent: Union[str, None] = Header(default=None)):
    return {"User-Agent": user_agent}
    
if __name__ == '__main__':
    uvicorn.run(app="main:app",host="0.0.0.0",port=8000,reload=True)

自动转换

大多数标准的headers用 "连字符" 分隔,也称为 "减号" (-)。

但是像 user-agent 这样的变量在Python中是无效的。

因此, 默认情况下, Header 将把参数名称的字符从下划线 (_) 转换为连字符 (-) 来提取并记录 headers.

文章作者: PercyC
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 percy家园
Python python pythonweb
喜欢就支持一下吧