FastApi架构学习日记1

FastApi 一个用于构建API的现代的,快速(高性能)的web框架

fastapi 是建立在Starlette 和Pydantic的基础之上的,Starlette 一个轻量级的ASGI框架和工具包,是构建高性能Asyncio服务的理性选择;Pydantic,一个基于python类型提示来定义数据验证,序列化和文档化的库。

一.FastAPI使用的流程:

  1. 导入 FastAPI。
    2.创建一个 app 实例。
    3.编写一个路径操作装饰器(如 @app.get("/"))
    4.编写一个路径操作函数(如上面的 def root(): ...)
    5.运行开发服务器(如 uvicorn main:app --reload)
    a》 main:main.py 文件(一个 Python “模块”)
    b》 app:在 main.py 文件中通过 app = FastAPI() 创建的对象。
    c》 --reload:让服务器在更新代码后重新启动。仅在开发时使用该选项。
# 引入FastAPI类
from fastapi import FastAPI

# 实例化
app = FastAPI()

# 定义路径装饰器和路径操作函数
@app.get("/")
async def root():
    return {"message": "Hello World 老高"}

# 定义路径装饰器和路径操作函数
@app.get("/hello/{name}")
async def say_hello(name: str):
    return {"message": f"Hello {name}"}

2. 在PyCharm中 快捷的使用uvicorn试试服务器

from fastapi import FastAPI
import uvicorn

# 实例化
app = FastAPI()
# 定义路径装饰器和路径操作函数
@app.get("/")
async def root():
    return {"message": "Hello World 老高"}

# 判断该文件是否为主运行文件。
if __name__ == "__main__":
    uvicorn.run("main:app",host='127.0.0.1',port=8080,reload=True)
    #uvicorn.run("文件名称:入口实例名称",host='127.0.0.1',port=8080,reload=True)

二.路径操作

1.路径装饰器

fastapi 支持各种请求方式,如下:

@app.get()
@app.post()
@app.put()
@app.patch()
@app.delete()
@app.option()
@app.head()
@app.trace()

1.主文件路由和子路由,以及APIRouter和include_router的使用
  • 首先定义一个子路由。
    子路由的路径为shopping.apps.app01,文件名称为urls.py
#urls.py 子路由代码如下
# 导入子路由依赖文件 APIRouter
from fastapi import APIRouter

#实例化子路由 路由接口
shop = APIRouter()

#定义子路由的 路由方法
@shop.get('/food/')
async def shop_food():
    return {'shop':'food'}

@shop.get('/bed/')
async def shop_bed():
    return {'shop':'bed'}

  • 定义主入口文件
    include_router 路由分发
# 导入主文件所需依赖
from fastapi import FastAPI
import uvicorn

# 导入子路由
from shopping.apps.app01.urls import shop
from shopping.apps.app02.urls import user


app = FastAPI()

@app.get('/')
async def index():
    return '我是首页'

# 导入子路由(参数分别为 APIRouter,前缀,便签)
app.include_router(shop,prefix='/shop',tags=['购物中心接口'])
app.include_router(user,prefix='/user',tags=['用户中心接口'])


if __name__ == "__main__":
    uvicorn.run("main:app",port=8080,host='127.0.0.1',reload=True)

三.数据请求与响应

1.路径参数和查询参数
  • 路径参数
from fastapi import FastAPI
import uvicorn

# 实例化
app = FastAPI()

# 首页,路径参数
@app.get('/{name}/',tags=['首页接口'])
async def index(name):
    return {'index':'hello ,'+name}
  • 查询参数:除了路径参数以外的参数 都是查询参数。
from fastapi import FastAPI
import uvicorn
from typing import Union,Optional

# 实例化
app = FastAPI()

# 参数可以设置默认值,也可以设置数据类型,数据类型类型可以设置为多个数据类型
# Union 定义数据类型的一个集合,可以设置多个数据类型。Union[str,None] 就等于Optional['str']

@app.get('/login/{name}/',tags=['首页接口'])
async def login(name,psd:Union[str,None]=None,nick:Optional['str']=None):
    return {'index':'hello ,'+name,
            "昵称":nick,
            "密码":psd
            }

