鍵.png)
使用NestJS和Prisma構(gòu)建REST API:身份驗證
該系列的目標(biāo)是通過解決一個具體問題:在線課程的評分系統(tǒng),探索和演示現(xiàn)代后端的不同模式、問題和架構(gòu)。選擇這個問題是因為它涉及多種關(guān)系類型,而且復(fù)雜度足夠,能夠很好地反映現(xiàn)實世界的應(yīng)用場景。
上面提供了實時流的錄制內(nèi)容,其內(nèi)容與本文相同。
該系列將重點關(guān)注數(shù)據(jù)庫在后端開發(fā)各個方面的作用,包括:
話題 | 部分 |
---|---|
數(shù)據(jù)建模 | 第 1 部分 |
增刪改查 | 第 1 部分 |
聚合 | 第 1 部分 |
REST API 層 | 第2部分 |
驗證 | 第2部分 |
測試 | 第2部分 |
無密碼認(rèn)證 | 第三部分 |
授權(quán) | 第三部分 |
與外部 API 集成 | 第三部分 |
持續(xù)集成 | 第 4 部分(當(dāng)前) |
部署 | 第 4 部分(當(dāng)前) |
在第一篇文章中,您為問題域設(shè)計了一個數(shù)據(jù)模型,并編寫了一個使用Prisma Client將數(shù)據(jù)保存到數(shù)據(jù)庫的種子腳本。
在本系列的第二篇文章中,您基于第一篇文章所介紹的數(shù)據(jù)模型和Prisma架構(gòu),成功構(gòu)建了一個REST API。您使用Hapi構(gòu)建了 REST API,它允許通過 HTTP 請求對資源執(zhí)行 CRUD 操作。
在本系列的第三篇文章中,您實現(xiàn)了基于電子郵件的無密碼身份驗證和授權(quán),并使用JSON Web 令牌 (JWT)和 Hapi 來保護(hù) REST API。此外,您還實現(xiàn)了基于資源的授權(quán)機(jī)制,以明確用戶被允許執(zhí)行的具體操作。
在本文中,您將通過定義運行測試并將后端部署到 Heroku(您將在其中托管后端和 PostgreSQL 數(shù)據(jù)庫)的工作流程,將 GitHub Actions 設(shè)置為 CI/CD 服務(wù)器。
Heroku 是一個平臺即服務(wù)(PaaS)提供商。與無服務(wù)器部署模型有所不同,在 Heroku 上,即使當(dāng)前沒有向您的應(yīng)用程序發(fā)出請求,應(yīng)用程序也會保持運行狀態(tài)。雖然無服務(wù)器具有許多優(yōu)勢,例如更低的成本和更少的運營開銷,但這種方法避免了無服務(wù)器方法常見的數(shù)據(jù)庫連接擾動和冷啟動的挑戰(zhàn)。
注意:在整個指南中,您將找到各種檢查點,使您能夠驗證是否正確執(zhí)行了這些步驟。
要將帶有 GitHub Action 的后端部署到 Heroku,您將需要以下內(nèi)容:
持續(xù)集成(CI)是一種技術(shù)手段,旨在將單個開發(fā)人員的工作成果整合到主代碼庫中,以便及時發(fā)現(xiàn)集成過程中可能出現(xiàn)的錯誤,并促進(jìn)開發(fā)團(tuán)隊之間的協(xié)作與效率提升。通常,CI 服務(wù)器連接到 Git 存儲庫,每次將提交推送到存儲庫時,CI 服務(wù)器都會運行。
持續(xù)部署 (CD) 是一種涉及自動化部署過程的方法,以便可以快速、一致地部署更改。
盡管CI和CD各自承擔(dān)著不同的職責(zé),但它們之間是相互關(guān)聯(lián)的,并且通常我們會利用相同的工具來執(zhí)行這兩個過程。在本文中,您將使用 GitHub Actions 來處理 CI 和 CD。
通過持續(xù)集成,主要構(gòu)建塊是管道。管道是您定義的一組步驟,用于確保您的更改不會引入錯誤或回歸。例如,管道可能包含運行測試、代碼檢查和 TypeScript 編譯器的步驟。如果其中一個步驟失敗,CI 服務(wù)器將停止并向 GitHub 報告失敗的步驟。
在團(tuán)隊協(xié)作中,若采用拉取請求來引入代碼更改,那么CI(持續(xù)集成)服務(wù)器通常會被設(shè)定為對每個拉取請求自動執(zhí)行相應(yīng)的管道流程。
您在前面的步驟中編寫的測試通過模擬對 API 端點的請求來工作。由于這些端點的處理程序與數(shù)據(jù)庫交互,因此在測試期間您將需要一個具有后端架構(gòu)的 PostgreSQL 數(shù)據(jù)庫。在接下來的步驟中,您需要配置GitHub Actions,以便在運行CI時能夠啟動測試數(shù)據(jù)庫并執(zhí)行遷移操作,從而確保測試數(shù)據(jù)庫的結(jié)構(gòu)與您的Prisma架構(gòu)保持一致。
注意: CI 的好壞取決于您編寫的測試。如果您的測試覆蓋率較低,通過測試可能會產(chǎn)生錯誤的自信感。
GitHub Actions 是一個可用于持續(xù)集成的自動化平臺。它提供了一個 API,用于根據(jù) GitHub 中的事件編排工作流程,并可用于從 GitHub 構(gòu)建、測試和部署代碼。
要配置 GitHub Actions,您可以使用 yaml 定義工作流程。工作流可以配置為在不同的存儲庫事件上運行,例如,當(dāng)提交被推送到存儲庫時或當(dāng)創(chuàng)建拉取請求時。
每個工作流可以包含多個作業(yè),而每個作業(yè)又由多個步驟所組成。在這些作業(yè)中,每一個步驟都代表著一個命令,并且這些命令能夠訪問到正在進(jìn)行測試的特定提交所對應(yīng)的源代碼。
注意: CI 服務(wù)對管道使用不同的術(shù)語;例如,GitHub Actions 使用術(shù)語“工作流程”來指代同一事物。
在本文中,您將使用存儲庫中的grading-app
工作流。
讓我們看一下工作流程:
name: grading-app
on: push
jobs:
test:
runs-on: ubuntu-latest
# Service containers to run with container-job
services:
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres
# Provide the password for postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps TCP port 5432 on service container to the host
- 5432:5432
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/grading-app
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- run: npm ci
# run the migration in the test database
- run: npm run db:push
- run: npm run test
deploy:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master' # Only deploy master
needs: test
steps:
- uses: actions/checkout@v2
- run: npm ci
- name: Run production migration
run: npm run migrate:deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- uses: akhileshns/heroku-deploy@v3.4.6
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: ${{ secrets.HEROKU_APP_NAME }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
該grading-app
工作流有兩個作業(yè):test
和deploy
。
測試作業(yè)將執(zhí)行以下操作:
services
。注意:
services
可用于運行附加服務(wù)。在上面的測試作業(yè)中,它用于創(chuàng)建測試 PostgreSQL 數(shù)據(jù)庫。
部署作業(yè)將執(zhí)行以下操作:
注意:?
on: push
?會為每次代碼推送到倉庫時觸發(fā)相應(yīng)的工作流程。而?if: github.event_name == 'push' && github.ref == 'refs/heads/master'
?這個條件則確保了名為?deploy
?的作業(yè)僅在代碼被推送到?master
?分支時才會被觸發(fā)執(zhí)行。
首先分叉GitHub 存儲庫,以便您可以配置 GitHub 操作。
注意:如果您已經(jīng)對倉庫進(jìn)行了分叉,那么請將原始倉庫中
master
分支的更改合并到您的分叉?zhèn)}庫中。
分叉后,轉(zhuǎn)到Github 上的操作選項卡:
單擊啟用按鈕啟用工作流程:
現(xiàn)在,當(dāng)您將提交推送到存儲庫時,GitHub 將運行工作流程。
確保您已使用 CLI 登錄到 Heroku:
heroku login
要將后端應(yīng)用程序部署到 Heroku,您需要創(chuàng)建一個 Heroku 應(yīng)用程序。從克隆存儲庫的文件夾中運行以下命令:
cd real-world-grading-app
heroku apps:create YOUR_APP_NAME
注意:使用您選擇的唯一名稱而不是
YOUR_APP_NAME
。
檢查點Heroku CLI 應(yīng)記錄應(yīng)用程序已成功創(chuàng)建:
Creating ? YOUR_APP_NAME... done
使用以下命令創(chuàng)建數(shù)據(jù)庫:
heroku addons:create heroku-postgresql:hobby-dev
檢查點:要驗證數(shù)據(jù)庫是否已創(chuàng)建,您應(yīng)該看到以下內(nèi)容:
Creating heroku-postgresql:hobby-dev on ? YOUR_APP_NAME... free
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-closed-86440 as DATABASE_URL
注意:?Heroku 會自動設(shè)置
DATABASE_URL
應(yīng)用程序運行時的環(huán)境變量。Prisma 客戶端會使用與在 Prisma 架構(gòu)的?DATABASE_URL
?中所配置的環(huán)境變量相匹配的那個環(huán)境變量。
為了在 GitHub Actions 中執(zhí)行生產(chǎn)數(shù)據(jù)庫的遷移操作以及將后端部署到 Heroku,您需要在 GitHub 中創(chuàng)建四個機(jī)密,這些機(jī)密將在工作流程中被引用。
注意:構(gòu)建時機(jī)密和運行時機(jī)密之間存在區(qū)別。構(gòu)建時機(jī)密將在 GitHub 中定義并在 GitHub Actions 運行期間使用。另一方面,運行時秘密將在 Heroku 中定義并由后端使用。
HEROKU_APP_NAME
:您在上一步中選擇的應(yīng)用程序的名稱。HEROKU_EMAIL
:您注冊 Heroku 時使用的電子郵件。HEROKU_API_KEY
:Heroku API 密鑰DATABASE_URL
:Heroku 上的生產(chǎn) PostgreSQL URL,需要在部署之前運行生產(chǎn)數(shù)據(jù)庫遷移。要獲取DATABASE_URL
Heroku 在配置數(shù)據(jù)庫時設(shè)置的 , 請使用以下 Heroku CLI 命令:
heroku config:get DATABASE_URL
檢查點:您應(yīng)該在輸出中看到 URL,例如,postgres://username:password@ec2-12.eu-west-1.compute.amazonaws.com:5432/dbname
您可以從自己的Heroku帳戶設(shè)置頁面中獲取Heroku API密鑰:
要創(chuàng)建四個機(jī)密,請轉(zhuǎn)到存儲庫設(shè)置并打開“機(jī)密”選項卡:
單擊“新建密鑰”,使用名稱字段作為密鑰名稱,例如,HEROKU_APP_NAME
并設(shè)置值:
檢查點:創(chuàng)建四個秘密后,您應(yīng)該看到以下內(nèi)容:
后端需要三個密鑰,這些密鑰將在運行時作為環(huán)境變量傳遞給應(yīng)用程序:
SENDGRID_API_KEY
:SendGrid API 密鑰。JWT_SECRET
:用于簽署 JWT 令牌的秘密。DATABASE_URL
:Heroku 自動設(shè)置的數(shù)據(jù)庫連接 URL。注意:您可以
JWT_SECRET
通過在終端中運行以下命令來生成:
node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"
要使用 Heroku CLI 設(shè)置它們,請使用以下命令:
heroku config:set SENDGRID_API_KEY="REPLACE_WITH_API_KEY" JWT_SECRET="REPLACE_WITH_SECRET"
檢查點:為了確認(rèn)環(huán)境變量是否已經(jīng)正確設(shè)置,您應(yīng)該能夠看到如下內(nèi)容:
Setting SENDGRID_API_KEY, JWT_SECRET and restarting ? YOUR_APP_NAME... done, v7
配置工作流程、在 Heroku 上創(chuàng)建應(yīng)用程序以及設(shè)置所有機(jī)密后,您現(xiàn)在可以觸發(fā)工作流程來運行測試和部署。
為了觸發(fā)構(gòu)建流程,您可以創(chuàng)建一個空提交并將其推送。
git commit --allow-empty -m "Trigger build"
git push
推送提交后,轉(zhuǎn)到 GitHub 存儲庫的“操作”選項卡,您應(yīng)該會看到以下內(nèi)容:
單擊表中包含提交消息的第一行:
要查看作業(yè)的日志test
,請單擊test
相應(yīng)的按鈕,您可以查看每個步驟的日志。例如,在下面的屏幕截圖中,您可以查看測試結(jié)果:
要驗證該deploy
作業(yè)已成功部署到 Heroku,請單擊deploy
左側(cè)的Deploy to Heroku
并展開該步驟。您應(yīng)該在日志末尾看到以下行:
remote: https://***.herokuapp.com/ deployed to Heroku
若要從瀏覽器中訪問API,請在已克隆的存儲庫文件夾內(nèi)執(zhí)行以下Heroku CLI命令:
heroku open
這將打開指向https://YOUR_APP_NAME.herokuapp.com/
的瀏覽器。
檢查點:您應(yīng)該在瀏覽器中看到由狀態(tài)端點{"up":true}
提供的服務(wù)。
要查看后端日志,請從克隆的存儲庫文件夾中使用以下 Heroku CLI 命令:
heroku logs --tail -a YOUR_APP_NAME
要測試登錄流程,您需要對 REST API 進(jìn)行兩次調(diào)用。
首先獲取 API 的 URL:
heroku apps:info
使用curl 對登錄端點進(jìn)行POST 調(diào)用:
curl --header "Content-Type: application/json" --request POST --data '{"email":"your-email@prisma.io"}' https://YOUR_APP_NAME.herokuapp.com/login
檢查您電子郵件中收到的8位數(shù)令牌,并據(jù)此執(zhí)行下一步操作。
curl -v --header "Content-Type: application/json" --request POST --data '{"email":"your-email@prisma.io", "emailToken": "99223388"}' https://YOUR_APP_NAME.herokuapp.com/authenticate
檢查點:響應(yīng)應(yīng)具有 200 成功狀態(tài)代碼并包含Authorization
帶有 JWT 令牌的標(biāo)頭:
< Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkIjo4fQ.ea2lBPMJ6mrPkwEHCgeIFqqQfkQ2uMQ4hL-GCuwtBAE
您的后端已經(jīng)成功部署并正在運行中。做得非常好!
您通過定義 GitHub Actions 工作流程配置持續(xù)集成和部署,創(chuàng)建 Heroku 應(yīng)用程序,配置 PostgreSQL 數(shù)據(jù)庫,并使用 GitHub Actions 將后端部署到 Heroku。
當(dāng)您向倉庫提交代碼并推送更改以引入新功能時,測試和TypeScript編譯器將會自動執(zhí)行。如果一切順利,后端將會被部署。
您可以通過進(jìn)入 Heroku 儀表板來查看內(nèi)存使用情況、響應(yīng)時間和吞吐量等指標(biāo)。這對于深入了解后端如何處理不同的流量非常有用。例如,后端負(fù)載增加可能會導(dǎo)致響應(yīng)時間變慢。
通過將TypeScript與Prisma Client結(jié)合使用,您可以在編譯階段就消除一類通常在運行時才會發(fā)現(xiàn)且需要調(diào)試的類型錯誤。
您可以在GitHub上找到后端的完整源代碼。
盡管Prisma的設(shè)計初衷是為了簡化關(guān)系數(shù)據(jù)庫的使用,但深入了解底層數(shù)據(jù)庫以及Heroku的具體細(xì)節(jié)仍然是非常有益的。
原文鏈接:https://www.prisma.io/blog/backend-prisma-typescript-orm-with-postgresql-deployment-bbba1ps7kip5