【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 FastAPI  app = 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 FastAPI app = 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 FastAPI  app = 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,Query  from .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,Query  app = 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,Body  app = 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 Enum    from fastapi import FastAPI    class 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. 创建一个继承strEnum的类,并创建几个类属性,这些类属性的值将是可用的有效值。

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=3  ip:port/list/query                # 使用默认值 page=1,limit=10  ip: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,Query  from 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: N802      default: 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, Query    app = 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, Path    app = 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, Path    app = 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, Query    app = 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(最常见)、PUTDELETEPATCH

(二)不使用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 BaseModel    class Item(BaseModel):  //自定义一个pydantic模型    name: str       description: str = None      price: float       tax: float = None  

所以访问链接的时候传入的请求体可以是下面两种:

{      'name': 'Foo',      'description': 'An optional description',      'price': 45.2,      'tax': 3.5  }

另一种可以不传递默认值或者是可选值:

{      'name': 'Foo',      'price': 45.2  }

C: 属性类型自动转换为相应的请求类型

图片

图片

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

图片

图片

2.使用数据模型

A:将模型定义为参数

将上面定义的模型添加到你的路径操作中,类比定义PathQuery参数的方式,声明参数的类型创建的模型Item:

from fastapi import FastAPI  from pydantic import BaseModel      class Item(BaseModel):      name: str      description: str = None      price: float      tax: float = None      app = FastAPI()    @app.post('/body/')  def create_item(item: Item):      return item

B:在函数内部,可以直接访问模型对象的所有属性

from fastapi import FastAPI  from pydantic import BaseModel      class Item(BaseModel):      name: str      description: str = None      price: float      tax: float = None      app = 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 FastAPI  from pydantic import BaseModel    app = FastAPI()      class Item(BaseModel):      name: str      description: str = None      price: float      tax: float = None      class User(BaseModel):      username: str      full_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: N802      default: 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:

以上就是本次分享的内容,感谢大家支持。您的关注、点赞、收藏是我创作的动力。

万水千山总是情,点个 👍 行不行。

  • 41
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值