2. 请求体

请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。
我们使用 Pydantic 模型来声明请求体,并能够获得它们所具有的所有能力和优点。

  • 请求体不能够使用GET方法发送,只能使用POST(较常见)、PUT、DELETE 或 PATCH方法之一
  1. pydantic中的模块
  • BaseModel:定义数据模型的基类。它允许你创建具有验证、类型转换和序列化功能的数据模型,以便于数据的输入、处理和输出。
  • Field:定义模型字段(Model Field)的一个函数,Field 函数允许你为 Pydantic 模型的字段指定额外的配置选项,例如数据校验、默认值、别名等。它通常与 Pydantic 的模型类一起使用。
  • validator:添加自定义验证逻辑的装饰器函数。它允许你在 Pydantic 模型中定义验证函数,以便在创建或更新模型实例时执行自定义的数据验证。

2.数据模型的使用

可以限定数据类型,可以使用默认值,可以使用正则表达式,可以多重数据类型嵌套; 还可以使用validator 装饰器,自定义自己的验证规则

# 请求体
from fastapi import APIRouter
from typing import Union,Optional,List

# 请求体 - 导入Pydantic的baseModel
from pydantic import BaseModel,Field,validator
from datetime import date  #引入关于时间的类


app03 = APIRouter()
# 创建数据模型 Addr,声明为参数
class Addr(BaseModel):
    province:str
    city:str

# 创建数据模型 Item
class Item(BaseModel):
    # name:str = Field(regex='^a') # 可以使用正则表达式进行验证
    name:str
    price: int = None
    nick:str
    age:int = Field(default=0,gt=0,lt=100) # 限定区间值,默认值为0,大于0,切小于100的区间值
    description:Union[str,None] = None
    tax:Union[float,None] = None #可以使用多个数据类型集合,可以设置默认值
    dateDay:date = None
    add:Addr     # 多重数据类型嵌套

    # 自定义验证规则,需要引入validator类
    # 自定义name的验证规则,譬如:name 能为字母组合
    @validator("name")
    def name_must_alpha(cls,v):
        assert v.isalpha(),"name must is alpha" # assert 断言,如果v.isalpha()为False时,然后后面提示信息
        return v

    # 自定义nick验证规则,昵称需要字母和数字的组合,并且必须又一个字母为大写字母
    @validator('nick')
    def nick_must_alpha(cls,s):
        # 判断是否同时包含字母和数字
        has_alpha = any(char.isalpha() for char in s)
        has_digit = any(char.isdigit() for char in s)

        # 判断是否包含至少一个大写字母
        has_upper = any(char.isupper() for char in s)

        assert has_alpha and has_digit and has_upper,'nick格式不正确 ,nick 只能是字母+数字+大写的组合'
        return s

@app03.post('/items/')
async def create_item(item:Item):
    return item

3. Form表单

Form 是直接继承自 Body 的类,使用 Form 可以声明与 Body (及 Query、Path、Cookie)相同的元数据和验证。

# 引入Form表单
from fastapi import APIRouter,Form


app04 = APIRouter()

# 使用Form表单的方式接受数据
@app04.post('/regin/')
async def regin_test(username:str=Form(),password:str=Form()):
    print(f'username:{username};password:{password}')
    return {'username':username}

与 JSON 不同,HTML 表单(<form></form>)向服务器发送数据通常使用「特殊」的编码。

  • 表单数据的「媒体类型」编码一般为 application/x-www-form-urlencoded

  • 但包含文件的表单编码为 multipart/form-data

  • 注意事项:

可在一个路径操作中声明多个 Form 参数,但不能同时声明要接收 JSON 的 Body 字段。因为此时请求体的编码是 application/x-www-form-urlencoded,不是 application/json。

这不是 FastAPI 的问题,而是 HTTP 协议的规定。

4. 文件上传

因为上传文件以「表单数据」形式发送,所以接收上传文件,要预先安装 python-multipart

文件上传主要用到2个模块:File和UploadFile。
File一般只适应于小文件上传。大文件或者多文件一般使用UploadFile。

