FastAPI初識


FastAPI

准備

官網:https://fastapi.tiangolo.com/

Documentation: https://fastapi.tiangolo.com

Source Code: https://github.com/tiangolo/fastapi

FastAPI 框架,高性能,易於學習,高效編碼,生產可用

FastAPI 是一個用於構建 API 的現代、快速(高性能)的 web 框架,使用 Python 3.6+ 並基於標准的 Python 類型提示。

關鍵特性:

  • 快速:可與 NodeJS 和 Go 比肩的極高性能(歸功於 Starlette(網絡工具包) 和 Pydantic(數據認證))。最快的 Python web 框架之一。
  • 高效編碼:提高功能開發速度約 200% 至 300%。*
  • 更少 bug:減少約 40% 的人為(開發者)導致錯誤。*
  • 智能:極佳的編輯器支持。處處皆可自動補全,減少調試時間。
  • 簡單:設計的易於使用和學習,閱讀文檔的時間更短。
  • 簡短:使代碼重復最小化。通過不同的參數聲明實現豐富功能。bug 更少。
  • 健壯:生產可用級別的代碼。還有自動生成的交互式文檔。
  • 標准化:基於(並完全兼容)API 的相關開放標准:OpenAPI (以前被稱為 Swagger) 和 JSON Schema。

FastAPI可以用來做什么

  • 由Sebastian Ramirez 開發
  • 開發 web API
  • 開發網站
  • 做一個測試平台
  • 做一個持續集成工具
  • 生成文檔

為什么要學習FastAPI

  • FastAPI的使用方法和設計參考了幾十個python明星項目,博采眾長,吸收各家精華
  • FastAPI和Fast一樣簡約
  • FastAPI非常新,並且基於python3.6的類型聲明系統
  • 自動生成文檔
  • 類型聲明和數據檢驗
  • 內置身份認證
  • 性能強
  • 原生支持異步
  • 強大的依賴注入系統
  • GraphQL和Websocket支持

可選依賴¶

用於 Pydantic:

  • ujson - 更快的 JSON 「解析」。
  • email_validator - 用於 email 校驗。

用於 Starlette:

  • requests - 使用 TestClient 時安裝。
  • aiofiles - 使用 FileResponse 或 StaticFiles 時安裝。
  • jinja2 - 使用默認模板配置時安裝。
  • python-multipart - 需要通過 request.form() 對表單進行「解析」時安裝。
  • itsdangerous - 需要 SessionMiddleware 支持時安裝。
  • pyyaml - 使用 Starlette 提供的 SchemaGenerator 時安裝(有 FastAPI 你可能並不需要它)。
  • graphene - 需要 GraphQLApp 支持時安裝。
  • ujson - 使用 UJSONResponse 時安裝。

用於 FastAPI / Starlette:

  • uvicorn - 用於加載和運行你的應用程序的服務器。
  • orjson - 使用 ORJSONResponse 時安裝。

你可以通過 pip install fastapi[all] 命令來安裝以上所有依賴。

# python和pycharm安裝
# anaconda創建虛擬環境
conda create -n fastapi python=3.9
# 進入/切換到指定名稱的虛擬環境,如果不帶任何參數,則默認回到全局環境base中。
# conda activate  <虛擬環境名稱>
conda activate fastapi 
# 退出當前虛擬環境
conda deactivate

安裝 FastAPI¶

# 安裝所有的可選依賴及對應功能包括了 uvicorn,你可以將其用作運行代碼的服務器
pip install fastapi[all]  # 安裝所有組件
# 分開來安裝
pip install fastapi
# 安裝uvicorn來作為服務器:
pip install uvicorn[standard]

創建FastAPI項目並運行

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    # 返回字符串
    # return "hello world"
    # 返回列表
    # return ["項目1", "項目2", "項目3"]
    # 返回json格式
    return {"message": "Hello World"}


@app.get("/hello/{name}")
async def say_hello(name: str):
    return {"message": f"Hello {name}"}

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main.py:app --reload

url和url模板渲染、template

main.py代碼:

from fastapi import FastAPI  # 導入fastapi
from starlette.requests import Request
from starlette.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.get("/")
async def main(request: Request):
    #  context: dict, 上下文管理器 flask沒有這個是因為它本身做了這個 不寫會報錯
    # hello 鍵 是變量 會傳給 templates文件夾中的index.html
    return templates.TemplateResponse('index.html', {'request': request, 'hello': 'world'})


