一文掌握fastapi微服務(wù)開發(fā)-創(chuàng)新互聯(lián)

目錄

成都創(chuàng)新互聯(lián)公司作為成都網(wǎng)站建設(shè)公司,專注網(wǎng)站建設(shè)公司、網(wǎng)站設(shè)計(jì),有關(guān)成都定制網(wǎng)頁設(shè)計(jì)方案、改版、費(fèi)用等問題,行業(yè)涉及水泥攪拌車等多個領(lǐng)域,已為上千家企業(yè)服務(wù),得到了客戶的尊重與認(rèn)可。

一、概述

1.1 微服務(wù)

1.1.1 微服務(wù)的優(yōu)勢

1.1.2 微服務(wù)的缺點(diǎn)

1.2 為何使用Python開發(fā)微服務(wù)

1.3 FastAPI概述

二、開發(fā)

2.1 安裝FastAPI

2.1.1 安裝虛擬環(huán)境

2.1.2?創(chuàng)建虛擬環(huán)境

2.1.3?激活虛擬環(huán)境

2.1.4?安裝FastAPI

2.2 FastAPI簡單使用

2.2.1 查詢

2.2.2?添加

2.2.3?修改

2.2.4?刪除

2.3?代碼組織

2.4?使用PostgreSQL數(shù)據(jù)庫

2.4.1 安裝PostgreSQL數(shù)據(jù)庫

2.4.2?在FastAPI中連接PostgreSQL數(shù)據(jù)庫

2.5?微服務(wù)中的數(shù)據(jù)管理

三、小結(jié)


一、概述 1.1 微服務(wù)

如果你是一名Python Web開發(fā)人員,那么肯定聽說過微服務(wù)這個名詞,并且希望通過Python來構(gòu)建微服務(wù)。那么到底什么是微服務(wù)呢?

微服務(wù)(Microservice)是一種構(gòu)建高可伸縮應(yīng)用程序的架構(gòu),是一種將大型單一應(yīng)用程序分解為專門針對特定服務(wù)、功能的單個應(yīng)用程序的方法。舉例來說,假如我們需要給自己的家進(jìn)行裝修,我們以前的做法就是找一家全包的裝修公司將家里的水電、門窗、家具等全部交給這家裝修公司,這家裝修公司跟我們簽訂合同以后就統(tǒng)籌來安排所有的裝修細(xì)節(jié),我們后續(xù)的對接直接跟這家裝修公司溝通就行了。裝修時,所有的材料費(fèi)都由這家裝修公司統(tǒng)一采購和支出。這種方式在web開發(fā)領(lǐng)域就是典型的單片體系結(jié)構(gòu),每個業(yè)務(wù)邏輯(門窗裝修、水電裝修、家具裝修)都駐留在同一個應(yīng)用程序中(同一家裝修公司負(fù)責(zé)),并且使用相同的數(shù)據(jù)庫(所有裝修的采購和財(cái)務(wù)由公司統(tǒng)一管理)。微服務(wù)架構(gòu)則與這種單片體系結(jié)構(gòu)不同,在微服務(wù)體系結(jié)構(gòu)中,應(yīng)用程序被分解為幾個獨(dú)立的服務(wù),這些服務(wù)在不同的進(jìn)程中運(yùn)行。同樣以裝修為例,如果我們對這家公司的整體裝修水平是認(rèn)同的,但是,對他們打的家具不滿意,我們想用別家專門做家具的來給我們打一套家具,那么我們就可以把打家具這項(xiàng)裝修任務(wù)摘出去,交給另一家專門做家具的公司。很顯然,我們完全可以將各個裝修子任務(wù)都采用這種方式交給專門的裝修公司。水電的交給專門做水電的、家具的交給專門做家具的、門窗的交給專門做門窗的。這種“細(xì)分”的方式能夠讓我們得到更滿意的裝修成果,畢竟術(shù)業(yè)有專攻,這種方式最終的性價(jià)比會更高。但是有個問題,全部任務(wù)分散以后我們必須規(guī)劃好各個任務(wù)的進(jìn)度和接口對接。例如,對于裝修來說,我們一般是先裝修水電再裝修門窗家具,這里就有一個時間調(diào)度的安排。另外,水電的一些接口位置也必須提前規(guī)劃好,因?yàn)楹竺嬖O(shè)計(jì)門窗時也要考慮水電的位置安排。總之,這些各個分散的獨(dú)立服務(wù)之間需要有效“溝通”才能真正發(fā)揮微服務(wù)的作用。微服務(wù)對于應(yīng)用程序的不同功能有一個不同的數(shù)據(jù)庫,根據(jù)每個服務(wù)的性質(zhì),微服務(wù)使用HTTP、AMQP或類似TCP的二進(jìn)制協(xié)議相互通信,也可以使用RabbitMQ、Kafka或Redis等消息隊(duì)列執(zhí)行服務(wù)間通信。