# 引入Form表单
from fastapi import APIRouter,File,UploadFile
from typing import List
import os

app05 = APIRouter()

@app05.post('/file/')
async def get_file(file:bytes = File()):
    # print('get_file-->',file) # 输出为二进制数据
    # 将文件一次性加载到内存,只适合小文件上传,上传大文件到时候会导致内存溢出,性能低下
    return {'file':len(file)}

@app05.post('/files/')
async def get_files(files:List[bytes] = File()):
    # 一次性上传多个文件
    return {'files':len(files)}


@app05.post('/updateFile/')
async def get_updatefile(file:UploadFile):
    # print('UploadFile-->',file)  # 输出:<starlette.datastructures.UploadFile object at 0x1109ab7d0>
    # 文件上传,并保存到服务器
    img = os.path.join('imgs',file.filename)
    with open(img,'wb') as f:
        for line in file.file:
            f.write(line)
    return {'files':file.filename}

@app05.post('/updateFiles/')
async def get_updatefiles(files:List[UploadFile]):
    # 多个文件上传,并保存到服务器
    for file in files:
        img = os.path.join('imgs',file.filename)
        with open(img,'wb') as f:
            for line in file.file:
                f.write(line)
    print('文件写入完成!')

    return {
        'files': [file.filename for file in files]
    }

5. Resquest对象

Fast API 还包含着Resquest模块,Header模块,通过这个模块可以快速的访问用户的头部信息

# Request对象 可以获取一些除了数据之外的其他数据,如文件头信息,IP地址,

from fastapi import APIRouter,Request

app06 = APIRouter()

@app06.post("/get_request/")
async def get_request(res:Request):
    # lst = [i for i in res]
    return {
        '客户端url地址':res.url,
        '客户端ip地址':res.client.host,
        '头信息headers':res.headers,
        'cookie':res.cookies
    }

6. 请求静态文件

静态文件:不是由服务器生成的文件如css,js,图片文件等等。

# 设置网站的静态路径
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles


# 实例化
app = FastAPI()

# 设置静态文件路径,
app.mount('/static',StaticFiles(directory="statics"))

# 通过改地址可以直接访问statics文件夹内的文件。如css文件:http://127.0.0.1:8080/static/css/common.css
7. 响应模型的参数

FastAPI提供response_model参数,来声明return相应体的模型。response_model是「装饰器」的参数,而不是被装饰函数的参数。

FastAPI 将使用此 response_model 来:

  • 将输出数据转换为其声明的类型。
  • 校验数据。
  • 在 OpenAPI 的路径操作中为响应添加一个 JSON Schema。
  • 并在自动生成文档系统中使用。
from fastapi import APIRouter
from pydantic import BaseModel,EmailStr
# 注意如果引入EmailStr后还报错,需要安装一下 
from typing import Union


app07 = APIRouter()

# 接收数据模型
class UserIn(BaseModel):
    username:str
    password:str
    email: EmailStr
    fullname:Union[str,None] = None

# 响应的数据模型
class UserOut(BaseModel):
    username: str
    email: EmailStr
    fullname: Union[str, None] = None

# 注册功能:response_model 给装饰器添加数据模型
@app07.post("/user_reg",response_model=UserOut)
async def user_reg(user:UserIn):
    return user

# 输入值模型需要有username,password,email,fullname 这几个节点。而响应数据只有username,email,fullname 三个节点。这个就是使用响应的数据模型的作用。

响应数据模型其他功能:
  • response_model:返回值响应的数据模型
  • response_model_exclude_unset:过滤掉响应中的默认值,而是仅有实际设置的值
  • response_model_exclude_none=True: 相应值中不返回none的值
  • response_model_exclude_defaults=True:相应值中返回默认值
  • response_model_include: 相应值中只返回include包含的数据
  • response_model_exclude:相应值中不返回include包含的数据

使用路径操作装饰器的 response_model 参数来定义响应模型,特别是确保私有数据被过滤掉。

response 其他功能demo :
#+++++++++++++++++++++++++++++++++++
class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}

@app07.get(
    "/reponse/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容