import random

導(dǎo)入(FastAPI)


FastAPI 的導(dǎo)入聲明則被歸類(lèi)到不同的包中,所以看起來(lái)很復(fù)雜。下面的代碼塊導(dǎo)入了對(duì)表單字段輸入的支持、對(duì)返回不同類(lèi)型返回的支持,以及通過(guò)模板引擎渲染靜態(tài)文件和 HTML 文件的支持。

from fastapi import FastAPI, Form, Request
from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import random
import uvicorn

最最基礎(chǔ)的導(dǎo)入應(yīng)該長(zhǎng)這個(gè)樣子:

from fastapi import FastAPI
from pydantic import BaseModel
import random # needed for generating a random number for an API
import uvicorn # optional if you run it directly from terminal

初始化(Flask)


Flask 可以處理靜態(tài)文件及模板引擎,初始化代碼如下:

app = Flask(__name__)

初始化(FastAPI)


除了標(biāo)準(zhǔn)初始化流程,還需“掛載”靜態(tài)文件路徑。同樣,模板引擎渲染也需要聲明一個(gè)變量。大部分的初始化代碼都是在用基于 Pydantic 的語(yǔ)法創(chuàng)建數(shù)據(jù)模型類(lèi)。

app = FastAPI()
# 可選,用于渲染靜態(tài)文件
app.mount("/static", StaticFiles(directory="static"), name="static")
# 可選,用于模板引擎渲染網(wǎng)頁(yè)
templates = Jinja2Templates(directory="templates")
# 視使用情況
class Item(BaseModel):
language = 'english'

Hello World(Flask)


創(chuàng)建一個(gè)可以返回字符串的路由。

@app.route('/')
def hello():
return "Hello World!"

Hello World(FastAPI)

FastAPI 版本的“Hello World”如下。因?yàn)槟J(rèn)返回類(lèi)型為 JSON,所以需要修改 response_class 到 PlainTextResponse 來(lái)返回字符串。async 字段會(huì)讓異步代碼更簡(jiǎn)單,雖然不是必需,但除非你的代碼不支持異步,否則我建議你最好加上。

@app.get("/", response_class=PlainTextResponse)
async def hello():
return "Hello World!"

隨機(jī)數(shù)(Flask)


在 Flask 服務(wù)器上返回隨機(jī)生成數(shù)字 API 的代碼如下。

@app.route('/random-number')
def random_number():
return str(random.randrange(100))

隨機(jī)數(shù)(FastAPI)


FastAPI 的代碼只需簡(jiǎn)單修改:

@app.get('/random-number', response_class=PlainTextResponse)
async def random_number():
return str(random.randrange(100))

檢查 isAlpha(Flask)


下面我們將測(cè)試一個(gè)接收名為 text 的查詢參數(shù),并返回 JSON 結(jié)果的 API。在 Flask 中,這一步是通過(guò)路由裝飾器設(shè)置完成的。在這里我們將其設(shè)置為僅接受 GET 請(qǐng)求。

@app.route('/alpha', methods=['GET'])
def alpha():
text = request.args.get('text', '')
result = {'text': text, 'is_alpha' : text.isalpha()}
return jsonify(result)

檢查 isAlpha(FastAPI)

首先定義 HTTP 請(qǐng)求方法和裝飾器,這在 FastAPI 中被稱(chēng)作操作(operation)。GET 操作需要調(diào)用 app.get 來(lái)完成;而對(duì)于多個(gè)功能相同的 HTTP 請(qǐng)求方法則需要將其邏輯打包到一個(gè)函數(shù)中,然后在其各自的操作中獨(dú)立調(diào)用。查詢參數(shù)需要和類(lèi)型提示一起指定。text: str 表示一個(gè)需要字符串查詢參數(shù) text。也可以通過(guò)指定默認(rèn)值 text = ‘text’,使其成為一個(gè)可選參數(shù)。

app.get('/alpha')
async def alpha(text: str):
result = {'text': text, 'is_alpha' : text.isalpha()}
return result

創(chuàng)建新 User(Flask)


添加新數(shù)據(jù)到數(shù)據(jù)庫(kù),通常需要使用 POST 請(qǐng)求。下面的例子接收兩個(gè)表單字段,返回一個(gè) JSON 結(jié)果。

@app.route('/create-user', methods=['POST'])
def create_user():
id = request.form.get('id', '0001')
name = request.form.get('name', 'Anonymous')
# 用于認(rèn)證、校驗(yàn)、更新數(shù)據(jù)庫(kù)
data = {'id': id, 'name': name}
result = {'status_code': '0', 'status_message' : 'Success', 'data': data}
return jsonify(result)

創(chuàng)建新 User(FastAPI)


POST 請(qǐng)求由 app.post 裝飾器處理。默認(rèn)情況下的實(shí)現(xiàn)是基于 JSON 或查詢參數(shù)的,如果要聲明輸入?yún)?shù),則需指定 Form(…)。

@app.post('/create-user')
async def create_user(id: str = Form(...), name: str = Form(...)):
# 用于認(rèn)證、校驗(yàn)、更新數(shù)據(jù)庫(kù)
data = {'id': id, 'name': name}
result = {'status_code': '0', 'status_message' : 'Success', 'data': data}
return result

更新 Language(Flask)


目前為止,本文已經(jīng)介紹了查詢參數(shù)以及表單字段的代碼。下面這個(gè)例子則將根據(jù) JSON 輸入更新一個(gè)名為 language 的變量,這類(lèi)對(duì)現(xiàn)有數(shù)據(jù)更新的操作,建議使用 PUT 方法。展示的代碼中沒(méi)有直接指定 PUT 方法,而是通過(guò)條件語(yǔ)句來(lái)實(shí)現(xiàn)。

@app.route('/update-language', methods=['POST', 'PUT', 'GET', 'DELETE'])
def update_language():
language = 'english'
if request.method == 'PUT':
json_data = request.get_json()
language = json_data['language']
return "Successfully updated language to %s" % (language)

更新 Language(FastAPI)


同理,PUT 操作是由 app.put 裝飾器處理。在初始化的過(guò)程中,我們?cè)x過(guò)以下的 class:

class Item(BaseModel):
language = 'english'

然后我們需要將這個(gè) class 作為 item 輸入?yún)?shù)的類(lèi)型提示。直接使用 variable_name.attribute_name 語(yǔ)法調(diào)用即可,解析會(huì)在后臺(tái)正確完成。在本例中,我們用 item.language。

@app.put('/update-language', response_class=PlainTextResponse)
async def update_language(item: Item):
language = item.language
return "Successfully updated language to %s" % (language)

HTML 網(wǎng)頁(yè)(Flask)

在 Flask 中服務(wù)網(wǎng)頁(yè)相對(duì)比較簡(jiǎn)單,使用 Jinja2 模板引擎即可完成。我們只需要在 templates 的文件夾中聲明 HTML 文件,如果你需要提供靜態(tài)文件,則需要將其放入名為 static 的文件夾中。下面的代碼示例使用 index.html 渲染網(wǎng)頁(yè),變量可以作為輸入?yún)?shù)傳入:

@app.route('/get-webpage', methods=['GET'])
def get_webpage():
return render_template('index.html', message="Contact Us")

HTML 網(wǎng)頁(yè)(FastAPI)


在初始化過(guò)程中,我們“掛載”了一個(gè) static 文件夾,用于提供靜態(tài)文件:

app.mount("/static", StaticFiles(directory="static"), name="static")

基于 Jinja2Templates 創(chuàng)建了一個(gè)變量:

templates = Jinja2Templates(directory="templates")

這些都是用于渲染 HTML 模板的。為提供 HTML 網(wǎng)頁(yè),我們需要將 response_class 改為 HTMLResponse。如果你用的不是模板引擎,那么可以直接將結(jié)果返回為字符串。
Request 參數(shù)需要返回模板以及自定義參數(shù)。

@app.get('/get-webpage', response_class=HTMLResponse)
async def get_webpage(request: Request):
return templates.TemplateResponse("index.html", {"request": request, "message": "Contact Us"})

文件響應(yīng)(Flask)

若要將文件返回給用戶,最佳的處理方式是通過(guò)內(nèi)置函數(shù) send_from_directory,如果路徑或文件是通過(guò)用戶輸入獲得,那么則更應(yīng)如此。該內(nèi)置函數(shù)接受兩個(gè)主要輸入:

文件路徑

文件名

另外,你也可以額外聲明其他參數(shù),諸如:as_attachment,通過(guò)修改 Content-Disposition 頭來(lái)指定其為附件。路徑參數(shù)可以通過(guò)<type:variable_name>語(yǔ)法來(lái)指定。在本例中,我們用<string:language>

@app.route('/get-language-file/<string:language>', methods=['GET'])
def get_language_file(language):
return send_from_directory('./static/language', language + '.json', as_attachment=True)

文件響應(yīng)(FastAPI)

FastAPI 根據(jù)要求和需要,提供了相當(dāng)多的響應(yīng)類(lèi)型。如果需要返回文件,可以用 FileResponse 或 StreamingResponse。在本文中我們將展示 FileResponse 的使用案例,它接受以下輸入:

path:需要流式傳輸?shù)奈募窂?/p>

headers:任何自定義頭,以字典形式輸入

media_type:給定媒體類(lèi)型的字符串。默認(rèn)通過(guò)文件名或路徑推斷媒體類(lèi)型。

filename:設(shè)置后,會(huì)被響應(yīng)的 Content-Disposition 引用。代碼展示:

@app.get('/get-language-file/{language}')
async def get_language_file(language: str):
file_name = "%s.json" % (language)
file_path = "./static/language/" + file_name
return FileResponse(path=file_path, headers={"Content-Disposition": "attachment; filename=" + file_name})

主函數(shù)(Flask)


Flask 中主函數(shù)應(yīng)如下:

if __name__ == '__main__':
    app.run('0.0.0.0',port=8000)

然后在終端中通過(guò)這條命令運(yùn)行文件:

python myapp.py

主函數(shù)(FastAPI)


FastAPI 則需要導(dǎo)入 uvicorn。

import uvicorn

并且用如下方法指定主函數(shù)(myapp 為文件名,app 為 FastAPI 實(shí)例所聲明的變量名):

if __name__ == '__main__':
uvicorn.run('myapp:app', host='0.0.0.0', port=8000)

然后在終端中正常運(yùn)行即可:

python myapp.py

更好的方法則是不調(diào)用主函數(shù),在終端中通過(guò) uvicorn 直接運(yùn)行。

uvicorn myapp:app

還可以再額外指定一些參數(shù),諸如:

reload:?jiǎn)⒂米詣?dòng)加載功能,修改文件后會(huì)刷新服務(wù)器。對(duì)本地開(kāi)發(fā)非常有用。

port:服務(wù)器端口,默認(rèn)為 8000。這條代碼可以將端口號(hào)改為 5000:

uvicorn myapp:app --reload --port 5000

Flask 服務(wù)器


以下為 Flask 服務(wù)器中的完整 代碼。

# 導(dǎo)入聲明
from flask import Flask, request, jsonify, render_template, send_from_directory
import random
# 初始化
app = Flask(__name__)

# hello world,GET 方法,返回字符串
@app.route('/')
def hello():
return "Hello World!"
# 隨機(jī)數(shù),GET 方法,返回字符串
@app.route('/random-number')
def random_number():
return str(random.randrange(100))

# 檢查 isAlpha,GET 方法,查詢參數(shù),返回 JSON
@app.route('/alpha', methods=['GET'])
def alpha():
text = request.args.get('text', '')
result = {'text': text, 'is_alpha' : text.isalpha()}
return jsonify(result)

# 創(chuàng)建新 user,POST 方法,表單字段,返回 JSON
@app.route('/create-user', methods=['POST'])
def create_user():
id = request.form.get('id', '0001')
name = request.form.get('name', 'Anonymous')

# 用于認(rèn)證、校驗(yàn)、更新數(shù)據(jù)庫(kù)
data = {'id': id, 'name': name}
result = {'status_code': '0', 'status_message' : 'Success', 'data': data}
return jsonify(result)

# 更新 language,PUT 方法,JSON 輸入,返回字符串
@app.route('/update-language', methods=['POST', 'PUT', 'GET', 'DELETE'])
def update_language():
language = 'english'

if request.method == 'PUT':
json_data = request.get_json()
language = json_data['language']

return "Successfully updated language to %s" % (language)

# 服務(wù)網(wǎng)頁(yè),GET 方法,返回 HTML
@app.route('/get-webpage', methods=['GET'])
def get_webpage():
return render_template('index.html', message="Contact Us")

# 文件響應(yīng),GET 方法,返回文件為附件
@app.route('/get-language-file/<string:language>', methods=['GET'])
def get_language_file(language):
return send_from_directory('./static/language', language + '.json', as_attachment=True)

# main
if __name__ == '__main__':
app.run('0.0.0.0',port=8000)

FastAPI 服務(wù)器


以下 代碼 是使用 FastAPI 實(shí)現(xiàn)的相同功能。

# 導(dǎo)入聲明
from fastapi import FastAPI, Form, Request
from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

from pydantic import BaseModel
import random
import uvicorn

# 初始化
app = FastAPI()

# “掛載”靜態(tài)文件夾,用于渲染靜態(tài)文件
app.mount("/static", StaticFiles(directory="static"), name="static")

# Jinja2 模板,用于利用模板引擎返回網(wǎng)頁(yè)
templates = Jinja2Templates(directory="templates")