1.1.1 微服務(wù)的優(yōu)勢
  • 松耦合

松散耦合的應(yīng)用程序意味著可以使用最適合它們的技術(shù)來構(gòu)建不同的服務(wù)。因此,開發(fā)團(tuán)隊(duì)可以根據(jù)每個子服務(wù)最適合的技術(shù)來開發(fā)。

  • 易控制

術(shù)業(yè)有專攻,微服務(wù)可以使整個應(yīng)用程序更容易理解和控制。

  • 易擴(kuò)展

使用微服務(wù)可以使應(yīng)用程序擴(kuò)展變得更容易,因?yàn)槿绻渲幸粋€服務(wù)需要高GPU使用率,那么只有包含該服務(wù)的服務(wù)器需要高GPU,而其他服務(wù)器可以在普通服務(wù)器上運(yùn)行。這一點(diǎn)在當(dāng)今的人工智能時代尤其重要,因?yàn)槲覀兘?jīng)常需要部署一些基于AI這種高性能計(jì)算的微服務(wù)。

1.1.2 微服務(wù)的缺點(diǎn)

微服務(wù)并不是萬能的,它也有一些不足。

  • 數(shù)據(jù)庫同步

由于不同的服務(wù)使用不同的數(shù)據(jù)庫,因此涉及多個微服務(wù)的數(shù)據(jù)庫事務(wù)提交需要保證一致性。

  • 微服務(wù)拆分

在第一次嘗試時很難實(shí)現(xiàn)服務(wù)的完美分割,到底哪些功能應(yīng)該單獨(dú)拆出來組成一個微服務(wù)才是最佳的,這些都需要迭代測試。

  • 通信速度

由于微服務(wù)之間使用網(wǎng)絡(luò)交互進(jìn)行通信,這使得應(yīng)用程序容易因?yàn)榫W(wǎng)絡(luò)延遲和服務(wù)速度慢而變慢。

1.2 為何使用Python開發(fā)微服務(wù)

Python是構(gòu)建微服務(wù)的完美工具,因?yàn)樗哂袕?qiáng)大的社區(qū)、易于學(xué)習(xí)的曲線和大量的第三方庫。

Python是一種面向?qū)ο蟮摹⒔忉屝偷?、通用的、開源的腳本編程語言,它之所以非常流行,主要有三點(diǎn)原因:

  • Python 簡單易用,學(xué)習(xí)成本低,看起來非常優(yōu)雅干凈;
  • Python 標(biāo)準(zhǔn)庫和第三庫眾多,功能強(qiáng)大,既可以開發(fā)小工具,也可以開發(fā)企業(yè)級應(yīng)用;
  • Python 站在了人工智能和大數(shù)據(jù)的風(fēng)口上,流行度廣。

