鍵.png)
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
這是國外一個(gè)專門做框架性能對(duì)比的網(wǎng)站(TechEmpower)的數(shù)據(jù),這是對(duì) Python 語言的常用 web 框架的測試報(bào)告,可見 fastapi 表現(xiàn)優(yōu)異。
這是詳細(xì)的鏈接,有興趣的可以看下:
除了在上邊數(shù)據(jù)方面的優(yōu)異表現(xiàn)外,它還具有如下特點(diǎn):
拋去這些,我覺著僅性能堪比 Golang 語言的 gin 框架這一條,就值得我們學(xué)習(xí)下。
下面我們來具體看下 FastApi 的使用。
在看 FastApi 之前,我們先來回憶下 Python 的異步編程和協(xié)程。
Python 1.0 發(fā)布在 1994 年,當(dāng)時(shí)對(duì)編程語言性能的要求并不像現(xiàn)在這么高,所以它在設(shè)計(jì)之初就更傾向于快速開發(fā)和便捷的語法。即便有性能的要求,多進(jìn)程多線程也完全能夠應(yīng)付。但是隨著現(xiàn)代互聯(lián)網(wǎng)的發(fā)展,對(duì)編程語言自身的性能要求就越來越高。除了多進(jìn)程和多線程模型,還逐漸演化出「協(xié)程」模型(協(xié)程,是一種用戶態(tài)的更小力度的任務(wù)運(yùn)行單元?;诰€程,可實(shí)現(xiàn)多個(gè)任務(wù)的并行。)為代表的異步編程思想。
在早期,Python 實(shí)現(xiàn)異步編程,需要地方的庫,如 Twisted、Tornado 等。從 Python3 開始,加入了對(duì)異步編程的原生支持。
yield from
,用戶可實(shí)現(xiàn)基于生成器的簡易協(xié)程;asyncio
庫,正式引入?yún)f(xié)程概念,使用關(guān)鍵字@asyncio.coroutine
和yield from
來表示協(xié)程調(diào)用;async/await
代替@asyncio.coroutine
和yield from
,可以讓我們使用同步的方式寫出異步的代碼;下面這種以async def
定義函數(shù),且用await
?關(guān)鍵字來調(diào)用函數(shù)的代碼,便是協(xié)程相關(guān)的代碼。
import asyncio
async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y
async def print_sum(x, y):
result = await compute(x, y)
print("%s + %s = %s" % (x, y, result))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
協(xié)程的運(yùn)行有 3 種方式,參考[5]
aysncio.run()
用來運(yùn)行最高層次的main()
函數(shù);await
調(diào)用協(xié)程函數(shù);asyncio.create_task()
并發(fā)運(yùn)行作為asyncio
任務(wù)的多個(gè)協(xié)程;一些其他概念:
CGI(通用網(wǎng)關(guān)接口, Common Gateway Interface),簡單來說就是解析瀏覽器等客戶端發(fā)送給服務(wù)端的請求,并組裝需要返回的 HTTP 請求的一種通用協(xié)議,處理這個(gè)過程的程序,我們就可以叫 CGI 腳本?;ヂ?lián)網(wǎng)早起的動(dòng)態(tài)網(wǎng)頁都是基于 CGI 標(biāo)準(zhǔn)的。
WSGI?是一種 Python 專用的 Web 服務(wù)器網(wǎng)關(guān)接口,它分為兩部分”服務(wù)器(或網(wǎng)關(guān))“和”應(yīng)用程序(或應(yīng)用框架)”?!阜?wù)器」,一般獨(dú)立于應(yīng)用框架,為應(yīng)用程序運(yùn)行提供環(huán)境信息和一個(gè)回調(diào)函數(shù)(Callback Function)。當(dāng)應(yīng)用程序完成處理請求后,透過回調(diào)函數(shù),將結(jié)果回傳給服務(wù)器。常用的 WSGI 服務(wù)器有: uwsgi、gunicon?!笐?yīng)用程序」,是各種實(shí)現(xiàn)了 WSGI 標(biāo)準(zhǔn)的 Python web 框架了,常用的有 Django、Flask 等。
ASGI(Asynchronous Server Gateway Interface)?是 Django 團(tuán)隊(duì)提出的一種具有異步功能的 Python web 服務(wù)器網(wǎng)關(guān)接口協(xié)議。能夠處理多種通用的協(xié)議類型,包括 HTTP,HTTP2 和 WebSocket。WSGI 是基于 HTTP 協(xié)議模式的,不支持 WebSocket,而 ASGI 的誕生則是為了解決 Python 常用的 WSGI 不支持當(dāng)前 Web 開發(fā)中的一些新的協(xié)議標(biāo)準(zhǔn)(WebSocket、Http2 等)。同時(shí),ASGI 向下兼容 WSGI 標(biāo)準(zhǔn),可以通過一些方法跑 WSGI 的應(yīng)用程序。常用的「服務(wù)器」有 Daphne、Uvicorn。
FastApi 要求 Python 在 3.6 以上,它應(yīng)用了很多 Python3 的新特性。下面我們安裝一下:
pip install fastapi uvicorn
我們使用uvicorn
來啟動(dòng)異步的 web server ,同時(shí)把uvicorn
也安裝上。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
uvicorn main:app --reload
,生產(chǎn)推薦,生產(chǎn)中把 reload 去掉。python main.py
,僅用于調(diào)試。if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
整體代碼看下來,和 Flask 的 Hellow world 類似,有程序?qū)嵗?app 用來啟動(dòng)程序,有路由和路由處理函數(shù)。
我們來看下它自帶的 Swagger 類型的文檔:
是不是很方便。
接下來,讓我們來看些復(fù)雜點(diǎn)的用法。
使用 get 方法來請求數(shù)據(jù):
@app.get('/user')
async def user(user_id: int = Query(..., title="The ID of the user to get", gt=0)):
# do somethings
return {'user_id': user_id}
QueryString 的傳遞使用了一個(gè)類Query
來做參數(shù)的校驗(yàn),Query 類繼承了相關(guān) pydandic 庫的類,實(shí)現(xiàn)了對(duì)參數(shù)的類型校驗(yàn),附默認(rèn)值等功能。
此處...
是表示 user_id 參數(shù)時(shí)必須的。若此處為 None,則表示 user_id 可選。
使用 put 方法來更新數(shù)據(jù):
@app.put('/user/{user_id}')
async def user(user_id: int = Path(..., title="The ID of the user to get", gt=0)):
# do somethings
return {'user_id': user_id}
這里的路徑參數(shù),可以使用類Path
來做類型校驗(yàn),功能和Query
類似。
使用 post 方法來創(chuàng)建數(shù)據(jù):
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
@app.post("/users/")
async def create_user(user: User):
# do somethings
return user
這里定義了一個(gè)用戶類,作為函數(shù)參數(shù)的類型。在請求時(shí),F(xiàn)astApi 會(huì)自動(dòng)的將參數(shù)注入到該類型的各對(duì)應(yīng)屬性字段。該類也起到了參數(shù)類型校驗(yàn)的作用。在函數(shù)參數(shù)類型這塊,User
類有點(diǎn)類似 Golang 中結(jié)構(gòu)體定義的函數(shù)參數(shù)類型。
使用 delete 方法來刪除數(shù)據(jù):
@app.delete('/user/{user_id}')
async def user(user_id: int = Path(..., title="The ID of the user to get", gt=0)):
# do somethings
return {'user_id': user_id}
同 put 方法的用法。
看了這些基本的用法之后,我們對(duì) FastApi 的使用有了一個(gè)初步的了解。
我們從之前的代碼中可以看到路由和路由函數(shù)在一塊的,這種方式在路由少的情況下是非常方便的,但是隨著項(xiàng)目復(fù)雜度的提升,路由逐漸增多,如果路由設(shè)計(jì)不合理,便會(huì)非常的不好維護(hù)。
針對(duì)這種情況,F(xiàn)astApi 提供了 APIRouter
類來規(guī)劃設(shè)計(jì)路由,以便適應(yīng)大型的項(xiàng)目架構(gòu)。
APIRouter
?類的基本用法如下:
# 頁面路由
page_routes = APIRouter()
page_routes.include_router(views.router, prefix="")
# api 相關(guān)路由
api_routes = APIRouter()
api_routes.include_router(api_v1_views.router, prefix='/v1')
api_routes.include_router(api_v2_views.router, prefix='/v2')
可以通過它來拆分管理路由,最后再將所有路由注冊到根路由即可。
app = FastAPI()
app.include_router(page_routes)
app.include_router(api_routes, prefix=config.API_PREFIX)
接下來,讓我們看一個(gè)真實(shí)的生產(chǎn)環(huán)境中的項(xiàng)目案例:
我們從下邊幾點(diǎn)來詳細(xì)說下這個(gè)項(xiàng)目案例:
首先在 ORM 選擇方面,官方推薦了強(qiáng)大的SQLAlchemy
,它可以說是 Python web 開發(fā)中最好用的第三方 ORM 了。在同步框架 Flask 中,應(yīng)該說已經(jīng)成為標(biāo)配。
SQLAlchemy
目前為止對(duì)異步的支持還不夠完成,官方推薦使用 Encode 組織下的異步驅(qū)動(dòng) databases
(目前支持 PostgreSQL/MySQL/SQLite),只所以叫他驅(qū)動(dòng)沒叫他 ORM,是因?yàn)樗鼉H提供了和數(shù)據(jù)庫的異步鏈接的管理,并沒有對(duì)象模型。在使用的時(shí)候,可以結(jié)合SQLAlchemy
或直接寫 SQL。
使用SQLAlchemy
來處理同步的數(shù)據(jù)操作,使用SQLAlchemy
加databases
來實(shí)現(xiàn)異步的數(shù)據(jù)操作,完美實(shí)現(xiàn)了我們的需求。
SQLAlchemy
還有一個(gè)數(shù)據(jù)庫遷移的問題,它自己不支持?jǐn)?shù)據(jù)庫表的變更遷移,只能刪除重建。在 Flask 中可以使用插件flask_migrate
來實(shí)現(xiàn)數(shù)據(jù)庫表的變更遷移。
SQLAlchemy
官方推薦使用alembic
。一個(gè)遷移過程大概步驟如下:
# 1/ 初始化環(huán)境
alembic init migrations
# 2/ 修改配置參數(shù)
# migrations/env.py
import sys
sys.path = ['', '..'] + sys.path[1:]
from core.config import DATABASE_URL
config.set_main_option("sqlalchemy.url", str(DATABASE_URL))
...
from models.posts import PostsBase
from models.posts2 import PostsBase2
target_metadata = Base.metadata # 一個(gè)app model
target_metadata = [PostsBase.metadata, PostBase2.metadata] # 多個(gè)app model
# 3/ 生成遷移腳本
alembic revision --autogenerate -m "init"
# 4/ 應(yīng)用遷移腳本到數(shù)據(jù)庫
alembic upgrade head
從項(xiàng)目目錄可以看到有個(gè) service 目錄,很顯然,當(dāng)業(yè)務(wù)邏輯服務(wù)度升高時(shí),我們可以提取很多共用的邏輯作為底層的共用邏輯。這個(gè)就比較靈活了,完全有你自己控制。各種設(shè)計(jì)模式,就可以往上懟了。
最后我們來看下 docker 化,Dockerfile 如下:
# 我們選擇了官方 slim 鏡像,體積相對(duì)小
FROM python:3.9-slim-buster
LABEL maintainer="DeanWu <pyli.xm@gmail.com>"
# stdout 無緩沖,直接輸出
ENV PYTHONUNBUFFERED 1
# 復(fù)制代碼,調(diào)整工作目錄和腳本權(quán)限
COPY . /app
WORKDIR /app
RUN chmod +x start.sh prestart.sh start-reload.sh
# 安裝用到的工具和python 包
RUN apt-get update && \
apt-get install -y --no-install-recommends default-libmysqlclient-dev gcc libffi-dev make && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
pip install --no-cache-dir -r requirements.txt && \
rm -rf requirements.txt && \
pip install --no-cache-dir gunicorn
ENV PYTHONPATH=/app
EXPOSE 80
# 啟動(dòng)命令 可添加也可不添加
#CMD ["sh", "start.sh"]
編譯和啟動(dòng),
docker build -t fastapi-mysql:v1.0 .
docker run -p 80:80 -d -e DB_CONNECTION="mysql://root:Root1024@xxxx/fastapi" fastapi-mysql:v1.0 ./start.sh
到這里我們從背景到生產(chǎn)項(xiàng)目案例,已經(jīng)介紹完FastApi
?這個(gè)框架了,你有沒有覺著這個(gè)框架很酷呢?我今天只是簡單的介紹了框架的部分應(yīng)用場景,還有很多好玩的功能,大家可以去參考它的官方文檔。也可以關(guān)注我公眾號(hào),一起討論學(xué)習(xí)。
本文章轉(zhuǎn)載微信公眾號(hào)@碼農(nóng)吳先生
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
nodejs + mongodb 編寫 restful 風(fēng)格博客 api
表格插件wpDataTables-將 WordPress 表與 Google Sheets API 連接
手把手教你用Python和Flask創(chuàng)建REST API
使用 Django 和 Django REST 框架構(gòu)建 RESTful API:實(shí)現(xiàn) CRUD 操作
ASP.NET Web API快速入門介紹
2024年在線市場平臺(tái)的11大最佳支付解決方案
完整指南:如何在應(yīng)用程序中集成和使用ChatGPT API
選擇AI API的指南:ChatGPT、Gemini或Claude,哪一個(gè)最適合你?
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)