# Pydantic 數(shù)據(jù)模型 class
class Item(BaseModel):
#language: str
language = 'english'

# hello world,GET 方法,返回字符串
@app.get("/", response_class=PlainTextResponse)
async def hello():
return "Hello World!"

# 隨機(jī)數(shù),GET 方法,返回字符串
@app.get('/random-number', response_class=PlainTextResponse)
async def random_number():
return str(random.randrange(100))

# 檢查 isAlpha,GET 方法,查詢參數(shù),返回 JSON
@app.get('/alpha')
async def alpha(text: str):
result = {'text': text, 'is_alpha' : text.isalpha()}
return result

# 創(chuàng)建新 user,POST 方法,表單字段,返回 JSON
@app.post('/create-user')
async def create_user(id: str = Form(...), name: str = Form(...)):
# 用于認(rèn)證、校驗(yàn)、更新數(shù)據(jù)庫(kù)
data = {'id': id, 'name': name}
result = {'status_code': '0', 'status_message' : 'Success', 'data': data}
return result
# 更新 language,PUT 方法,JSON 輸入,返回字符串
@app.put('/update-language', response_class=PlainTextResponse)
async def update_language(item: Item):
language = item.language
return "Successfully updated language to %s" % (language)

# 服務(wù)網(wǎng)頁(yè),GET 方法,返回 HTML
@app.get('/get-webpage', response_class=HTMLResponse)
async def get_webpage(request: Request):
return templates.TemplateResponse("index.html", {"request": request, "message": "Contact Us"})

# 文件響應(yīng),GET 方法,返回文件為附件
@app.get('/get-language-file/{language}')
async def get_language_file(language: str):
file_name = "%s.json" % (language)
file_path = "./static/language/" + file_name

return FileResponse(path=file_path, headers={"Content-Disposition": "attachment; filename=" + file_name})

# main
if __name__ == '__main__':
uvicorn.run('myapp:app', host='0.0.0.0', port=8000)

第三步:文檔

在成功運(yùn)行 FastAPI 服務(wù)器后,你將得到兩個(gè)用于文檔的額外路由。交互式文檔(Swagger UI)第一個(gè)路由是交互式文檔 Swagger UI。如果在端口 8000 上運(yùn)行的服務(wù)器,那么就可以通過(guò)以下 URL 訪問(wèn):

http://localhost:8000/docs

進(jìn)入之后你會(huì)看到以下界面:

這是一個(gè)交互式的文檔,你可以在其中單獨(dú)測(cè)試 API。點(diǎn)擊 /alpha 路由時(shí),你應(yīng)該能看到以下界面:

在 text 字段輸入字符串后,點(diǎn)擊“Try it out”按鈕。接著再點(diǎn)擊“Execute”按鈕,會(huì)得到以下結(jié)果:

ReDoc

除此之外,FastAPI 還提供另一種文檔 ReDoc。通過(guò)以下 URL 訪問(wèn):

http://localhost:8000/redoc

你會(huì)看到以下文檔界面。

第四步:結(jié)論

總結(jié)時(shí)間:

本文開(kāi)篇先是 FastAPI 核心概念的背景介紹,然后是 Flask 和 FastAPI 運(yùn)行所需模塊的安裝。安裝結(jié)束后,我們測(cè)試了不同 HTTP 請(qǐng)求方法、輸入請(qǐng)求、輸出響應(yīng)下的幾種 API,并分別對(duì)比了這些功能在 Flask 和 FastAPI 下代碼的區(qū)別。

本文概括介紹了如何將 Flask 服務(wù)器遷移到 FastAPI 服務(wù)器的基本過(guò)程,并列舉了使用實(shí)例。 延伸閱讀

https://medium.com/better-programming/migrate-from-flask-to-fastapi-smoothly-cc4c6c255397](https://medium.com/better-programming/migrate-from-flask-to-fastapi-smoothly-cc4c6c255397 參考資料

Uvicorn 的 Github 頁(yè)面:

https://github.com/encode/uvicorn

Uvicorn 文檔:

https://www.uvicorn.org/

FastAPI 的 Github 頁(yè)面:

https://github.com/tiangolo/fastapi

FastAPI 文檔:

https://fastapi.tiangolo.com/

官方文檔翻譯:

https://github.com/apachecn/fastapi-docs-cn

文章轉(zhuǎn)自微信公眾號(hào)@前端之巔

上一篇:

前端 api 請(qǐng)求緩存方案

下一篇:

大規(guī)模分布式架構(gòu)中,怎樣設(shè)計(jì)和選擇 API 限流技術(shù)?
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門(mén)場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)