@app.get("/{item_id}/")
async def item_id(request: Request, item_id):
    return templates.TemplateResponse('index.html', {'request': request, "item_id": item_id})


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main.py:app --reload

templates/index.html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>HELLO FastAPI...</h1>
    <h1>{{ hello }}</h1>
    <h1>{{ item_id }}</h1>
</body>
</html>

form表單與登錄頁面

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>HELLO FastAPI...</h1>
    <h1>{{ hello }}</h1>
    <h1>{{ item_id }}</h1>
    <h1>HELLO...{{ username }}</h1>
    <h1>HELLO...{{ password }}</h1>
</body>
</html>

post.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="container">
    <form action="/user/" enctype="application/x-www-form-urlencoded" method="post">
        <label for="">username</label>
        <br>
        <input type="username" name="username">
        <br>
        <label for="">password</label>
        <br>
        <input type="password" name="password">
        <br><br>
        <input type="submit">
    </form>
</div>
</body>
</html>

main.py

from fastapi import FastAPI, Form
from starlette.requests import Request
from starlette.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.post("/user/")
async def create_upload_files(request: Request, username: str = Form(...), password: str = Form(...)):
    # flask的做法:寫在函數體里面 Request.get.form('index.html')
    print('username', username)
    print('password', password)

    # return {'text_1': text_1, 'text_2': text_2}
    return templates.TemplateResponse('index.html', {'request': request, 'username': username, 'password': password})


@app.get("/")
async def main(request: Request):
    #  context: dict, 上下文管理器 flask沒有這個是因為它本身做了這個 不寫會報錯
    # hello 鍵 是變量 會傳給 templates文件夾中的index.html
    return templates.TemplateResponse('post.html', {'request': request})


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main.py:app --reload

file上傳文件

main.py

from fastapi import FastAPI, Form, File, UploadFile
from typing import List
from starlette.requests import Request
from starlette.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.post("/files/")
async def files(
        request: Request,
        files_list: List[bytes] = File(...),  # List 可以上傳多個
        files_name: List[UploadFile] = File(...),
):
    return templates.TemplateResponse('index.html',
                                      {
                                          'request': request,
                                          'file_sizes': [len(file) for file in files_list],  # 字節長度表示文件大小
                                          'filenames': [file.filename for file in files_name],  # 文件名
                                      })


@app.post("/create_file/")
async def create_file(
        request: Request,
        file: bytes = File(...),  # 單個文件 bytes這里指定什么類型,后面就自動給它什么類型(前提是有這個類型)
        fileb: UploadFile = File(...),
        notes: str = Form(...),
):
    return templates.TemplateResponse('index.html',
                                      {
                                          'request': request,
                                          "file_size": len(file),  # 文件大小
                                          "notes": notes,  # 注釋
                                          "fileb_content_type": fileb.content_type,  # 文件類型
                                      })


@app.get("/")
async def main(request: Request):
    return templates.TemplateResponse("post.html", {"request": request})


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main.py:app --reload

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div class="container">
        <h1>NO.1</h1>
        <h2>File Name : {{ filenames }}</h2>
        <h2>File Size : {{ file_sizes }}</h2>

        <h1>NO.2</h1>
        <h2>File Size : {{ file_size }}</h2>
        <h2>File Notes : {{ notes }}</h2>
        <h2>File Type : {{ fileb_content_type }}</h2>
    </div>
</body>
</html>

post.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/files/" enctype="multipart/form-data" method="post">
        <input name="files_list" type="file" multiple><br><br>
        <input name="files_name" type="file" multiple><br><br>
        <input type="submit" value="點擊這里顯示文件名字與大小">
    </form>
    <br><br><br>

    <form action="/create_file/" enctype="multipart/form-data" method="post">
        <input type="file" name="file" multiple><br><br>
        <input type="file" name="fileb" multiple><br><br>
        <input type="text" name="notes" multiple><br><br>
        <input type="submit" value="點擊這里顯示文件屬性">
    </form>

</body>
</html>

文檔自動生成

FastAPI-Swagger UI:   http://127.0.0.1:8000/docs
FastAPI-ReDoc:      http://127.0.0.1:8000/redoc

發送POST請求

main.py 代碼:

from fastapi import FastAPI

app = FastAPI()


# @app.post("/login")
# async def login():
#     return {"msg": "login success"}

@app.api_route("/login", methods=["GET", "POST", "PUT"])
def login():
    return {"msg": "login success"}

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

獲取URL參數

