通常對於Request Body不會經過get提交,對於get提交的參數通常稱爲是查詢參數。因此,若是是經過POTS,PUT等方式提交的參數信息,咱們通常是放到Request Body來提交到咱們的後端。html
對於如何接收和校驗請求體,FastApi提供的形式是使用:from pydantic import BaseModel數據庫
示例以下:json
import uvicorn 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 if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
在上面的模型中,若是提交的Item它必須是怎麼樣的一個格式,好比name是必選字段,description是可選且默認爲None, price是必選,且須要是float類型的,tax是可須且默認爲None。後端
那客戶端如何提交上面那些參數吶?api
嘗試提交參數什麼都不寫的狀況下:架構
http://127.0.0.1:8000/items/
使用JSON格式提交參數的狀況下:app
{ "name":"Foo", "description":"An openfdsf", "price":45.4, "tax":3.5 }
故意提交錯誤參數格式請求:async
{ "name":"Foo", "description":"An openfdsf", "price":"45abc", "tax":3.5 }
在設計一些API過程當中不免的可能也會須要綜合遇到上述的一些混搭的組合,須要同時多個參數的提交和獲取post
那麼咱們一般接收此次參數的話通常怎麼接收吶?學習
示例代碼如:
import uvicorn from fastapi import FastAPI, Path from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str = None price: float tax: float = None @app.put("/items/{item_id}") async def update_item( *, item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), q: str = None, item: Item = None, ): results = {"item_id": item_id} if q: results.update({"q": q}) if item: results.update({"item": item}) return results if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
經過以前的學習,其實也很簡單道理也仍是同樣,如上的示例請求的話:
url:
http://127.0.0.1:8000/items/1000?q=xiao
參數:
{ "name":"Foo", "description":"An openfdsf", "price": 45.4, "tax":3.5 }
效果以下:
更復雜的業務其實會存在多體的Boay的提交,以前作的商城下單裏面,客戶端有可能就會同時提交多個實體的對象信息到後端,如訂單實體,地址實體,商品信息實體等。
那麼在Fastapi如何接受多個Body實體吶?一般之前的話,在bottle,一般直接的request.body 或 request.json就能夠獲取客戶端部提交的信息了。
在Fastapi假設客戶端提交的參數是這樣的形式:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }, "user": { "username": "dave", "full_name": "Dave Grohl" } }
那如何的接收處理吶?
import uvicorn from fastapi import FastAPI, Path 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 if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
這種狀況,其實就是客戶端提交多個實體對象。那能夠定義多個模型對象便可。fastapi它會自動幫你處理提取信息。
http://127.0.0.1:8000/items/1000
若是另外再假設:
在Fastapi假設客戶端提交的參數是這樣的形式:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 }, "user": { "username": "dave", "full_name": "Dave Grohl" }, "importance": 5 }
其實這種可能也不是不存在滴,那如何的讀取解析importance參數吶?既然參數有Query 和 Path,固然也會有 Body 。
import uvicorn from fastapi import Body, 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, importance: int = Body(..., gt=0) ): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} return results if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
上面的代碼中咱們引入了Body 而且在importance: int = Body(...)進行處理和提取:
若是另外再假設,客戶端提交的是一個單體對象內嵌的話,咱們須要怎麼處理?:
{ "item": { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 } }
FastAPI提供了一個:
item: Item = Body(..., embed=True) 具體以下:
import uvicorn from fastapi import Body, FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str = None price: float tax: float = 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 if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
請求示例如:
若是另外再假設,客戶端提交一個更復雜的嵌套模型的話,怎麼辦?麻蛋的 確定也是會有這樣的狀況滴! 嵌套裏面有列表有實體。好比:
{ "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2, "tags": ["rock", "metal", "bar"], "image": { "url": "http://example.com/baz.jpg", "name": "The Foo live" } }
這時候,咱們就須要所謂的子內嵌啦:
import uvicorn from typing import Set from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Image(BaseModel): url: str name: str class Item(BaseModel): name: str description: str = None price: float tax: float = None tags: Set[str] = [] image: Image = None @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='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
如上代碼,Item裏面包含了Image,也包含了,tags類型的列表定義。
MMP更深層的嵌套也是能夠定義的如:
{ "name":"Foo", "description":"The pretender", "price":42, "items":[ { "name":"Foo", "description":"The pretender", "price":42, "tax":3.2, "tags":[ "rock", "metal", "bar" ], "image":{ "url":"http://example.com/baz.jpg", "name":"The Foo live" } }, { "name":"Foo2", "description":"The 2", "price":422, "tax":3.2, "tags":[ "rock", "metal", "bar" ], "image":{ "url":"http://example.com/baz.jpg", "name":"The Foo live" } } ] }
對應的解析爲:
import uvicorn from fastapi import FastAPI from pydantic import BaseModel from typing import List, Set app = FastAPI() class Image(BaseModel): url: str name: str class Item(BaseModel): name: str description: str = None price: float tax: float = None tags: Set[str] = [] # images: List[Image] = None image: Image = None class Offer(BaseModel): name: str description: str = None price: float items: List[Item] @app.post("/offers/") async def create_offer(*, offer: Offer): return offer if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
請求url
http://127.0.0.1:8000/offers
Field字段的意思其實就是相似上面Query, Path,也一樣給Body內的字段的信息添加相關的校驗。
也就是說。經過Field來規範提交的Body參數信息。好比:
import uvicorn from fastapi import Body, FastAPI from pydantic import BaseModel, Field app = FastAPI() class Item(BaseModel): name: str description: str = Field(None, title="標題啊", description="錯誤提示文字啊", max_length=30) price: float = Field(..., gt=0, description="錯誤提示文字啊") tax: float = 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 if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
上面的意思就是和以前定義參數校驗其實同樣
正常狀況:
{ "item":{ "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2 } }
異常狀況:
{ "item":{ "name": "Foo", "description": "The pretender sssssssssssssssss", "price": 42.0, "tax": 3.2 } }
對於數據格式的校驗,一般,咱們不止於
int
float
str
bool
可是提交參數不止於上述的幾種格式,有時候好比是對手機號碼的校驗,有些時候是時間類型的校驗等
其餘類型:
其餘數據類型¶ 如下是您可使用的一些其餘數據類型(來自官方文檔):
UUID:
一個標準的「通用惟一標識符」,在許多數據庫和系統中常見於ID。
在請求和答覆中,將表示爲str.
datetime.datetime:
一隻Pythondatetime.datetime.
在請求和答覆中,將表示爲str採用ISO 8601格式,如:2008-09-15T15:53:00+05:00.
datetime.date:
Pythondatetime.date.
在請求和答覆中,將表示爲str採用ISO 8601格式,如:2008-09-15.
datetime.time:
一隻Pythondatetime.time.
在請求和答覆中,將表示爲str採用ISO 8601格式,如:14:23:55.003.
datetime.timedelta:
一隻Pythondatetime.timedelta.
在請求和答覆中,將表示爲float總秒數。
Pydantic還容許將其表示爲「ISO 8601時間差別編碼」,有關更多信息,請參閱文檔。.
frozenset:
在請求和答覆中,將其視爲set:
在請求中,將讀取列表,消除重複,並將其轉換爲set.
在答覆中,set將轉換爲list.
生成的架構將指定set值是惟一的(使用JSONSchema的uniqueItems).
bytes:
標準Pythonbytes.
在請求和答覆中將被視爲str.
生成的架構將指定它是str帶着binary「格式」。
Decimal:
標準PythonDecimal.
在請求和響應中,處理方式與float.
因此我還可使用其餘類型來校驗:
import uvicorn from datetime import datetime, time, timedelta from uuid import UUID from fastapi import Body, FastAPI app = FastAPI() @app.put("/items/{item_id}") async def read_items( item_id: UUID, start_datetime: datetime = Body(None), end_datetime: datetime = Body(None), repeat_at: time = Body(None), process_after: timedelta = Body(None), ): start_process = start_datetime + process_after duration = end_datetime - start_process return { "item_id": item_id, "start_datetime": start_datetime, "end_datetime": end_datetime, "repeat_at": repeat_at, "process_after": process_after, "start_process": start_process, "duration": duration, } if __name__ == '__main__': uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
本文參考連接: