
【FastAPI】从0开始学FastAPI!一篇搞懂!
一、什么是FastAPI?
FastAPI是一个现代、快速(高性能)的python web框架,基于标准的python类型提示,使用python3.6+构建的web框架。
FastAPI的架构为RESTful风格,RESTful是一种网络应用程序的设计风格和开发方式,其特点为每一个URI代表一种资源,客户端通过GET、POST、PUT、DELETE等动作,对服务器端资源进行操作。
(一)环境准备
1.安装FastAPI:pip install fastapi
(交互文档需要访问外部资源,行内在1.0.3版本中将外部资源转为行内资源,若行内网络使用请指定版本1.0.3)
2.安装ASGI服务:pip install uvicorn

(二)入门示例
1. 新建一个main.py文件,编写如下:
from fastapi import FastAPIapp = FastAPI()@app.get('/')def root():return {'message': 'Hello World'}
2. 启动服务
命令:uvicorn main:app --reload
² main:文件main.py(python模块)
² app:在模块中app=FastAPI()行中创建的对象
² --reload:代码更改后自动重启服务(上线时该参数值不能为true,降低性能)
启动服务后终端将会看到如下输出:

3. 访问服务
启动服务后,使用浏览器访问127.0.0.1:8000,
可以得到{"Hello":"World"} ,说明环境安装成功。

4. API交互文档
启动服务后,FastAPI会自动给生成两个交互文档:
SwaggerUI:http://127.0.0.1:8000/docs
ReDoc:http://127.0.0.1:8000/redoc
http://127.0.0.1:8000/openapi.json

5. 查看openapi.json
http://127.0.0.1:8000/openapi.json

6. 本地部署
命令:uvicorn main:app --host 0.0.0.0 --port 8000
² main:启动服务的py文件名
² app:服务对象名
² --host:IP地址
² --port:端口
本地部署后,可通过外部访问本地启动服务。

(三)入门示例了解FastAPI结构
from fastapi import FastAPIapp = FastAPI()@app.get('/')def root():return {'message': 'Hello World'}
1. 导入FastAPI
from fastapi import FastAPI
2. 创建一个app实例
app = FastAPI()
3. 编写路径操作装饰器
@app.get('/')
(1)使用get请求,也可使用其他请求方法的装饰器
@app.post()
@app.put()
@app.delete()
@app.options()
@app.head()
@app.patch()
@app.trace()
(2)路径('/') 自定义
4. 定义路径操作函数
def root():return {'message': 'Hello World'}
(1)python函数;
(2)当FastAPI接收一个使用GET方法访问路径为/的请求时这个函数会被调用;
(3)此处的返回值可以是:字典,列表,单独的值:比如str,int,Pydantic模型,自动转换为JSON的对象和模型。
5. 运行开发服务
uvicorn main:app
此处可以执行要运行的服务器IP和端口号,默认IP :127.0.0.1,端口:8000
uvicorn main:app --host 127.0.0.1 --port 8080
二、uvicorn启动方式
(一)使用命令行运行
按入门示例的方式,在py文件所在目录下的命令行中运行。
(二)使用uvicorn.run()
| 参数 | 作用 |
| app | 运行的 py 文件:FastAPI 实例对象 |
| host | 访问url,默认 127.0.0.1 |
| port | 访问端口,默认 8000 |
| reload | 热更新,为true时有内容修改自动重启服务器 |
| debug | 同reload |
| reload_dirs | 设置需要 reload 的目录,List[str] 类型 |
| log_level | 设置日志级别,默认 info |
三、接口文档注释
(一)注释类型
1.title标题
2.description描述
3.summary注释
4.tags标签
示例:
from fastapi import FastAPIapp = FastAPI(title='测试api应用程序', description='整体描述')@app.get(path='/', summary='接口注释', description='接口描述', tags= ['Root'])def read_root():return {"Hello": "World"}
(二)多行注释
1.示例1
@app.get("/list/query1")def list_query1(page:int = 1,limit:int = 10):"""多行备注- param page: 页数- param limit: 每页个数- return: 以给定页数和每页个数为数据的对象,字段为page,limit"""return
2.效果1

3.示例2
@app.get("/list/query2")def list_query2(page:int = 1,limit :int = None):"""多行备注| *参数名称* | *参数类型* | *默认值* | *释义* || :--: | :--: | :--: | :--: || page | int | 1 | 页数|| limit | int | none | 每页个数|| *返回值类型* | *释义* || :--: | :--: || page | 页数 || limit | 每页个数 |"""return
4.效果2

(三)路径/查询参数/请求体注释
1.示例1
from fastapi import FastAPI,Queryfrom .demo_data import *app = FastAPI()@app.get('/customer_level/{level}')def read_enum1(Level: Cust_level = Query(Cust_level.Level1,alias="零售客户等级")):return {'level_res': Level}
2.效果1

3.示例2
from fastapi import FastAPI,Queryapp = FastAPI()@app.get("/list/query3")def list_query3(page:int = Query('1',alias='页数'),limit :int = Query(...,alias='每页个数')):return{"page":page,"limit":limit}
4.效果2

5.示例3
from fastapi import FastAPI,Bodyapp = FastAPI()class Item2(BaseModel):name:str = Body(default="张三",alias="姓名")description:str=Body(default="",alias="描述")price:float = Body(default='',alias="分数",gt=5.0,lt=10.5)tax:float=None@app04.post('def create_item3(item:Item2 ):return item
6.效果3

四、声明路径参数
(一)路径参数
1.代码
@app.get("/items/{item_id}")def read_items(item_id):return {"item_id": item_id}
2.代码运行之后,路径参数item_id的值会作为read_items函数参数item_id的值
(二)指定数据类型的路径参数
1.代码
@app.get("/item1/{item_id}")def read_int(item_id:int): #以整数类型接受参数return {"item_id": item_id}@app.get("/item2/{item_id}")def read_str(item_id:str): #以字符串类型接受参数return {"item_id": item_id}
2.说明
如果访问链接时提供的参数类型不对,FastAPI还会自动进行数据校验。类型声明有int、str,float,bool或者其他更复杂的类型。
(三)枚举型的路径参数
1.代码
from enum import Enumfrom fastapi import FastAPIclass cust_level(str, Enum):level1 = '钻石'level2 = '私人银行'level3 = '金葵花'level4 = '金卡'level5 = '普卡'app = FastAPI()@app.get('/customer_level/{level}')def read_enum(level: cust_level):return {'level_res': level}
2.运行效果

3.说明
1. 创建一个继承str和Enum的类,并创建几个类属性,这些类属性的值将是可用的有效值。
2. 声明路径参数。路径参数level的值将传递给函数read_enum的参数Level。且这个参数的取值范围只能是Cust_level类中类属性的值。
3. read_enum函数中可以调用cust_level类的类属性。调用方式:Cust_info.Name
(四) 路径类型的路径参数
1.代码
@app.get("/files/{file_path:path}") # :path 代表任意路径def read_file(file_path: str):return {"file_path": file_path}
2.说明
路径参数时请求路径的一部分,如果不传,请求路径不完整则会报错404。
五、声明查询参数
(一)基础概念
1.查询参数就是在URL之后的key-value键值对每对键值对用&分割开来。
示例:
http://127.0.0.1:8000/items/?page=1&limit=10
该请求的查询参数有两个,page和limit,值分别为1,10。
2.当声明不属于路径参数的其他函数参数时,它们将自动解释为查询参数;查询参数可以是非必填,也可具有默认值。
3.查询参数也是URL的一部分,所以 “本质上” 它们都是字符串。
但当需要使用Python类型来声明query参数时(例如用int),他们就会被转换为相应的类型并且依据这个类型来验证传入参数。
(二) 设置参数默认值
1.代码
@app.get("/list/query1")def list_query1(page: int = 1, limit: int = 10):return {"page": page, "limit": limit}
2.调用方法
ip:port/list/query?page=1&limit=3ip:port/list/query # 使用默认值 page=1,limit=10ip:port/list/query?page=&limit= # 报错,报错如下爱徒

(三)设置为可选参数
声明可选的查询参数,只需要将他们的默认值设置为None即可。
1.代码
@app.get("/list/query2")def list_query2(page:int = None):return {"page": page}
2.调用方法
ip:port/list/testip:port/list/test?page=3
(四)设置为枚举类型参数
1.代码
from fastapi import APIRouter,Queryfrom enum import Enum//自定义枚举类class Cust_level(str, Enum):Level1 = '钻石'Level2 = '私人银行'Level3 = '金葵花'Level4 = '金卡'Level5 = '普卡'app03 = APIRouter()@app03.get("/list/query4")def list_query4(name:str = Query(...,alias='姓名'),level :Cust_level = Cust_level.Level1 ):return{"name":name,"level":level}
2.效果

5. Query简单介绍
Query库,可以提供对查询参数进行额外校验的功能。
1. Query函数的入参值说明
def Query( # noqa: N802default: Any = Undefined, //参数类型,传...表示为必传,传None表示为可选*,alias: Optional[str] = None, //别名title: Optional[str] = None,description: Optional[str] = None, //描述gt: Optional[float] = None,ge: Optional[float] = None,lt: Optional[float] = None,le: Optional[float] = None,min_length: Optional[int] = None, //最小长度max_length: Optional[int] = None, //最大长度regex: Optional[str] = None, //正则表达式校验example: Any = Undefined,examples: Optional[Dict[str, Any]] = None,deprecated: Optional[bool] = None,include_in_schema: bool = True,**extra: Any,) -> Any:
2. 最小长度、最大长度、正则表达式校验
from fastapi import FastAPI, Queryapp = FastAPI()@app.get('/items/')def read_items(q: str = Query(None, min_length=1, max_length=20, regex='^str$') ):results = {'items': [{'item_id': 'Foo'}, {'item_id': 'Bar'}]}if q:results.update({'q': q})return results
这个特定的正则表达式检查接收到的参数值:
^: 表示字符串str前面没有字符
str: 匹配 str字符串
$: 表示字符串str后面不匹配任何字符
3. 数值校验
(1)大于等于ge,只能比较整数,例如大于等于1。
from fastapi import FastAPI, Pathapp = FastAPI()@app.get('/items/{item_id}')def read_items(*, item_id: int = Path(..., ge=1), q: str ):results = {'item_id': item_id}if q:results.update({'q': q})return results
(2)小于等于le,只能比较整数,例如小于等于1000。
from fastapi import FastAPI, Pathapp = FastAPI()@app.get('/items/{item_id}')async def read_items(*,*,item_id: int = Path(..., gt=0, le=1000), q: str ):results = {'item_id': item_id}if q:results.update({'q': q})return results
(3)大于gt, 小于lt,可以比较浮点数和整数。
from fastapi import FastAPI, Path, Queryapp = FastAPI()@app.get('/items/{item_id}')def read_items(*, item_id: int = Path(..., ge=0, le=1000),item_id: int = Path(..., ge=0, le=1000),q: str,size: float = Query(..., gt=0, lt=10.5) ):results = {'item_id': item_id}if q:results.update({'q': q})return results
六、请求体
(一) 基础概念
请求体是客户端发送到API的数据,响应体是API发送给客户端的数据。
定义请求体,一般需要使用Pydantic模型,发送请求体数据,常用以下几种方法:POST(最常见)、PUT、DELETE、PATCH。
(二)不使用Pydantic模型
1.代码
@app.post("/bodyapi1")def read_item1(item: dict):return {"item": item}
指定查询参数的类型为dict
2.效果
{
"item":1234
}

(三)使用Pydantic模型
1. 如何定义请求体
A:从pydantic中导入BaseModel
from pydantic import BaseModel
B:创建请求体数据模型
声明请求体数据模型为一个类,且该类继承 BaseModel。所有的属性都用标准Python类。
和查询参数一样:数据类型的属性如果不是必须的话,可以拥有一个默认值或者是可选None,否则,该属性就是必须的。
from pydantic import BaseModelclass Item(BaseModel): //自定义一个pydantic模型name: strdescription: str = Noneprice: floattax: float = None
所以访问链接的时候传入的请求体可以是下面两种:
{'name': 'Foo','description': 'An optional description','price': 45.2,'tax': 3.5}
另一种可以不传递默认值或者是可选值:
{'name': 'Foo','price': 45.2}
C: 属性类型自动转换为相应的请求类型
![]()

D: 验证数据失败,会返回清晰的报错


2.使用数据模型
A:将模型定义为参数
将上面定义的模型添加到你的路径操作中,类比定义Path和Query参数的方式,声明参数的类型创建的模型Item:
from fastapi import FastAPIfrom pydantic import BaseModelclass Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = Noneapp = FastAPI()@app.post('/body/')def create_item(item: Item):return item
B:在函数内部,可以直接访问模型对象的所有属性
from fastapi import FastAPIfrom pydantic import BaseModelclass Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = Noneapp = FastAPI()@app.post('/items/')async def create_item(item: Item):return Item.name
关注:
可以同时定义路径参数、查询参数、请求体参数,如果path中声明了某个参数,那么这个参数将作为路径参数是使用;如果参数是单一类型(例如int,float,str,str,bool等),它将被解释为query参数。
C:多个模型的请求体参数
我们可以定义多个请求体模型。例如:Item和User
from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = Noneclass User(BaseModel):username: strfull_name: str = None@app.put('/items/{item_id}')async def update_item(*, item_id: int, item: Item, user: User):results = {'item_id': item_id, 'item': item, 'user': user}return results
在这种情况下,请求体输入的格式是一个字典,它将使用参数名称作为正文中的key,Pydantic的类作为key的内容,例如上述请求体的正确格式如下:
{'item': {'name': 'Foo','description': 'The pretender','price': 42.0,'tax': 3.2},'user': {'username': 'dave','full_name': 'Dave Grohl'}}
我们将这个输入传入之后得到的输出如下。URL为:127.0.0.1:8001/items/3
{'item_id': 3,'item': {'name': 'Foo','description': 'The pretender','price': 42.0,'tax': 3.2},'user': {'username': 'dave','full_name': 'Dave Grohl'}}
(四)Body简单介绍
1.可以将单类型的参数成为Request Body的一部分,即查询参数变成请求体参数。
2.和 Query提供的额外校验基本一致。
def Body( # noqa: N802default: Any = Undefined,*,embed: bool = False,media_type: str = "application/json",alias: Optional[str] = None,title: Optional[str] = None,description: Optional[str] = None,gt: Optional[float] = None,ge: Optional[float] = None,lt: Optional[float] = None,le: Optional[float] = None,min_length: Optional[int] = None,max_length: Optional[int] = None,regex: Optional[str] = None,example: Any = Undefined,examples: Optional[Dict[str, Any]] = None,**extra: Any,) -> Any:
以上就是本次分享的内容,感谢大家支持。您的关注、点赞、收藏是我创作的动力。
万水千山总是情,点个 👍 行不行。
更多推荐

所有评论(0)