main.py 代碼:

http://127.0.0.1:8000/user/5

from fastapi import FastAPI

app = FastAPI()


@app.get("/user/{pk}")
def user(pk):
    return {"pk": pk}

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

獲取請求頭和請求體的參數

http://127.0.0.1:8000/user/?pk=1

main.py

from fastapi import FastAPI
app = FastAPI()
@app.get("/user/")
def user(pk):
    return {"pk": pk}

pip install python-multipart  # 使用Form 需要安裝

from fastapi import FastAPI, Header, Body, Form

app = FastAPI()


@app.get("/user/")
def user(pk, token=Header(None)):
    return {"pk": pk, "token": token}  # 請求頭


# @app.post("/login")
# def login(data=Body(None)):
#     return {"data": data}  # 請求體 json

@app.post("/login")
def login(username=Form(None), password=Form(None)):
    return {"data": {"username": username, "password": password}}  # 請求體 Form 表單

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

返回圖片和定制返回信息

main.py

from fastapi import FastAPI
from fastapi.responses import JSONResponse, HTMLResponse, FileResponse

app = FastAPI()

@app.get("/user")
def user():
    # return {"msg": "get user"}
    return JSONResponse(content={"msg": "get user"},
                        status_code=202,
                        headers={"name": "xiaobai"})

@app.get("/")
def user():
    html_content = """
    <html>
        <body><p style="color:red">Hello World</p></body>
    </html>
    """
    return HTMLResponse(content=html_content)

@app.get("/avatar")
def user():
    avatar = 'static/mage.jpg'
    return FileResponse(avatar)  # 
    # return FileResponse(path=avatar, filename="mage.jpg")  # 下載圖片
# pip install aiofiles

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

jinja2模板返回HTML頁面

http://127.0.0.1:8000/?username=xiaobai

main.py

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates  # pip install jinja2

app = FastAPI()
template = Jinja2Templates("templates")


@app.get("/")
def user(username, req: Request):
    # context 必須加 key必須為"request"固定不可改變
    return template.TemplateResponse("index.html", context={"request": req, "name": username})

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>首頁</h1>
    <p>歡迎來到 FastAPI</p>
    <p>今天是2021年12月25日星期六</p>
    <p>用戶名:{{ name }}</p>
</body>
</html>

實戰小應用

main.py

from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates  # pip install jinja2
from fastapi.responses import RedirectResponse

app = FastAPI()
template = Jinja2Templates("templates")

todos = ["寫日記", "看電影", "玩游戲"]


@app.get("/")
def index(req: Request):
    return template.TemplateResponse("index.html", context={"request": req, "todos": todos})


@app.post("/todo")
def todo(todo=Form(None)):
    """處理用戶發送過來的todolist數據"""
    todos.insert(0, todo)
    return RedirectResponse("/", status_code=302)  # 默認為307 不能跳轉 get請求

# if __name__ == '__main__':
#     import uvicorn
#
#     uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>待辦事項</h1>

    <div>
        <form action="/todo" method="post">
            <input type="text" placeholder="請添加待辦事項..." name="todo">
            <input type="submit" value="添加">
        </form>
    </div>

    {% for todo in todos %}
        <p>{{ todo }}</p>
    {% endfor %}


</body>
</html>

FastAPI集成Bootstrap

main.py

from fastapi import FastAPI, Form
from starlette.requests import Request
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory='static'), name='static')


@app.post("/user/")
async def files(
        request: Request,
        username: str = Form(...),
        password: str = Form(...),
):
    print('username', username)
    print('password', password)
    return templates.TemplateResponse(
        name="index.html",
        context={
            "request": request,
            "username": username,
        })


@app.get("/")
async def main(request: Request):
    if __name__ == '__main__':
        return templates.TemplateResponse(name='signin.html', context={'request': request})


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

signin.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
<!--    <link rel="icon" href="../../favicon.ico">-->
    <link rel="icon" href="{{ url_for('static', path='/images/favicon.ico') }}">

    <title>Signin Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="{{ url_for('static', path='/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="{{ url_for('static', path='/css/signin.css') }}" rel="stylesheet">

    <![endif]-->
  </head>

  <body>

    <div class="container">

      <form class="form-signin" action="/user/" enctype="application/x-www-form-urlencoded" method="post">
        <h2 class="form-signin-heading">Please sign in</h2>
        <label for="inputEmail" class="sr-only">username</label>
        <input type="username" name="username" id="inputEmail" class="form-control" placeholder="username" required autofocus>
        <label for="inputPassword" class="sr-only">Password</label>
        <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
        <div class="checkbox">
          <label>
            <input type="checkbox" value="remember-me"> Remember me
          </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      </form>

    </div> <!-- /container -->

  </body>
