FastAPI简介
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架。
FastAPI官方文档:fastapi.tiangolo.com/zh/
FastAPI特点:
-
性能优越
与Django、Flask不同,FastAPI属于异步框架。在编写函数时加上
async
,就可以实现异步响应功能。python对于异步有较好的支持是从python3.6开始的,所以使用FastAPI框架应该使用python3.6及以上的版本。 -
开发效率高
提高功能开发速度约 200% 至 300%,官方数据。
-
减少40%人为bug
业务开发方面产生的bug,由于他的明确的错误提示、标准的开发准则等。
-
易学易用
官方文档友好、易懂、详细。
-
精简编码,代码重复率低。
-
自带API交互文档,开发成果随时交付。
/docs
、/redoc
-
API开发标准化
适合RESTful API风格开发。
FastAPI 相关库
1.Starlette、Pydantic库:
python3.5以上类型提示 type hints :
Python 是动态类型语言,运行时不需要指定变量类型。这一点是不变的,但是2015年9月Python 3.5 引入了一个类型系统,允许开发者指定变量类型。它的主要作用是方便开发,供IDE 和各种开发工具使用,对代码运行不产生影响,运行时会过滤类型信息。
def get_user_info(name: str, age: int, status: bool):
print(name, age, status)
get_user_info(name="林一峰", age=[], status="wang")
Pydantic 是一个基于python类型提示来定义验证,序列化和文档库,FastAPI用它来做数据模型校验。
Starlette 是一种轻量级的ASGI库,特别适合用来构建高性能的 asyncio 服务。
- fastapi、uvicorn库
-
fastapi FastAPI核心库,python web框架
-
uvicorn 可安装的ASGI框架,用于加载和提供应用程序的服务器
最简单的开始
安装:
pip install fastapi
pip install uvicorn
最简单的应用:
# step1: 导入核心库
from fastapi import FastAPI
import uvicorn
app = FastAPI() # step2: 创建一个 FastAPI 实例
@app.get("/") # step3: 创建一个路径操作,定义一个路径操作装饰器
async def home(): # step4: 定义路径操作函数
return {"message": "welcome!"} # step5: 返回内容
if __name__ == '__main__':
# step6: 运行开发服务器
uvicorn.run(app="main:app", host='127.0.0.1', port=8082, reload=True)
自带API交互文档:
通过访问http://127.0.0.1:8082/docs
免费获得 Swagger UI
通过访问 http://127.0.0.1:8082/redoc
免费获得 ReDoc
路径参数
-
路径参数
@app.get("/items/{item_id}") async def read_item(item_id): return {"item_id": item_id}
路径参数
item_id
的值将作为参数item_id
传递给你的函数,访问http://127.0.0.1:8082/items/1
-
有类型的路径参数
@app.get("/items/{item_id}") async def read_item(item_id: int): # int型 return {"item_id": item_id}
item_id
被声明为int
类型 -
数据转换
访问
http://127.0.0.1:8000/items/3
,FastAPI通过上面的类型声明提供了对请求的自动解析,函数接收到的不是字符串3,而是int型的3。 -
数据校验
访问
http://127.0.0.1:8000/items/foo
,会返回明确的错误提示。
查询参数
-
查询参数
声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数。
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]
查询字符串是键值对的集合,这些键值对位于 URL 的
?
之后,并以&
符号分隔访问:
http://127.0.0.1:8000/items/?skip=0&limit=10
,查询参数为skip
、limit
-
可选参数
默认值设置为
None
来声明可选查询参数。from typing import Union @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}
函数参数
q
将是可选的,并且默认值为None
-
查询参数类型转换
from typing import Union async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False): item = {"item_id": item_id} if q: item.update({"q": q}) ' if not short: item.update( {"description": "This is an amazing item that has a long description"} ) return item
以下几种方式任何其他的变体形式(大写,首字母大写等等),你的函数接收的
short
参数都会是布尔值True
,它们将被自动转换为布尔类型。http://127.0.0.1:8000/items/foo?short=1 http://127.0.0.1:8000/items/foo?short=True http://127.0.0.1:8000/items/foo?short=true http://127.0.0.1:8000/items/foo?short=on http://127.0.0.1:8000/items/foo?short=yes
-
必需查询参数
如果你想使该参数成为可选的,则将默认值设置为
None
。但当你想让一个查询参数成为必需的,不声明任何默认值就可以。
请求体
-
请求体
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。
我们使用Pydantic模型来声明请求体。
不能使用
GET
操作(HTTP 方法)发送请求体,要发送数据,你必须使用下列方法之一:POST
(较常见)、PUT
、DELETE
或PATCH
。from typing import Union from fastapi import FastAPI from pydantic import BaseModel # step1: 导入Pydantic的BaseModel # step2: 创建数据模型 class Goods(BaseModel): name: str description: Union[str, None] = None price: float tax: Union[float, None] = None app = FastAPI() @app.post("/goods/") async def create_goods(goods: Goods): # step3: 声明为参数 return goods
传入参数:
{ "name": "Foo", "description": "An optional description", "price": 45.2, "tax": 3.5 }
或:
{ "name": "Foo", "price": 45.2 }
-
请求体 + 路径参数 + 查询参数
还可以同时声明请求体、路径参数和查询参数。FastAPI会识别它们中的每一个,并从正确的位置获取数据。
class Goods(BaseModel): name: str description: Union[str, None] = None price: float tax: Union[float, None] = None app = FastAPI() @app.post("/goods/info/{goods_id}") async def create_goods_info(goods_id:int,goods: Goods,q:Union[str,None]=None): result = {"goods_id": goods_id, **goods.dict()} if q: result.update({"q": q}) return result
函数参数将依次按如下规则进行识别:
- 如果在路径中也声明了该参数,它将被用作路径参数。
- 如果参数属于单一类型(比如
int
、float
、str
、bool
等)它将被解释为查询参数。 - 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体。
查询参数和字符串校验
-
额外的校验
添加约束条件:即使
q
是可选的,但只要提供了该参数,则该参数值不能超过50个字符的长度。from typing import Union from fastapi import FastAPI, Query # step1: 导入Query app = FastAPI() @app.get("/items/") async def read_items(q: Union[str, None] = Query(default=None, max_length=50)): # 将 Query 用作查询参数的默认值,并将它的 max_length 参数设置为 50 results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) return results
路径参数和数值校验
与使用 Query
为查询参数声明更多的校验和元数据的方式相同,你也可以使用 Path
为路径参数声明相同类型的校验和元数据。
from fastapi import FastAPI, Path # 导入Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(item_id: int = Path(title="The ID of the item to get", ge=1) ):
# 添加 ge=1 后,item_id 将必须是一个大于(greater than)或等于(equal)1 的整数
results = {"item_id": item_id}
return results
同样的规则适用于:
- gt: 大于(
g
reatert
han) - le: 小于等于(
l
ess than ore
qual)
Query
、Path
以及你后面会看到的其他类继承自一个共同的 Param
类,它们都共享相同的所有你已看到并用于添加额外校验和元数据的参数。
响应模型
可以在任意的路径操作中使用 response_model
参数来声明用于响应的模型。
from typing import Any, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
full_name: Union[str, None] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user