舉個簡單的例子來說明一下 Python 的簡單。比如要實(shí)現(xiàn)某個功能,C語言可能需要 100 行代碼,而 Python 可能只需要幾行代碼,因?yàn)镃語言什么都要得從頭開始編寫,而 Python 已經(jīng)內(nèi)置了很多常見功能,我們只需要導(dǎo)入包,然后調(diào)用一個函數(shù)即可。簡單就是 Python 的巨大魅力之一,是它的殺手锏。正因?yàn)閜ython的簡潔,很多著名的web應(yīng)用也開始陸續(xù)的采用python進(jìn)行開發(fā),例如豆瓣和知乎。但是,Python也有缺陷,就是它的速度相比其它語言要慢。雖然Python的速度問題一直被人詬病,但是由于Python引入了異步編程,因此近來出現(xiàn)了性能與GO和Node.js同等的web框架:Fastapi。

1.3 FastAPI概述

FastAPI是近幾年基于Python推出的一款高性能web框架,使用Python 3.6+并基于標(biāo)準(zhǔn)的Python進(jìn)行構(gòu)建。它的優(yōu)勢如下:

  • 快速:可與NodeJS和Go比肩的極高性能(歸功于 Starlette 和 Pydantic),使其超越django和flask成為最快的python web框架之一。

  • 高效編碼:提高功能開發(fā)速度約200%至300%。

  • 更少 bug:減少約40%的人為(開發(fā)者)錯誤。
  • 智能:極佳的編輯器支持。處處皆可自動補(bǔ)全,減少調(diào)試時間。
  • 簡單:設(shè)計(jì)的易于使用和學(xué)習(xí)。
  • 簡短:使代碼重復(fù)最小化。
  • 健壯:生產(chǎn)可用級別的代碼。還有自動生成的交互式文檔。

具體可參考FastAPI官方文檔。

本教程將使用python web框架FastAPI來構(gòu)建一個微服務(wù)應(yīng)用。相關(guān)環(huán)境說明如下所示:

編程語言:Python 3.6.1

操作系統(tǒng):Windows 7

二、開發(fā) 2.1 安裝FastAPI 2.1.1 安裝虛擬環(huán)境

虛擬環(huán)境是Python解釋器的一個副本環(huán)境,在這個環(huán)境中可以安裝其它第三方Python包,在虛擬環(huán)境中安裝的Python包不會影響全局環(huán)境中的包。打個比方,如果我同時接手兩個團(tuán)隊(duì)的活:團(tuán)隊(duì)A和團(tuán)隊(duì)B,A團(tuán)隊(duì)的項(xiàng)目依賴了人工智能的tensorflow庫(非常流行的深度學(xué)習(xí)庫),B團(tuán)隊(duì)的項(xiàng)目也依賴了tensorflow,但是不巧的是A團(tuán)隊(duì)使用的是tensorflow 1版本,而B團(tuán)隊(duì)使用的是tensorflow 2版本,兩個版本的兼容性非常差,那么兩個項(xiàng)目同時在我自己的電腦上操作我該安裝哪個庫呢。假設(shè)兩個庫能同時安裝在電腦上,具體執(zhí)行的時候Python解釋器也不知道到底該調(diào)用哪個tensorflow庫。有沒有什么辦法把兩個庫在同一臺電腦上隔離開,需要用哪個庫就切換到哪個,這樣,我就可以在一臺電腦上同時開發(fā)兩個不同環(huán)境的項(xiàng)目了。這個解決辦法就是虛擬環(huán)境。

簡單理解,虛擬環(huán)境就像一個容器,在某個虛擬環(huán)境中安裝的python包可以獨(dú)立于其它環(huán)境。

Windows平臺下的虛擬環(huán)境需要使用第三方工具virtualenv來創(chuàng)建,打開命令終端,輸入下面的命令即可完成安裝:

pip install virtualenv

安裝完成后檢查是否成功安裝,繼續(xù)輸入命令如下:

virtualenv --version

效果如下圖所示:

此時會輸出virtualenv的版本號,上面的版本號為20.4.2。

2.1.2?創(chuàng)建虛擬環(huán)境

現(xiàn)在我們假定有一個項(xiàng)目工程,該工程位于文件夾micropro中,我們現(xiàn)在的目標(biāo)就是在這個micropro項(xiàng)目中創(chuàng)建python虛擬環(huán)境,這個虛擬環(huán)境是專門為micropro項(xiàng)目成立的。在命令行終端中通過cd命令進(jìn)入項(xiàng)目目錄中(假設(shè)micropro文件夾位于D盤目錄下),如下圖所示:

輸入下面的命令用來創(chuàng)建名為venv的虛擬環(huán)境:

virtualenv venv

成功效果圖如下所示:

這樣我們就在micrppro文件夾下有了一個名為venv的子文件夾,它保存一個全新的虛擬環(huán)境,其中有一個私有的Python解釋器位于micropro/venv/Scripts,在該虛擬環(huán)境中安裝的python包會存放在micropro/venv/Lib路徑下。

2.1.3?激活虛擬環(huán)境

Windows平臺下激活虛擬環(huán)境的命令如下:

venv\Scripts\activate

成功激活之后,虛擬環(huán)境解釋器的路徑就被加入PATH中,但這種改變不是永久的,他只會影響當(dāng)前的命令行終端。為了提醒用戶已經(jīng)激活了虛擬環(huán)境,如下圖所示,會修改命令行的提示符,加入環(huán)境名:

像上述這種前面帶()的命令行就說明已經(jīng)在虛擬環(huán)境中了。

2.1.4?安裝FastAPI

在虛擬環(huán)境中,我們使用下面的命令安裝FastAPI:

pip install fastapi

由于FastAPI沒有內(nèi)置web服務(wù),所以需要安裝uvicorn才能運(yùn)行web應(yīng)用。uvicorn是一個ASGI服務(wù)器,它允許我們使用異步特性。

使用以下命令安裝uvicorn:

pip install uvicorn
2.2 FastAPI簡單使用 2.2.1 查詢

本小節(jié)先簡單介紹和熟悉下FastAPI的基本使用方法。

在新創(chuàng)建的micropro目錄中創(chuàng)建一個新目錄app和一個新文件main.py,然后在main.py中添加以下代碼:

from fastapi import FastAPI

app = FastAPI()


@app.get('/')
async def index():
    return {"Real": "Python"}

上述代碼首先導(dǎo)入并實(shí)例化FastAPI,然后注冊根網(wǎng)址/,然后返回JSON。

我們可以使用uvicorn運(yùn)行應(yīng)用程序服務(wù)器:

uvicorn app.main:app

這里app.main表示使用app目錄中的main.py文件,:app表示程序中定義的FastAPI實(shí)例名稱。

成功啟動后效果如下:

然后我們可以在瀏覽器中訪問 http://127.0.0.1:8000,最終效果如下:

我們也可以訪問http://127.0.0.1:8000/docs 來查看當(dāng)前的所有訪問路由并進(jìn)行測試:

接下來,我們再深入擴(kuò)展一下,在腳本中定義一個電影類Movie,代碼如下所示:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List

app = FastAPI()
fake_movie_db = [{
    'name': 'Star Wars: Episode IX - The Rise of Skywalker',  #電影名
    'genres': ['Action', 'Adventure', 'Fantasy'], #題材
    'casts': ['Daisy Ridley', 'Adam Driver'] # 演員陣容
}]


class Movie(BaseModel):
    name: str
    genres: List[str]
    casts: List[str]


@app.get('/', response_model=List[Movie])
async def index():
    return fake_movie_db

上述代碼中我們創(chuàng)建了一個新的類電影Movie,它從pydantic擴(kuò)展了BaseModel。電影模型包含名稱、題材和演員陣容。Pydantic內(nèi)置了FastAPI,使得定義模型并對模型進(jìn)行請求驗(yàn)證變得容易。我們在定義路由時額外使用了response_model=List[Movie],表明我們想要返回類Movie對應(yīng)的實(shí)例對象列表,這里我們返回fake_movie_db。

我們重新運(yùn)行服務(wù)器,然后訪問?http://127.0.0.1:8000/docs ,可以看到如下效果:

我們可以看到示例響應(yīng)部分中已經(jīng)生成了電影模型的字段。

2.2.2?添加

接下來,我們添加路由,可以將電影添加到電影列表中。添加新的路由定義來處理POST請求:

@app.post('/', status_code=201)
async def add_movie(payload: Movie):
    movie = payload.dict()
    fake_movie_db.append(movie)
    return {'id': len(fake_movie_db) - 1}

重新啟動服務(wù)器然后測試這個新的API。

我們先訪問http://127.0.0.1:8000/docs,然后測試一下剛添加的api,輸入數(shù)據(jù)如下圖所示:

可以看到,系統(tǒng)成功返回了信息。我們成功的添加了一條電影信息。我們重新訪問http://127.0.0.1:8000,查詢效果如下圖所示:

可以看到,我們剛添加的信息已經(jīng)成功返回了。

2.2.3?修改

接下來,我們希望能夠通過請求來修改電影列表中的數(shù)據(jù),添加代碼如下:

from fastapi import HTTPException 

@app.put('/{id}')
async def update_movie(id: int, payload: Movie):
    movie = payload.dict()
    movies_length = len(fake_movie_db)
    if 0<= id< movies_length:
        fake_movie_db[id] = movie
        return None
    raise HTTPException(status_code=404, detail="Movie with given id not found")

上述代碼中的id是我們的電影列表中某部電影的索引。我們重新啟動服務(wù)器,來看下效果。提交數(shù)據(jù)如下所示:

然后我們重新訪問http://127.0.0.1:8000,可以看到效果如下:

我們看到信息已經(jīng)被修改了過來。

2.2.4?刪除

最后我們定義刪除接口,添加代碼如下:

@app.delete('/{id}')
async def delete_movie(id: int):
    movies_length = len(fake_movie_db)
    if 0<= id< movies_length:
        del fake_movie_db[id]
        return None
    raise HTTPException(status_code=404, detail="Movie with given id not found")

然后我們重新啟動服務(wù)器,首先使用前面的Post接口添加3條數(shù)據(jù),效果如下:

然后使用剛添加的刪除接口,首先刪除id=0的電影:

重新訪問http://127.0.0.1:8000,效果如下:

可以看到,第一部電影已經(jīng)刪除掉了。

2.3?代碼組織

通過2.2節(jié)我們熟悉了FastAPI基本的增刪查改操作,前面我們的代碼都是在一個腳本里編寫的,這對于大型項(xiàng)目來說是不合適的,我們需要重新組織代碼結(jié)構(gòu),使其更符合大型項(xiàng)目開發(fā)需求。

緊接著2.2節(jié)的內(nèi)容。在應(yīng)用程序中創(chuàng)建新文件夾api,并在api文件夾中創(chuàng)建新的movies.py。將所有與路由相關(guān)的代碼從main.py移動到movies.py。調(diào)整后的movies.py如下所示:

#~/micropro/app/api/movies.py

from typing import List
from fastapi import Header, APIRouter
from fastapi import HTTPException

from app.api.models import Movie

fake_movie_db = [
    {
        'name': 'Star Wars: Episode IX - The Rise of Skywalker',
        'plot': 'The surviving members of the resistance face the First Order once again.',
        'genres': ['Action', 'Adventure', 'Fantasy'],
        'casts': ['Daisy Ridley', 'Adam Driver']
    }
]

movies = APIRouter()

@movies.get('/', response_model=List[Movie])
async def index():
    return fake_movie_db

@movies.post('/', status_code=201)
async def add_movie(payload: Movie):
    movie = payload.dict()
    fake_movie_db.append(movie)
    return {'id': len(fake_movie_db) - 1}

@movies.put('/{id}')
async def update_movie(id: int, payload: Movie):
    movie = payload.dict()
    movies_length = len(fake_movie_db)
    if 0<= id< movies_length:
        fake_movie_db[id] = movie
        return None
    raise HTTPException(status_code=404, detail="Movie with given id not found")

@movies.delete('/{id}')
async def delete_movie(id: int):
    movies_length = len(fake_movie_db)
    if 0<= id< movies_length:
        del fake_movie_db[id]
        return None
    raise HTTPException(status_code=404, detail="Movie with given id not found")

上述代碼我們使用FastAPI中的APIRouter來注冊新的API路由。另外,在api中創(chuàng)建一個新文件models.py,我們將在這個文件中保存我們定義的Pydantic模型。

接下來在main.py文件中注冊這些新的路由:

#~/micropro/app/main.py
from fastapi import FastAPI
from app.api.movies import movies

app = FastAPI()
app.include_router(movies)

最終我們的應(yīng)用結(jié)構(gòu)如下:

最后,我們重新啟動,查看下是否各項(xiàng)功能都正常。

2.4?使用PostgreSQL數(shù)據(jù)庫

前面的案例中為了簡單我們使用假的Python list來添加電影,在本小節(jié)我們將使用更實(shí)際的數(shù)據(jù)庫來實(shí)現(xiàn)這個功能。本小節(jié)我們將使用PostgreSQL數(shù)據(jù)庫。

2.4.1 安裝PostgreSQL數(shù)據(jù)庫

PostgreSQL是一個功能強(qiáng)大的開源對象關(guān)系型數(shù)據(jù)庫系統(tǒng),他使用和擴(kuò)展了SQL語言,并結(jié)合了許多安全存儲和擴(kuò)展最復(fù)雜數(shù)據(jù)工作負(fù)載的功能。PostgreSQL的起源可以追溯到1986年,作為加州大學(xué)伯克利分校POSTGRES項(xiàng)目的一部分,并且在核心平臺上進(jìn)行了30多年的積極開發(fā)。PostgreSql提供了許多功能,旨在幫助開發(fā)人員構(gòu)建應(yīng)用程序,管理員保護(hù)數(shù)據(jù)完整性并且構(gòu)建容錯環(huán)境,并幫助你管理數(shù)據(jù),無論數(shù)據(jù)集的大小。除了免費(fèi)和開源之外,Postgre SQL還具有高度的可擴(kuò)展性。?

進(jìn)入下載頁面:PostgreSQL: Downloads,由于我們使用windows系統(tǒng),因此選擇Windows對應(yīng)的版本下載。下載完成后按照提示進(jìn)行安裝即可。安裝完成后我們從開始菜單中找到pgAdmin4,這是PostgreSQL對應(yīng)的數(shù)據(jù)庫管理軟件。

輸入密碼登陸pgAdmin4以后,我們創(chuàng)建一個名為movie_db數(shù)據(jù)庫用于我們項(xiàng)目的數(shù)據(jù)管理。如下圖所示:

最終效果如下:

2.4.2?在FastAPI中連接PostgreSQL數(shù)據(jù)庫

為了能夠在python中連接PostgreSQL數(shù)據(jù)庫,我們需要依賴第三方庫,使用下面的命令安裝所需的庫:

pip install 'databases[postgresql]'
pip install psycopg2

上述命令將同時安裝sqlalchemy和asyncpg,這是后面使用PostgreSQL所必需的。

在api中創(chuàng)建一個新文件并將其命名為db.py,這個文件將包含REST API的實(shí)際數(shù)據(jù)庫模型:

from sqlalchemy import (Column, Integer, MetaData, String, Table,
                        create_engine, ARRAY)

from databases import Database

DATABASE_URL = 'postgresql://movie_user:movie_password@localhost/movie_db'

engine = create_engine(DATABASE_URL)
metadata = MetaData()

movies = Table(
    'movies',
    metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('genres', ARRAY(String)),
    Column('casts', ARRAY(String))
)

database = Database(DATABASE_URL)

這里,DATABASE_URL是用于連接到PostgreSQL數(shù)據(jù)庫的URL。這里movie_user是數(shù)據(jù)庫用戶的名稱,movie_password是數(shù)據(jù)庫用戶的密碼,movie_db是數(shù)據(jù)庫的名稱。默認(rèn)的用戶名為postgres,密碼即為安裝PostgreSQL時設(shè)置的密碼。上述代碼中創(chuàng)建了Movie對應(yīng)的table。

更新main.py來連接數(shù)據(jù)庫。main.py代碼如下所示:

#~/micropro/app/main.py
from fastapi import FastAPI
from app.api.movies import movies
from app.api.db import metadata, database, engine

metadata.create_all(engine)

app = FastAPI()

@app.on_event("startup")
async def startup():
    await database.connect()

@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()


app.include_router(movies)

FastAPI提供了一些事件處理程序,可以在應(yīng)用程序啟動時使用這些處理程序連接到我們的數(shù)據(jù)庫,并在應(yīng)用程序關(guān)閉時斷開連接。

接下來我們更新movies.py文件,使其使用數(shù)據(jù)庫而不是Python列表:

#~/micropro/app/api/movies.py

from typing import List
from fastapi import Header, APIRouter,HTTPException

from app.api.models import MovieIn, MovieOut
from app.api import db_manager

movies = APIRouter()

@movies.get('/', response_model=List[MovieOut])
async def index():
    return await db_manager.get_all_movies()

@movies.post('/', status_code=201)
async def add_movie(payload: MovieIn):
    movie_id = await db_manager.add_movie(payload)
    response = {
        'id': movie_id,
        **payload.dict()
    }
    return response


@movies.put('/{id}')
async def update_movie(id: int, payload: MovieIn):
    movie = await db_manager.get_movie(id)
    if not movie:
        raise HTTPException(status_code=404, detail="Movie not found")

    update_data = payload.dict(exclude_unset=True)
    movie_in_db = MovieIn(**movie)

    updated_movie = movie_in_db.copy(update=update_data)

    return await db_manager.update_movie(id, updated_movie)

@movies.delete('/{id}')
async def delete_movie(id: int):
    movie = await db_manager.get_movie(id)
    if not movie:
        raise HTTPException(status_code=404, detail="Movie not found")
    return await db_manager.delete_movie(id)

接下來添加db_manager.py文件用于操作數(shù)據(jù)庫:

from app.api.models import MovieIn, MovieOut, MovieUpdate
from app.api.db import movies, database


async def add_movie(payload: MovieIn):
    query = movies.insert().values(**payload.dict())

    return await database.execute(query=query)

async def get_all_movies():
    query = movies.select()
    return await database.fetch_all(query=query)

async def get_movie(id):
    query = movies.select(movies.c.id==id)
    return await database.fetch_one(query=query)

async def delete_movie(id: int):
    query = movies.delete().where(movies.c.id==id)
    return await database.execute(query=query)

async def update_movie(id: int, payload: MovieIn):
    query = (
        movies
        .update()
        .where(movies.c.id == id)
        .values(**payload.dict())
    )
    return await database.execute(query=query)

最后更新models.py,以便可以將Pydantic模型與sqlalchemy表一起使用:

#~/micropro/api/models.py

from pydantic import BaseModel
from typing import List, Optional

class MovieIn(BaseModel):
    name: str
    genres: List[str]
    casts: List[str]


class MovieOut(MovieIn):
    id: int


class MovieUpdate(MovieIn):
    name: Optional[str] = None
    genres: Optional[List[str]] = None
    casts: Optional[List[str]] = None