</html>

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="{{ url_for('static', path='/images/favicon.ico') }}">

    <title>Jumbotron Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="{{ url_for('static', path='/css/bootstrap.min.css') }}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="{{ url_for('static', path='/css/jumbotron.css') }}" rel="stylesheet">

</head>

<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Project name</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <form class="navbar-form navbar-right">
                <div class="form-group">
                    <input type="text" placeholder="Email" class="form-control">
                </div>
                <div class="form-group">
                    <input type="password" placeholder="Password" class="form-control">
                </div>
                <button type="submit" class="btn btn-success">Sign in</button>
            </form>
        </div><!--/.navbar-collapse -->
    </div>
</nav>

<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
    <div class="container">
        <h1>Hello, {{ username }}!</h1>
        <p>This is a template for a simple marketing or informational website. It includes a large callout called a
            jumbotron and three supporting pieces of content. Use it as a starting point to create something more
            unique.</p>
        <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more &raquo;</a></p>
    </div>
</div>

<div class="container">
    <!-- Example row of columns -->
    <div class="row">
        <div class="col-md-4">
            <h2>Heading</h2>
            <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris
                condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis
                euismod. Donec sed odio dui. </p>
            <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2>Heading</h2>
            <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris
                condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis
                euismod. Donec sed odio dui. </p>
            <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>
        <div class="col-md-4">
            <h2>Heading</h2>
            <p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula
                porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut
                fermentum massa justo sit amet risus.</p>
            <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>
    </div>

    <hr>

    <footer>
        <p>&copy; 2016 Company, Inc.</p>
    </footer>
</div> <!-- /container -->


<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"
        integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ"
        crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
<script src="{{ url_for('static', path='/js/bootstrap.min.js') }}"></script>
</body>
</html>

1 url和交互式API文檔

ajax請求不能重定向

from fastapi import FastAPI

app = FastAPI()


# read_item_me必須寫在read_item前面
@app.get("/me/xx")
async def read_item_me():
    return {"me": 'me'}


@app.get("/me/{item_id}")
async def read_item(item_id: str):
    return {"item_id": item_id, }
# 路徑參數 item_id 的值將作為參數 item_id 傳遞給你的函數。

@app.get("/")
async def main():
    return {"message": "Hello, FastAPI"}

if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動




from fastapi import FastAPI
from enum import Enum


# 枚舉
class Name(str, Enum):
    Allan = "張三"
    Jon = "李四"
    Bob = "王五"


app = FastAPI()


@app.get("/{who}")
async def get_day(who: Name):
    if who == Name.Allan:
        return {"who": who, "message": "張三是德國人"}
    if who.value == "李四":
        return {"who": who, "message": "李四是英國人"}
    return {"who": who, "message": "王五是法國人"}


@app.get("/")
async def main():
    return {"message": "Hello, FastAPI"}


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

2 Query Parameters查詢參數

from fastapi import FastAPI

app = FastAPI()
fake_item_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


# http://127.0.0.1:8000/items/?skip=0&limit=2
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_item_db[skip: skip + limit]  # 默認返回0-10個


@app.get("/i/")
async def i(A: str = 'HI..', B: str = 'Hello..', C: str = 'He..'):
    return {'cc': A + B + C}, {'dd': B + C}


# http://127.0.0.1:8000/ii/?A=100
@app.get("/ii/")
async def ii(A: int = 0, B: int = 10, C: int = 20):
    return {'cc': A + B + C}, {'dd': B + C}


@app.get("/iii/")
async def iii(A: int = 0, B: int = 10, C: int = 20):
    return 'A+B+C', A + B + C


# http://127.0.0.1:8000/xxx/item_id=aaaa
# bool與類型轉換
@app.get("/xxx/{item_id}")
async def xxx(item_id: str, QQ: str = None, SS: bool = False):
    item = {"item_id": item_id}
    if QQ:
        item.update({"QQ": QQ})
    if not SS:  # 如果SS是假
        item.update(
            {"item_id": "This is SSSSSS"}
        )
    return item


