赞
踩
目录
7、Query/Path/Body/Field 参数(额外的校验) 与 字符串验证
12 、响应状态码-使用 status_code 参数来声明
基于Python3.6+版本的、用于构建API现代的、高性能的web框架。FastAPI是建立在Pydantic和Starlette基础上的,Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/工具包,是构建高性能Asyncio服务的理性选择。
- if __name__ == "__main__":
- uvicorn.run(app, host="127.0.0.1", port=8000)
在浏览器中请求 http://127.0.0.1:8000/docs ,显示交互式API文档, 自动交互式 API 文档(由 Swagger UI 提供),如下图:
在浏览器中请求 http://127.0.0.1:8000/redoc ,显示备用API文档, 备用的自动交互式文档(由 ReDoc 提供),如下图:
按照路径顺序匹配,默认匹配的是第一个带参数的路径
- from pydantic import BaseModel
-
- # schema基本定义方法
- class Person(BaseModel):
- name: str
-
- # 基本的schema实例化方法-直接传入
- p = Person(name="ABC123")
- print(p.json())
-
- >>> {"name": "ABC123"}
- from pydantic import BaseModel
-
- class User(BaseModel):
- username: str
- email: Optional[str] = None
- full_name: Optional[str] = None
- status: Optional[bool] = None
- from typing import Union
-
- from fastapi import FastAPI
- from pydantic import BaseModel
-
- class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
- app = FastAPI()
-
- """
- 函数参数将依次按如下规则进行识别:
- ● 如果在路径中也声明了该参数,它将被用作路径参数(例如:item_id)。
- ● 如果参数属于单一类型(比如 int、float、str、bool 等)它将被解释为查询参数(例如:q)。
- ● 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体(例如:item)。
- """
-
- @app.put("/items/{item_id}")
- async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
- result = {"item_id": item_id, **item.dict()}
- if q:
- result.update({"q": q})
- return result
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- from fastapi import FastAPI, Query
-
- # m是可选参数,参数长度2-10,以name开头
- @app.get("/update_items/")
- # 当使用 Query 且需要声明一个值是必需的时,可以将 ... 用作第一个参数值
- # def update_items(m: Optional[str] = Query(..., max_length=10,min_length=2,regex="^name")):
- def update_items(m: Optional[str] = Query(None, max_length=10,min_length=2,regex="^name")):
- results = {"items": [{"oneid": "北京"}, {"two": "上海"}]}
- if m:
- results.update({"上海": m})
- return results
-
-
- """
- 声明数值校验:
- gt:大于(greater than)
- ge:大于等于(greater than or equal)
- lt:小于(less than)
- le:小于等于(less than or equal)
- regex正侧参数的写法:
- 以 ^ 符号开头
- 以 $ 符号结尾
- 使用省略号(...)声明必需参数
- """
-
- # 需求:id大于5才能返回
- @app.get("/id")
- async def read_id(*, id: int = Query(..., ge=5, ), q_value: str):
- results = {"message": f"{q_value}"}
- if id:
- results.update({"new_value": q_value})
- return results
-
- """
- ● 传递 * 作为函数的第一个参数,
- ● 如果单独出现星号 *,
- ● 则星号 * 后的参数必须用关键字传入
- """
-
- @app.get("/items/{item_id}")
- # 使用 Path 为路径参数声明相同类型的校验和元数据
- async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
- results = {"item_id": item_id}
- if q:
- results.update({"q": q})
- return results
-
-
- """
- ●嵌入单个请求体参数,期望一个拥有 item 键并在值中包含模型内容的 JSON,
- ●返回如下:
- {
- "item": {
- "name": "Foo",
- "description": "The pretender",
- "price": 42.0,
- "tax": 3.2
- }
- }
- ●可以使用一个特殊的 Body 参数 embed : item: Item = Body(embed=True)
- """
-
- class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
- @app.put("/items/{item_id}")
- async def update_item(item_id: int, item: Item = Body(embed=True)):
- results = {"item_id": item_id, "item": item}
- return results
-
-
- # 通过get方式在URL路径中接收请求参数
- @app.get("/items/{item_id}")
- async def read_root1(item_id: int = Path(..., gt=0)):
- return {"item_id": item_id}
-
- # 虽然是通过post方式提交请求,但item_id仍然是在URL中通过?item_id进行请求
- @app.post("/items")
- async def read_root2(item_id: int = Query(..., ge=1)):
- return {"item_id": item_id}
-
- # post方式提交请求,但item_id仍然是在URL中通过?item_id进行请求
- @app.post("/items")
- async def read_root2(
- item_id: int = Body(..., ge=1, embed=True),
- item_name: str = Body(None, max_length=20)):
- return {"item_id": item_id, "item_name": item_name}
-
-
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
typing —— 类型注解支持 — Python 3.11.0 文档
前两行小写的不需要 import,后面三行都需要通过 typing 模块 import
- # 下面的函数接收与返回的都是字符串,注解方式如下:
- def items(name: str) -> str:
- return "hello" + name
-
- print(items("123"))
-
- >>>hello123
(声明a :Optional[int] = None) ,参数除了给定的默认值外还可以是None(作用是让编译器识别到该参数有一个类型提示,可以使指定类型,也可以是None,且参数是可选非必传的)。注意 Optional[] 里面只能写一个数据类型。即 Optional[X] 等价于 Union[X, None]
typing —— 类型注解支持 — Python 3.11.0 文档
- # 参数end是可选择的参数,有end就返回需求的,没有end返回所有的
- @app.get("/params")
- async def read_param(start: int = 0, end: Optional[int] = None):
- if end:
- return data[start:end]
- return data[start::]
- # Union[int, None] 表示既可以是 int,也可以是 None。没有顺序的说法
-
- python 3.6 及以上版本,需要导入typing中的Union
- from typing import Union
-
- class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: Union[int, None] = None
-
-
- python 3.9 及以上版本 ,不需要导入typing中的Union
- class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: int | None = None
-
-
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- from typing import Optional
-
- import uvicorn
- from fastapi import FastAPI, Body
- from typing import List, Tuple
-
- app = FastAPI()
-
-
- @app.put("/items/{item_id}")
- async def update_item(
- list_: List[int] = Body(...),
- tuple_: Tuple[int] = Body(...),
- ):
- results = {"list_": list_, "tuple_": tuple_}
- return results
-
-
- if __name__ == "__main__":
- uvicorn.run(app, host="127.0.0.1", port=8080)
-
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
使用Config 和 schema_extra 为Pydantic模型声明一个简单的示例
- import uvicorn
- from fastapi import FastAPI, Path, Query
- from pydantic import BaseModel, Field
- from typing import Union
-
- class Items(BaseModel):
- name: str
- desc: Optional[str] = None
- price: float
- tax: Optional[float] = None
-
- # 接口请求示例展现在接口文档中
- """使用Config 和 schema_extra 为Pydantic模型声明一个简单的示例"""
- class Config:
- schema_extra = {
- "example": {
- "name": "书名",
- "price": 20,
- "decs": "描述信息",
- "tax": 0.5
- }
- }
-
-
- @app.post("/items1")
- async def retrun_item(item: Items):
- results = {"item": item}
- return results
-
-
- """
- 通过工厂函数,增加example参数
- 注意:传递的额外参数不会添加任何验证,只会添加注释,用于文档的目的
- """
-
- class Item(BaseModel):
- name: str = Field(example="Foo")
- description: Union[str, None] = Field(default=None, example="A very nice Item")
- price: float = Field(example=35.4)
- tax: Union[float, None] = Field(default=None, example=3.2)
-
-
- @app.put("/items/{item_id}")
- async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
-
- if __name__ == '__main__':
- uvicorn.run(app, host="127.0.0.1", port=8000)
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- """
- header的必须有token且token必须是456,没有返回无权限,
- cookie必须有一个name,且等于123,否则返回认证失败
- """
- from typing import Optional
- from fastapi import Cookie, FastAPI,Header
- app = FastAPI()
- @app.get("/items/")
- def read_items(name: Optional[str] = Cookie(None),
- token: Optional[str] = Header(None)):
- if token is None or token!='456':
- return '无权限'
- if name is None or name !="123":
- return "认证失败"
- class UserIn(BaseModel):
- username: str
- password: str
- email: str
- full_name: Optional[str] = None
-
- class Userout(BaseModel):
- username: str
- email: str
- full_name: Optional[str] = None
-
- @app.post("/user/", response_model=Userout)
- def create_user(user: UserIn):
- return user
https://fastapi.tiangolo.com/zh/tutorial/response-status-code/
- import uvicorn
- from fastapi import FastAPI, Form
- app = FastAPI()
- @app.post("/login/",status_code=200)
- def login(username: str = Form(...), password: str = Form(...)):
- if password == "123456":
- return {"username": username}
- return "密码错误"
-
- # 注册用户,username长度8-16位,password长度6-16位,符合需求返回对应username
- @app.post("/register", status_code=200)
- async def register(username: str = Form(..., min_length=8, max_length=16, regex='^[a-zA-Z]'),
- password: str = Form(..., min_length=8, max_length=16, regex='^[0-9]')):
- return {"username": username}
-
-
- if __name__ == '__main__':
- uvicorn.run(app, host="127.0.0.1", port=8000)
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- from fastapi import FastAPI, File, UploadFile
-
- app = FastAPI()
-
- @app.post("/files/")
- def create(file: bytes = File(...)):
- return {"file_size": len(file)}
-
- @app.post("/uploadfile/")
- def upload_file(file: UploadFile = File(...)):
- return {"filename": file.filename}
- from fastapi import FastAPI, HTTPException
- app = FastAPI()
- items = {"test": "浅说测试开发"}
- @app.get("/items/{item_id}")
- def read_item(item_id: str):
- if item_id not in items:
- raise HTTPException(status_code=404, detail="Item not found")
- return {"item": items[item_id]}
https://fastapi.tiangolo.com/zh/tutorial/encoder/#__tabbed_1_2
- from fastapi import Depends
-
- # 定义依赖项函数
- def com_methods(q: Optional[str] = None, a: int = 0, b: int = 10):
- return {"q": q, "a": a, "b": b}
-
- @app.get("/com_item1")
- def com_item1(item1: dict = Depends(com_methods)):
- return item1
-
- @app.post("/com_item2")
- def com_item2(item2: dict = Depends(com_methods)):
- return item2
-
-
- """
- class CommonQueryParams:
- 类实现依赖注入2中写法:
- 1.commons: CommonQueryParams = Depends(CommonQueryParams)
- 2.commons: CommonQueryParams = Depends()
- """
-
- # 全局都需要校验token
-
- from fastapi import FastAPI,Header, HTTPException,Depends
-
- def verify_token(token: str = Header(...)):
- if token!="asdfghjkl":
- raise HTTPException(status_code=400, detail="Token header invalid")
- app = FastAPI(dependencies=[Depends(verify_token)])
-
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。