FastAPI 疾速开发 Web API 我的项目 学习笔记:
- 第一篇:通过 Python FastAPI 开发一个疾速的 Web API 我的项目
- 第二篇:FastAPI 的路由介绍与应用
- 第三篇:FastAPI 开发中数据校验利器 Pydantic 介绍与集成应用
1 介绍
FastAPI 容许您定义客户端在向 API 或 Web 应用程序发出请求时能够蕴含在 URL 中的参数和变量。这些参数可用于 查询数据库 、 排序 和过滤数据 以及影响返回响应的许多其余事件。
在本篇文章中,将会介绍 FastAPI 的门路和查问参数以及它们在 FastAPI 的工作形式。
2 门路参数
门路参数是什么?
能够作为 URL 的一部分的变量,通常会利用在指定门路的 URI
2.1 定义
定义:门路参数通过事后定义好的地位来承受参数。门路参数是蕴含在 API 路由中的参数,用于辨认资源。这些参数作为一个标识符,有时也是一个桥梁,能够在网络应用中进行进一步的操作。
依据 Restful 的设计格调,在设计一个 GET 办法 API 时,如果是要读取繁多资源,能够通过提供 URI 并带入门路参数的形式,来获取特定资源。比方,在咱们的 todo 我的项目中,如果想要获取 id=1
的待办事项的详细信息,就能够通过将数字 1 作为门路参数,而后将其作为参数传递给门路操作函数:
http://localhost:8888/todo/1
在 FastAPI 中,咱们能够应用与 Python 格局字符串雷同的语法申明门路“参数”或“变量”,应用 Path Parameter
时,应用 {}
在门路中设定一个参数,例如官网文档中的这个例子:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id):
return {"item_id": item_id}
下面代码中门路参数 item_id
的值将作为参数 item_id
传递给您的函数 read_item()
。
在 /items/{id}
路由装璜器中,咱们应用花括号来申明门路参数_id_。这个参数被传递到门路操作函数中,咱们能够用它作为键从库存字典中获取相应的我的项目。
2.2 带类型的门路参数
门路参数也能够申明类型,通过应用 Python 的类型注解,比方定义 async def read_item(item_id: int):
此处的 item_id
的类型就被申明为 int
类型。如果咱们拜访端点http://127.0.0.1:8888/todo/test,咱们会失去以下谬误响应:
{
"detail": [
{
"loc": [
"path",
"todo_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
如图:
2.3 门路程序
通常咱们须要制作具备类似构造的门路。当固定门路雷同时会产生这种状况。例如,假如咱们有两个端点,如下所示:
/todo/default
/todo/{todo_id}
第一个返回默认待办事项。第二个返回具备特定 todo_id 的 待办事项。在这种状况下,申明这些端点的程序很重要。门路按程序评估。因而,咱们须要在 /todo/{todo_id}
之前申明 /todo/
。见上面的代码:
@todo_router.get("/todo/")
async def get_default_todo():
if todo_list:
return {"todo_1": todo_list[0]
}
return {"message": "Todo is initial."}
@todo_router.get("/todo/{todo_id}")
async def get_single_todo(todo_id: int) -> dict:
for todo in todo_list:
if todo.id == todo_id:
return {"todo": todo}
return {"message": "Todo with supplied ID doesn't exist."}
2.4 数字校验
FastAPI 可能在将门路参数传递给咱们的函数之前验证门路参数中的数据。它通过类来实现这一点Path
。
更新您的 main.py
文件以匹配以下内容:
@todo_router.get("/todo/{todo_id}")
async def get_single_todo(todo_id: int = Path(ge=1, le=len(todo_list),
title="The ID of the todo to be retrieved.")) -> dict:
咱们为 Path 增加了额定的导入。而后在门路操作函数中,咱们在 todo_id
上创立一个数字限度,使其仅蕴含大于或等于 1 且小于或等于咱们 todo 列表长度的值。
有更好的办法来验证库存我的项目是否存在,咱们稍后会讲到,但当初,咱们只是演示如何应用 Path 类。
以下是您能够在 Path
类中设置的数字验证列表。
- gt:大于
- ge:大于或等于
- lt:小于
- le:小于或等于
2.5 字符串验证
您也能够对字符串参数施加束缚。将以下路由增加到您的 main.py
文件中。
@todo_router.get("/todos/{todo_name}")
async def get_todo(todo_name: str = Path(max_length=20)) -> dict:
for todo in todo_list:
if todo_name in todo["name"] :
return {"todo": todo}
return {"message": "Todo with supplied name doesn't exist."}
该门路将参数解释为字符串而不是数字,并将最大长度设置为 6 个字符。能够将其余束缚增加到参数,例如最小长度和正则表达式。查看 FastAPI 文档 理解更多。
咱们心愿建设一个 GET 申请,通过查问 id 来 获取 todo 的 API,因而能够承受 todo 的 id todo_id
,能够通过以下的形式:
from fastapi import APIRouter, Path
from models.model import Todo
todo_router = APIRouter()
todo_list = []
@todo_router.get("/todo/{todo_id}")
async def get_single_todo(todo_id: int = Path(..., title="The ID of the todo to be retrieved.")) -> dict:
for todo in todo_list:
if todo.id == todo_id:
return {"todo": todo}
return {"message": "Todo with supplied ID doesn't exist."}
在下面的例子中,咱们在 get_single_todo()
中定义了 todo_id
参数后,FastAPI 会主动注册的门路中寻找 {todo_id}
的地位,当承受到符合条件的 Request(/todo/{todo_id})
时,会主动将 {todo_id}
地位的值当成 get_single_todo()
的参数填入。
如果是要读取所有资源,并心愿可能进行排序、数量限度等操作,则能够通过带入查问参数。在上一节中,咱们曾经能通过 @todo_router.get("/todo")
获取到所有的待办事项。
启动 todo 我的项目:
uvicorn main:app --port 8888 --reload
启动胜利如下:
关上另外一个 Bash 终端:
$ curl -X 'GET' 'http://127.0.0.1:8888/todo/2' -H 'accept: applicaion/json'
{"message":"Todo with supplied ID doesn't exist."}
阐明此时通过查问 id 为 2 的待办事项,并不存在,因而,咱们通过 POST 申请新建一个 id 为 2 的代办事项,命令如下:
curl -X POST http://127.0.0.1:8888/todo -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"id": 2,"item":"learning path and query"}'
建设胜利之后,截图如下:
再通过查问来获取这个 id 为 2 的待办事项,能够看到刚刚新建的 item
信息为 “learning path and query”:
$ curl -X 'GET' 'http://127.0.0.1:8888/todo/2' -H 'accept: applicaion/json'
{"todo":{"id":2,"item":"learning path and query"}}(fastwebprojects)
后盾服务器也是显示 200 失常:
3 查问参数
3.1 定义
查问参数对于构建灵便的 API 至关重要。顾名思义,带有查问参数的端点通常能够帮忙客户端依据动静参数查问特定数据。查问参数是一个 可选的参数 ,通常呈现在 URL 的 问号 ?
之后。它用于过滤申请,并依据提供的查问返回特定的数据。
查问参数是什么?
通常会放于 URL 最初面,并以
?
区隔开来。查问参数用来承受 URL 所附加的参数,与Path Parameter
最大的差异在于没有事后定义地位。
在一个路由处理函数中,当咱们申明一个函数时,其参数不作为门路参数呈现,它们将被解释为查问参数。你也能够通过在函数参数中创立 FastAPI Query()
类的一个实例来定义一个查问,比方上面的例子:
async def query_route(query: str = Query(None)):
return query
回到咱们的 todo 我的项目中,如何定义一个查问参数呢?查看上面的例子:
@todo_router.get("/todos/")
async def get_default_todo(skip: int = 0, limit: int = 10):
if todo_list:
return todo_list[skip : skip + limit]
return {"message": "Todo is initial."}
咱们有两个参数 skip
和 limit
。这些参数不是门路参数的一部分。相同,它们以查问参数的模式提供,同时以 http://localhost:8000/todos?skip=0&limit=10
调用 API 端点。
此处,skip
的初始值为 0,limit
的初始值为 10。因为它们是 URL 的一部分,因而它们被视为字符串。然而,咱们应用 Python 类型申明它们。因而,它们会主动转换并依据它进行验证。
3.2 查问参数默认值
如咱们所见,查问参数不是固定门路的一部分。因而,它们是可选的。此外,它们能够具备默认值,以防咱们不传递任何值作为输出。
换句话说,如果咱们简略地调用 http://localhost:8888/todos
,这将意味着 skip
将采纳默认值 0,而 limit
将采纳默认值 10。
3.3 申明一个可选查问参数
同样,您能够通过将其默认设置为 None 来申明可选查问参数:
在 Python 3.10 和 Python 3.6 还有一点点不一样,这一点倡议多看看官网文档,这里以 3.10 为例:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None):
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
在这种状况下,函数参数 q
是可选的,默认状况下为 None
。
更改 todo_router.py
文件:
from fastapi import APIRouter, Path
from models.model import Todo
todo_router = APIRouter()
todo_list = [{"id":1,"item":"write a todo project"},
{"id":2,"item":"learning path parameters"},
{"id":3,"item":"learning query parameters"},
]
@todo_router.post("/todo")
async def add_todo(todo: Todo) -> dict:
todo_list.append(todo)
return {"message": "Todo added successfully"}
@todo_router.get("/todo")
async def retrieve_todos() -> dict:
return {"todos": todo_list}
@todo_router.get("/todo/{todo_id}")
async def get_single_todo(todo_id: int = Path(..., title="The ID of the todo to be retrieved.")) -> dict:
for todo in todo_list:
if todo.id == todo_id:
return {"todo": todo}
return {"message": "Todo with supplied ID doesn't exist."}
@todo_router.get("/todo/")
async def get_default_todo():
if todo_list:
return {"todo_1": todo_list[0]
}
return {"message": "Todo is initial."}
@todo_router.get("/todos/")
async def get_default_todo(skip: int = 0, limit: int = 10):
if todo_list:
return todo_list[skip : skip + limit]
return {"message": "Todo is initial."}
3.4 必输查问参数
当咱们申明一个具备默认值的查问参数时,咱们将其设为可选。此外,当咱们保留默认值 None 时,FastAPI 将其视为可选。
然而,咱们也能够强制指定某些查问参数。基本上,咱们不用提供默认值。在这种状况下,FastAPI 将查问参数视为必须参数。
请参见上面的示例:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_user_item(item_id: str, needy: str):
item = {"item_id": item_id, "needy": needy}
return item
这里的查问参数 needy
是一个必须的 str 类型的查问参数。
3.5 查问参数束缚
查问参数能够像门路参数一样被调配束缚。在下面的例子中,兴许咱们会限度 max_price
参数只承受正整数。
该过程与门路束缚雷同,但导入不同。增加 Query
到您的 fastapi
import,如下所示。
from fastapi import FastAPI, Path, Query
而后更新 get_items()
门路函数以应用 Query 类并设置适当的选项。
@app.get("/items/")
def get_items(vegan: bool = False, max_price: float = Query(default=20, ge=1)):
results = {}
counter = 1
for item in inventory.values():
if item["vegan"] == vegan and item["price"] <= max_price:
results[counter] = item
counter += 1
return results
当初为参数输出负值 max_price
会返回以下谬误音讯。
{"detail":[{"loc":["query","max_price"],"msg":"ensure this value is greater than or equal to 1","type":"value_error.number.not_ge","ctx":{"limit_value":1}}]}
查看 FastAPI 文档以理解 查问参数和字符串验证 看看您还能够用查问参数做什么。
4 总结
门路和查问参数都容许开发人员接管变量输出、解决它并返回基于该输出的响应。
在设计 API 路由时,有时您能够应用门路或查问参数来实现雷同的工作。以下是这方面的例子。
# 获取 id 为 1 的 todo
http://localhost:8888/todos/1
http://localhost:8000/todos/?id=1
然而门路参数更适宜创立对特定信息的申请。查问参数更适宜过滤和排序数据。
在这篇文章中,咱们理解了什么是门路和查问参数以及如何在 FastAPI 中实现它们。而后,咱们钻研了如何通过限度数字和字符串值来对这些参数创立束缚。咱们还回顾了门路参数和查问参数之间的次要区别,并在 todo 利用中使用了展现了如何去应用门路加入和查问参数。
如果想理解更多的这两个参数的细节,读者能够读取上面的参考资料,PS:官网文档才是第一手学习材料。
心愿本文能对你有所帮忙,如果喜爱本文,能够点个关注.
下一篇文章见!宇宙古今无有穷期,毕生不过顷刻,当思奋争。
参考链接:
- Path Parameters
- Query Parameter
- Path and Query Parameters