# http://127.0.0.1:8000/user/1/item/2
# http://127.0.0.1:8000/user/1/item/a?q=dddd
# 多路徑 和 查詢參數 和 必填字段
@app.get("/user/{user_id}/item/{item_id}")
async def read_user_item(user_id: int, item_id: str, q: str = None, short: bool = False):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

3 Request_Body請求正文(交互式API文檔)

當你需要將數據從客戶端(例如瀏覽器)發送給 API 時,你將其作為「請求體」發送。

請求體是客戶端發送給 API 的數據。響應體是 API 發送給客戶端的數據。

你的 API 幾乎總是要發送響應體。但是客戶端並不總是需要發送請求體。

你不能使用 GET 操作(HTTP 方法)發送請求體。

要發送數據,你必須使用下列方法之一:POST(較常見)、PUT、DELETE 或 PATCH。

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):
    print(item.dict())
    return item, '人生沒有無意義的經歷!'


@app.put("/items/{item_id}")
async def create_item2(item_id: int, item: Item, q: str = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    print(result)
    return result


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

4 Query_Validations查詢參數和字符串驗證

from fastapi import FastAPI, Query
from typing import List

app = FastAPI()


#############################################################
# 限制長度
@app.get("/items/")
async def read_item(q: str = Query(None, min_length=3, max_length=50)):
    # 填None就是默認值  填...則是必填項
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})

    return results


###########################################
# 正則表達式
@app.get("/items2/")
async def read_item2(q: str = Query(None, min_length=3, max_length=50, regex="^nice")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


##############################################
# 列表
@app.get("/items3/")
async def read_item3(q: List[str] = Query(["foo", "bar"])):
    query_items = {"q": q}
    return query_items


################################################
# http://127.0.0.1:8000/items4/?item-query=ddddd
# 別名參數
@app.get("/items4/")
async def read_items4(q: str = Query(None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


########################################
# http://127.0.0.1:8000/items5/?item-query=13771122333
# 棄用參數
@app.get("/items5/")
async def read_items5(
        q: str = Query(
            None,
            alias="item-query",
            title="Query string",
            description="Query string for the items to search in the database that have a good match",
            min_length=3,
            max_length=50,
            regex=r"^1[3-9]\d{9}$",
            deprecated=True
        )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

5 Path_Numeric路徑參數與數值驗證

from fastapi import FastAPI, Query, Path

app = FastAPI()


# http://127.0.0.1:8000/items/100?item-query=rrrr&size=0.8
@app.get("/items/{item_id}")
async def read_item(
        item_id: int = Path(..., title="The ID of the item to get", ge=50, le=100),
        q: str = Query(None, alias="item-query"),
        size: float = Query(1, gt=0, lt=10.5)
):
    results = {"items": item_id}
    if q:
        results.update({"q": q})

    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

6 Body_Multiple_Parameters多參數Body混合

混合使用 Path、Query 和請求體參數

from typing import Optional

from fastapi import FastAPI, Path
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


# 請注意,在這種情況下,將從請求體獲取的 item 是可選的。因為它的默認值為 None。
# http://127.0.0.1:8000/items/88?q=AAAA
@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: Optional[str] = None,
        item: Optional[Item] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if item:
        results.update({"item": item})
    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

多個請求體參數¶

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

請求體中的單一值¶

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items/{item_id}")
async def update_item(
        item_id: int, item: Item, user: User, importance: int = Body(...)
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

多個請求體參數和查詢參數¶

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items/{item_id}")
async def update_item(
        *,
        item_id: int,
        item: Item,
        user: User,
        importance: int = Body(..., gt=0),
        q: Optional[str] = None
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    if q:
        results.update({"q": q})
    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

嵌入單個請求體參數¶

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

7 Body_Fields字段驗證

請求體 - 字段¶

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

聲明模型屬性¶

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None


@app.put("/items/{item_id}")
# async def update_item(item_id: int, item: Item = Body(..., example={})):
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

8 Body_Nested_Models_嵌套模型

請求體 - 嵌套模型¶

List 字段¶

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: list = []


@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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

具有子類型的 List 字段¶聲明具有子類型的 List¶Set 類型¶

from typing import List, Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: list = []
    tags1: List[str] = []
    tags2: List[str] = []
    tags3: Set[str] = set()


@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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

定義子模型¶

from typing import Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Image(BaseModel):
    url: str
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    image: Optional[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__':
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)

# uvicorn main:app --reload  終端啟動

深度嵌套模型¶

from typing import List, Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image]] = None


class Offer(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    items: List[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):
    return offer


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM