• 请求方式
  • 不同请求方式下的参数获取方式

请求方式

FastAPI请求方式通过实例化FastAPI对象点属性来控制

单个请求方式

  1. from fastapi import FastAPI
  2. app = FastAPI()
  3. @app.get("/get/")
  4. def get():
  5. # GET请求
  6. return {"action": "GET"}
  7. @app.post("/post/")
  8. def post():
  9. # POST请求
  10. return {"action": "POST"}
  11. @app.put("/put/")
  12. def put():
  13. # PUT请求
  14. return {"action": "PUT"}
  15. @app.delete("/delete/")
  16. def delete():
  17. # DELETE请求
  18. return {"action": "DELETE"}

启动服务后,使用requests测试:

  1. import requests
  2. print(requests.get("http://localhost:8000/get").json())
  3. # {'action': 'GET'}
  4. print(requests.post("http://localhost:8000/post/").json())
  5. # {'action': 'POST'}
  6. print(requests.put("http://localhost:8000/put/").json())
  7. # {'action': 'PUT'}
  8. print(requests.delete("http://localhost:8000/delete/").json())
  9. # {'action': 'DELETE'}
  10. print(requests.post("http://localhost:8000/get").json())
  11. # {'detail': 'Method Not Allowed'}

多种请求方式

这里使用api_route属性,由FastAPI类提供(继承自Starlette

编写路由为http://127.0.0.1:8000/action/的接口,同时支持GET、POST、PUT、DELETE四种请求方式:

  1. from fastapi import FastAPI
  2. from starlette.requests import Request
  3. from starlette.responses import JSONResponse
  4. # 方式一
  5. @app.api_route("/action/", methods=["GET", "POST", "PUT", "DELETE"])
  6. def action(request: Request):
  7. return {"action": request.method}
  8. # 方式二:也可使用父类提供的route属性
  9. @app.route("/action/", methods=["GET", "POST", "PUT", "DELETE"])
  10. def action(request: Request):
  11. return JSONResponse({"action": request.method})

❕注意项:

使用父类route属性时,因为其内部并没有像Fast API那样额外封装支撑

所以在使用时:request参数为必填项,响应结果也必须为Response类型。

分别请求响应为:

  1. print(requests.get("http://localhost:8000/action/").json())
  2. # {'action': 'GET'}
  3. print(requests.post("http://localhost:8000/action/").json())
  4. # {'action': 'POST'}
  5. print(requests.put("http://localhost:8000/action/").json())
  6. # {'action': 'PUT'}
  7. print(requests.delete("http://localhost:8000/action/").json())
  8. # {'action': 'DELETE'}

路径参数

在路由里,通过{}标识获取

示例如下:

  1. from fastapi import FastAPI
  2. @app.get("/book/{book_id}")
  3. def book(book_id: int):
  4. """
  5. 书籍📚
  6. """
  7. return {
  8. "id": book_id
  9. }

❕注意项:

  1. 函数参数必须包含路径参数,否则会被认为是查询Query参数,导致路径参数无效果
  2. 因为在定义函数时,指定了book_id为int类型,FastAPI会自动校验其传入值是否符合(若对类型无要求,可不指定)

测试请求响应为:

  1. import requests
  2. print(requests.get("http://localhost:8000/book/1/").json())
  3. # {'id': 1}
  4. print(requests.get("http://localhost:8000/book/test/").json())
  5. # {'detail': [{'loc': ['path', 'book_id'], 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}]}

查询参数(Query参数)

查询参数中存在多种情况,如必选、非必选、默认值…

FastAPI提供简单的参数控制,将Python函数的参数定义方式结合到Web参数控制上,一定程度上简化了开发效率,节省了额外的参数校验工作。

接下来,分别定义多种参数,来看它们的实现方式:

  1. from fastapi import FastAPI
  2. from typing import Optional
  3. @app.get("/books/")
  4. def books(book_type: str, limit: int = 1, size: int = 10, book_name: Optional[str] = None, sort: bool = False):
  5. return {
  6. "book_type": book_type,
  7. "book_name": book_name,
  8. "sort": sort,
  9. "limit": limit,
  10. "size": size
  11. }

这个例子定义了四种不同性质的Query参数:

  • book_type:字符串,必选
  • limit、size:整型,非必选,且提供默认值
  • book_name:字符串,非必选,默认值为None
  • sort:布尔类型,非必选,默认值为False

❕注意项:

  1. 因为都指定了相应的数据类型,因此,FastAPI会做基本的数据类型校验和类型强制转换。

如:

  • limit为整型,传入字符串会导致强转失败,导致接口返回类型错误的提示信息。
  • sort为布尔值,不论传入字符串,还是整型,都可以强转为True或False。

分别测试请求响应为:

  1. import requests
  2. print(requests.get("http://localhost:8000/books/").json())
  3. # {'detail': [{'loc': ['query', 'book_type'], 'msg': 'field required', 'type': 'value_error.missing'}]}
  4. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍"}).json())
  5. # {'book_type': 'IT书籍', 'book_name': None, 'sort': False, 'limit': 1, 'size': 10}
  6. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍", "book_name": "数学之美"}).json())
  7. # {'book_type': 'IT书籍', 'book_name': '数学之美', 'sort': False, 'limit': 1, 'size': 10}
  8. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍", "book_name": "数学之美", "limit": 2, "size": 20}).json())
  9. # {'book_type': 'IT书籍', 'book_name': '数学之美', 'sort': False, 'limit': 2, 'size': 20}
  10. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍", "book_name": "数学之美", "limit": "limit", "size": "size"}).json())
  11. # {'detail': [{'loc': ['query', 'limit'], 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}, {'loc': ['query', 'size'], 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}]}
  12. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍", "book_name": "数学之美", "sort": True}).json())
  13. # {'book_type': 'IT书籍', 'book_name': '数学之美', 'sort': True, 'limit': 1, 'size': 10}
  14. print(requests.get("http://localhost:8000/books/", params={"book_type": "IT书籍", "book_name": "数学之美", "sort": 1}).json())
  15. # {'book_type': 'IT书籍', 'book_name': '数学之美', 'sort': True, 'limit': 1, 'size': 10}

Body参数

获取并操作body参数,Fast API提供两种方式。通过定义Pydantic模型和使用Body参数

Pydantic模型

需要先声明Pydantic模型,通过定义的属性来获取和校验body参数

定义方式如下:

  1. from fastapi import FastAPI
  2. from pydantic import BaseModel
  3. from typing import Optional
  4. # 定义Pydantic模型
  5. class Book(BaseModel):
  6. name: str
  7. type: Optional[str] = "其他"
  8. price: int
  9. app = FastAPI()
  10. @app.post("/book/")
  11. # 参数声明
  12. def create_book(book: Book):
  13. book_dict = book.dict()
  14. if book.price > 100:
  15. book_dict.update({"buy": "哦~,我买不起"})
  16. else:
  17. book_dict.update({"buy": "哈哈,我能买的起!!"})
  18. return book_dict

通过继承BaseModel,定义Pydantic模型类

然后将其声明为参数,同时,Fast API会将请求体作为json读取,根据指定的模型类校验或转换数据类型。验证通过后,将数据赋值给参数book

在获取到body参数后,可在函数内部访问模型对象的所有属性

测试请求响应为:

  1. import requests
  2. body = {"name": "数学之美"}
  3. print(requests.post("http://localhost:8000/book/", json=body).json())
  4. # {'detail': [{'loc': ['body', 'price'], 'msg': 'field required', 'type': 'value_error.missing'}]}
  5. body = {"name": "数学之美", "price": 1}
  6. print(requests.post("http://localhost:8000/book/", json=body).json())
  7. # {'name': '数学之美', 'type': '其他', 'price': 1, 'buy': '哈哈,我能买的起!!'}
  8. body = {"name": "数学之美", "price": 1000}
  9. print(requests.post("http://localhost:8000/book/", json=body).json())
  10. # {'name': '数学之美', 'type': '其他', 'price': 1000, 'buy': '哦~,我买不起'}
  11. body = {"name": "数学之美", "price": 1, "type": "IT书籍"}
  12. print(requests.post("http://localhost:8000/book/", json=body).json())
  13. # {'name': '数学之美', 'type': 'IT书籍', 'price': 1, 'buy': '哈哈,我能买的起!!'}

Body参数

小结

  1. 当同一个路由,同时存在路径参数、查询参数、body参数时,FastAPI匹配顺序如下:
    • 如果在路径中也声明了该参数,它将被用作路径参数。
    • 如果参数属于单一类型(比如 intfloatstrbool 等)它将被解释为查询参数。
    • 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体