這里MovieIn是用于將電影添加到數(shù)據(jù)庫的基礎(chǔ)類。當(dāng)我們從數(shù)據(jù)庫取出數(shù)據(jù)時我們需要使用MovieOut類。MovieUpdate類允許我們將模型中的值設(shè)置為可選的,以便在更新電影數(shù)據(jù)時只更新需要更新的字段。

最后,我們啟動服務(wù)器,然后按照之前的方法添加數(shù)據(jù),最后我們在pdAdmin4中查看有沒有添加成功,效果如下圖所示:

2.5?微服務(wù)中的數(shù)據(jù)管理

微服務(wù)中的數(shù)據(jù)庫管理是一個難點(diǎn)。在構(gòu)建整個應(yīng)用時如何拆分?jǐn)?shù)據(jù)?如何構(gòu)建不同微服務(wù)的數(shù)據(jù)庫?哪些數(shù)據(jù)是各個微服務(wù)共享的?這些在開發(fā)前都需要先仔細(xì)的考慮好。本小節(jié)給出一些基本的方案和優(yōu)缺點(diǎn)介紹:

  • 一個微服務(wù)管理一個獨(dú)立的數(shù)據(jù)庫

如果希望微服務(wù)盡可能松耦合,那么為每個微服務(wù)提供一個獨(dú)立的數(shù)據(jù)庫是比較好的方案。每個微服務(wù)有一個不同的數(shù)據(jù)庫允許我們獨(dú)立地?cái)U(kuò)展不同的服務(wù)。涉及多個數(shù)據(jù)庫的數(shù)據(jù)操作可以通過微服務(wù)之間良好的api實(shí)現(xiàn)。這種方式的缺點(diǎn)就是實(shí)現(xiàn)涉及多個微服務(wù)的業(yè)務(wù)數(shù)據(jù)操作比較麻煩,另外,網(wǎng)絡(luò)開銷的增加使得這種方式使用效率降低。

  • 共享數(shù)據(jù)庫

如果有很多數(shù)據(jù)操作涉及多個微服務(wù),那么最好使用共享數(shù)據(jù)庫。這帶來了高度一致的應(yīng)用程序的好處,但也喪失了微服務(wù)體系結(jié)構(gòu)帶來的大部分好處。在一個微服務(wù)上工作的開發(fā)人員需要與其他服務(wù)中的模式更改相協(xié)調(diào)。

  • API組合

在涉及多個數(shù)據(jù)庫的操作中,API組合充當(dāng)API網(wǎng)關(guān),并按所需順序執(zhí)行對其他微服務(wù)的API調(diào)用。最后,每個微服務(wù)的結(jié)果在內(nèi)存中執(zhí)行連接后返回給客戶機(jī)。這種方法的缺點(diǎn)是在內(nèi)存中進(jìn)行這種大型數(shù)據(jù)的鏈接效率比較低。

總之,到底該選用哪種數(shù)據(jù)拆分方式并沒有一個絕對完美的指導(dǎo)方案,需要根據(jù)項(xiàng)目類型、項(xiàng)目復(fù)雜度等綜合來考量,也需要在試錯和實(shí)踐中來改進(jìn)。用好微服務(wù)架構(gòu)能夠給整個項(xiàng)目帶來超強(qiáng)性能的效果。

三、小結(jié)

本文針對FastAPI微服務(wù)開發(fā)作了簡單介紹,想要快速上手FastAPI的讀者可以通過本文快速掌握FastAPI框架特性,能夠依樣“畫葫蘆”的將相關(guān)功能揉進(jìn)自己的項(xiàng)目中去。除了數(shù)據(jù)庫相關(guān)操作以外,F(xiàn)astAPI最有特色的功能就是集成機(jī)器學(xué)習(xí)和深度學(xué)習(xí)模型,完成線上AI推理,有興趣的讀者可以參考我的另一篇博文。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)站欄目:一文掌握fastapi微服務(wù)開發(fā)-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://muchs.cn/article4/eggoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站微信公眾號、品牌網(wǎng)站制作、App設(shè)計(jì)定制開發(fā)、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司