欢迎加入我们的社区,一起测试和分享您的知识!
done
学习 700 多个动手实验和课程并获得相关技能徽章

使用 Go 和 Cloud Run 開發 REST API

实验 1 小时 universal_currency_alt 5 积分 show_chart 中级
info 此实验可能会提供 AI 工具来支持您学习。
欢迎加入我们的社区,一起测试和分享您的知识!
done
学习 700 多个动手实验和课程并获得相关技能徽章

GSP761

Google Cloud 自修研究室標誌

Pet Theory 標誌

總覽

在「Serverless Cloud Run Development」課程的實驗室中,您要支援一間虛擬的企業,並輔助其中角色進行無伺服器遷移計畫。

小莉在 12 年前設立了連鎖獸醫診所 Pet Theory。隨著連鎖診所業務的成長,小莉花在與保險公司通話的時間,比醫療寵物的時間還要長。是否有辦法讓保險公司在網路上查看療程的總費用呢?

在先前本系列的其他實驗室中,小茹 (軟體顧問) 和阿克 (開發運作工程師) 將 Pet Theory 的顧客資料庫移至雲端的無伺服器 Firestore 資料庫,並且開放存取權,讓顧客可以在線上預約服務。Pet Theory 的營運團隊只有一個人,因此他們需要不必經常持續維護的無伺服器解決方案。

在本實驗室中,您會協助小茹和阿克將客戶資料存取權授予保險公司,但不公開個人識別資訊 (PII)。您將使用 Cloud Run 建構無伺服器且安全的「具象狀態傳輸」(REST) API 閘道。這樣一來,保險公司就能看到治療的總費用,且看不到顧客的 PII 資訊。

目標

本實驗室的學習內容如下:

  • 使用 Go 開發 REST API
  • 將測試用客戶資料匯入 Firestore
  • 將 REST API 連線至 Firestore 資料庫
  • 將 REST API 部署到 Cloud Run

先備知識

本實驗室的難度為中級,亦即假設您已熟悉 Cloud 控制台和 Cloud Shell 環境。本實驗室屬於一系列實驗室之一。參加先前的實驗室會對您有幫助,但並非必要:

  • 將資料匯入無伺服器資料庫
  • 使用 Firebase 和 Firestore 建構無伺服器網頁應用程式
  • 建構可建立 PDF 檔案的無伺服器應用程式

設定和需求

點選「Start Lab」按鈕前的須知事項

請詳閱以下操作說明。研究室活動會計時,而且中途無法暫停。點選「Start Lab」 後就會開始計時,讓您瞭解有多少時間可以使用 Google Cloud 資源。

您將在真正的雲端環境中完成實作研究室活動,而不是在模擬或示範環境。為達此目的,我們會提供新的暫時憑證,讓您用來在研究室活動期間登入及存取 Google Cloud。

如要完成這個研究室活動,請先確認:

  • 您可以使用標準的網際網路瀏覽器 (Chrome 瀏覽器為佳)。
注意:請使用無痕模式或私密瀏覽視窗執行此研究室。這可以防止個人帳戶和學生帳戶之間的衝突,避免個人帳戶產生額外費用。
  • 是時候完成研究室活動了!別忘了,活動一開始將無法暫停。
注意:如果您擁有個人 Google Cloud 帳戶或專案,請勿用於本研究室,以免產生額外費用。

如何開始研究室及登入 Google Cloud 控制台

  1. 按一下「Start Lab」(開始研究室) 按鈕。如果研究室會產生費用,畫面中會出現選擇付款方式的彈出式視窗。左側的「Lab Details」窗格會顯示下列項目:

    • 「Open Google Cloud console」按鈕
    • 剩餘時間
    • 必須在這個研究室中使用的暫時憑證
    • 完成這個實驗室所需的其他資訊 (如有)
  2. 點選「Open Google Cloud console」;如果使用 Chrome 瀏覽器,也能按一下滑鼠右鍵,然後選取「在無痕式視窗中開啟連結」

    接著,實驗室會啟動相關資源並開啟另一個分頁,當中顯示「登入」頁面。

    提示:您可以在不同的視窗中並排開啟分頁。

    注意:如果頁面中顯示「選擇帳戶」對話方塊,請點選「使用其他帳戶」
  3. 如有必要,請將下方的 Username 貼到「登入」對話方塊。

    {{{user_0.username | "Username"}}}

    您也可以在「Lab Details」窗格找到 Username

  4. 點選「下一步」

  5. 複製下方的 Password,並貼到「歡迎使用」對話方塊。

    {{{user_0.password | "Password"}}}

    您也可以在「Lab Details」窗格找到 Password

  6. 點選「下一步」

    重要事項:請務必使用實驗室提供的憑證,而非自己的 Google Cloud 帳戶憑證。 注意:如果使用自己的 Google Cloud 帳戶來進行這個實驗室,可能會產生額外費用。
  7. 按過後續的所有頁面:

    • 接受條款及細則。
    • 由於這是臨時帳戶,請勿新增救援選項或雙重驗證機制。
    • 請勿申請免費試用。

Google Cloud 控制台稍後會在這個分頁開啟。

注意:如要查看列出 Google Cloud 產品和服務的選單,請點選左上角的「導覽選單」「導覽選單」圖示

啟動 Cloud Shell

Cloud Shell 是搭載多項開發工具的虛擬機器,提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作。Cloud Shell 提供指令列存取權,方便您使用 Google Cloud 資源。

  1. 點按 Google Cloud 控制台上方的「啟用 Cloud Shell」圖示 「啟動 Cloud Shell」圖示

連線完成即代表已通過驗證,且專案已設為您的 PROJECT_ID。輸出內容中有一行宣告本工作階段 PROJECT_ID 的文字:

您在本工作階段中的 Cloud Platform 專案會設為「YOUR_PROJECT_ID」

gcloud 是 Google Cloud 的指令列工具,已預先安裝於 Cloud Shell,並支援 Tab 鍵自動完成功能。

  1. (選用) 您可以執行下列指令來列出使用中的帳戶:
gcloud auth list
  1. 點按「授權」

  2. 輸出畫面應如下所示:

輸出內容:

ACTIVE: * ACCOUNT: student-01-xxxxxxxxxxxx@qwiklabs.net To set the active account, run: $ gcloud config set account `ACCOUNT`
  1. (選用) 您可以使用下列指令來列出專案 ID:
gcloud config list project

輸出內容:

[core] project = <project_ID>

輸出內容範例:

[core] project = qwiklabs-gcp-44776a13dea667a6 附註:如需有關 gcloud 的完整說明,請前往 Google Cloud 並參閱「gcloud CLI overview guide」(gcloud CLI 總覽指南)。

小莉

小莉 (Pet Theory 創辦人)

小茹,妳好:

妳記得我上週跟妳說過,我快被保險公司的書面文件和電話淹沒了嗎?有沒有辦法能讓保險公司代表以有效且安全的方式,存取顧客記錄?

目前的工作負荷程度不太能長期保持下去。妳可以幫幫我嗎?

小莉

小茹

小茹 (軟體顧問)

小莉,妳好:

我昨天和阿克吃了一頓午餐,我們擬定了一項計畫,可以輕鬆讓授權的第三方安全地存取 Pet Theory 的數位記錄。

這項方法有四個步驟:

  1. 建構簡易的 REST API。
  2. 匯入客戶測試資料。
  3. 將 REST API 連線至顧客資料庫。
  4. 為 REST API 新增驗證機制。

阿克和我已經具備步驟 1 和 2 所需的技能了,所以我們有不錯的起點。我們計畫在本週末前有一個工作原型。

小茹

請協助小茹,管理為 Pet Theory 建構 REST API 所需的活動。

工作 1:啟用 Google API

本實驗室已為您啟用 2 個 API:

名稱 API
Cloud Build cloudbuild.googleapis.com
Cloud Run run.googleapis.com

工作 2:開發 REST API

  1. 啟用專案:
gcloud config set project $(gcloud projects list --format='value(PROJECT_ID)' --filter='qwiklabs-gcp')
  1. 複製 pet-theory 存放區並存取原始碼:
git clone https://github.com/rosera/pet-theory.git && cd pet-theory/lab08
  1. 使用您常用的文字編輯器,或 Cloud Shell 工具列的「程式碼編輯器」按鈕,查看 go.modgo.sum 檔案。

  2. 建立 main.go 檔案,並在其中新增以下內容:

package main import ( "fmt" "log" "net/http" "os" ) func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/v1/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "{status: 'running'}") }) log.Println("Pets REST API listening on port", port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatalf("Error launching Pets REST API server: %v", err) } } 注意: 以上的程式碼會建立端點,用於測試服務是否正常運作。在服務網址中附加「/v1/」,即可驗證應用程式是否正常運作。Cloud Run 會部署容器,因此您必須提供容器定義。「Dockerfile」檔案會告知 Cloud Run 要使用哪個 Go 版本、要在應用程式中加入哪些檔案,以及如何啟動程式碼。
  1. 接著建立 Dockerfile 檔案,並在其中加入下列內容:
FROM gcr.io/distroless/base-debian12 WORKDIR /usr/src/app COPY server . CMD [ "/usr/src/app/server" ]

server 檔案是從 main.go 建構的執行二進位檔。

  1. 執行下列指令,建構二進位檔:
go build -o server
  1. 執行建構指令後,請確認必要的 Dockerfile 和伺服器位於相同目錄中:
ls -la . ├── Dockerfile ├── go.mod ├── go.sum ├── main.go └── server

大部分以 Go 語言編寫的 Cloud Run 應用程式,不必修改上述的 Dockerfile 範本就能直接使用。

  1. 執行下列指令,部署簡易的 REST API:
gcloud builds submit \ --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1

這個指令會使用您的程式碼建構容器,並將其放入專案的 Container Registry。依序點選「導覽選單」>「Container Registry」,即可看到容器。如果沒有看到 rest-api,請按一下「重新整理」

Container Registry

點選「Check my progress」,確認上述工作已完成。

使用 Cloud Build 建構映像檔
  1. 如果容器已建構,請部署容器:
gcloud run deploy rest-api \ --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1 \ --platform managed \ --region {{{ project_0.default_region | "Filled in at lab startup." }}} \ --allow-unauthenticated \ --max-instances=2
  1. 部署作業完成後,您會看到類似下方的訊息:
Service [rest-api] revision [rest-api-00001] has been deployed and is serving traffic at https://rest-api-[hash].a.run.app

點選「Check my progress」,確認上述工作已完成。

已部署 REST API 服務
  1. 按一下訊息結尾的服務網址,在新瀏覽器分頁中開啟。將 /v1/ 附加至網址結尾,然後按下 Enter 鍵。

您應該會看到下列訊息:

{&quot;status&quot; : &quot;running&quot;}

REST API 正常運作中。透過可用的原型服務,我們將在下一節使用 API 擷取 Firestore 資料庫的「顧客」資訊。

工作 3:匯入測試用客戶資料

小茹

軟體顧問小茹

阿克,你好:

你還有我們不久前建立的虛擬客戶資料嗎?我們要用這些資料來測試。

你記得如何設定 Firestore 資料庫並匯入資料嗎?

小茹

阿克

IT 管理員阿克

小茹,妳好:

我還有測試資料。我今天會將資料移到 Firestore 供妳測試。

阿克

小茹和阿克先前建立了 10 位顧客的測試資料庫,內含某位顧客貓咪的一些療程提案。

請幫阿克設定 Firestore 資料庫,並且匯入顧客測試資料。首先,在專案中啟用 Firestore。

  1. 返回 Cloud 控制台,然後依序點選「導覽選單」>「Firestore」

  2. 按一下「建立資料庫」按鈕。

  3. 按一下「原生模式」按鈕,然後點選「繼續」

  4. 在「位置類型」部分,選取「區域」

  5. 從可用清單中選取區域,然後點選「建立資料庫」

繼續操作前,請先等待資料庫建立完成。

點選「Check my progress」,確認上述工作已完成。

已建立 Firestore 資料庫
  1. 將匯入檔案遷移至系統為您建立的 Cloud Storage bucket:
gsutil mb -c standard -l {{{ project_0.default_region | Region }}} gs://$GOOGLE_CLOUD_PROJECT-customer gsutil cp -r gs://spls/gsp645/2019-10-06T20:10:37_43617 gs://$GOOGLE_CLOUD_PROJECT-customer
  1. 接著將此檔案匯入 Firebase:
gcloud beta firestore import gs://$GOOGLE_CLOUD_PROJECT-customer/2019-10-06T20:10:37_43617/

重新載入 Cloud 控制台瀏覽器,查看 Firestore 結果。

  1. 在 Firestore 中,按一下「預設」下方的「客戶」。您應該會看到已匯入的寵物資料。如果沒有看到任何資料,請嘗試重新整理頁面。

做得好,您已成功建立 Firestore 資料庫,並匯入測試資料!

工作 4:將 REST API 連線至 Firestore 資料庫

小茹

小茹 (軟體顧問)

小莉,妳好:

只是簡單更新一下進度,阿克和我已經完成清單中的前兩項工作了。

現在我要開始建構 REST API,以存取 Firestore 中的客戶資料。

小茹

小莉

小莉 (Pet Theory 創辦人)

小茹,妳好:

好極了!小茹。期待看到妳在下一個階段的進展。

小莉

在本節中,您要幫小茹在 REST API 中建立另一個端點,如下所示:

https://rest-api-[hash].a.run.app/v1/customer/22530

舉例來說,如果 Firestore 資料庫中有 ID 為 22530 的顧客,該網址應會傳回該顧客所有已提案、接受、及拒絕的療程總數。

{ "status": "success", "data": { "proposed": 1602, "approved": 585, "rejected": 489 } } 注意:如果資料庫中沒有該顧客,系統應會改為傳回 狀態碼 404 (找不到) 及錯誤訊息。

這個新功能需要使用一個套件存取 Firestore 資料庫,並使用另一個套件處理跨源資源共享。

  1. 取得 $GOOGLE_CLOUD_PROJECT 環境變數的值
echo $GOOGLE_CLOUD_PROJECT
  1. 在 pet-theory/lab08 目錄中,開啟現有的 main.go 檔案。
注意:請將 main.go 檔案中的值,更新為 $GOOGLE_CLOUD_PROJECT 顯示的值。
  1. 將檔案內容替換成下列程式碼,確保 PROJECT_ID 已設為
package main import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "cloud.google.com/go/firestore" "github.com/gorilla/handlers" "github.com/gorilla/mux" "google.golang.org/api/iterator" ) var client *firestore.Client func main() { var err error ctx := context.Background() client, err = firestore.NewClient(ctx, "{{{ project_0.project_id | \"Filled in at lab startup\"}}}") if err != nil { log.Fatalf("Error initializing Cloud Firestore client: %v", err) } port := os.Getenv("PORT") if port == "" { port = "8080" } r := mux.NewRouter() r.HandleFunc("/v1/", rootHandler) r.HandleFunc("/v1/customer/{id}", customerHandler) log.Println("Pets REST API listening on port", port) cors := handlers.CORS( handlers.AllowedHeaders([]string{"X-Requested-With", "Authorization", "Origin"}), handlers.AllowedOrigins([]string{"https://storage.googleapis.com"}), handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "OPTIONS", "PATCH", "CONNECT"}), ) if err := http.ListenAndServe(":"+port, cors(r)); err != nil { log.Fatalf("Error launching Pets REST API server: %v", err) } }
  1. 在檔案底部新增處理常式支援:
func rootHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "{status: 'running'}") } func customerHandler(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] ctx := context.Background() customer, err := getCustomer(ctx, id) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": '%s'}`, err) return } if customer == nil { w.WriteHeader(http.StatusNotFound) msg := fmt.Sprintf("`Customer \"%s\" not found`", id) fmt.Fprintf(w, fmt.Sprintf(`{"status": "fail", "data": {"title": %s}}`, msg)) return } amount, err := getAmounts(ctx, customer) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err) return } data, err := json.Marshal(amount) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err) return } fmt.Fprintf(w, fmt.Sprintf(`{"status": "success", "data": %s}`, data)) }
  1. 在檔案底部新增顧客服務:
type Customer struct { Email string `firestore:"email"` ID string `firestore:"id"` Name string `firestore:"name"` Phone string `firestore:"phone"` } func getCustomer(ctx context.Context, id string) (*Customer, error) { query := client.Collection("customers").Where("id", "==", id) iter := query.Documents(ctx) var c Customer for { doc, err := iter.Next() if err == iterator.Done { break } if err != nil { return nil, err } err = doc.DataTo(&c) if err != nil { return nil, err } } return &c, nil } func getAmounts(ctx context.Context, c *Customer) (map[string]int64, error) { if c == nil { return map[string]int64{}, fmt.Errorf("Customer should be non-nil: %v", c) } result := map[string]int64{ "proposed": 0, "approved": 0, "rejected": 0, } query := client.Collection(fmt.Sprintf("customers/%s/treatments", c.Email)) if query == nil { return map[string]int64{}, fmt.Errorf("Query is nil: %v", c) } iter := query.Documents(ctx) for { doc, err := iter.Next() if err == iterator.Done { break } if err != nil { return nil, err } treatment := doc.Data() result[treatment["status"].(string)] += treatment["cost"].(int64) } return result, nil }
  1. 「儲存」檔案。

工作 6:趣味測驗

Which function responds to URLs with the pattern `/v1/customer/` getAmounts customerHandler Which statement returns success to the client fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"} fmt.Fprintf(w, fmt.Sprintf(`{"status": "success", "data": %s} Which functions read from the Firestore database customerHandler and getCustomer getCustomer and getAmounts

工作 7:部署新的修訂版本

  1. 重新建構原始碼:
go build -o server
  1. 為 REST API 建構新映像檔:
gcloud builds submit \ --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2

點選「Check my progress」,確認目標已達成。 建構映像檔 0.2 修訂版本

  1. 部署更新後的映像檔:
gcloud run deploy rest-api \ --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2 \ --platform managed \ --region {{{ project_0.default_region | "Filled in at lab startup." }}} \ --allow-unauthenticated \ --max-instances=2 4. 部署作業完成後,您會看到與先前類似的訊息。在您部署新版本後,REST API 的網址不會變更: Service [rest-api] revision [rest-api-00002] has been deployed and is serving traffic at https://rest-api-[hash].a.run.app
  1. 返回已指向該網址的瀏覽器分頁 (結尾為 /v1/)。重新整理分頁,並確認您收到與先前相同的訊息,表示 API 狀態仍為執行中。

{status&quot; : &quot;running&quot;}

  1. /customer/22530 附加至瀏覽器網址列中的應用程式網址。您應該會收到下列 JSON 回應,列出顧客已提案、核准及拒絕的療程總數。

{&quot;status&quot; : &quot;success&quot;, &quot;data&quot; :{&quot;proposed&quot; :1602, &quot;approved&quot; :585, &quot;reected&quot; :489}}

  1. 以下是一些其他的顧客 ID,您可以用這些 ID 取代網址中的 22530:
  • 34216
  • 70156 (所有數量應為零)
  • 12345 (顧客/寵物皆不存在,系統應會傳回錯誤訊息,例如 Query is nil)

您已建構可擴充、不必頻繁維護、且可從資料庫讀取資料的無伺服器 REST API。

恭喜!

恭喜!在本實驗室中,您成功協助小茹和阿克,為 Pet Theory 建構了原型 REST API。您建立了連線至 Firestore 資料庫的 REST API,並將其部署至 Cloud Run。您也測試了 API,確保 API 能正常運作。

Google Cloud 教育訓練與認證

協助您瞭解如何充分運用 Google Cloud 的技術。我們的課程會介紹專業技能和最佳做法,讓您可以快速掌握要領並持續進修。我們提供從基本到進階等級的訓練課程,並有隨選、線上和虛擬課程等選項,方便您抽空參加。認證可協助您驗證及證明自己在 Google Cloud 技術方面的技能和專業知識。

使用手冊上次更新日期:2024 年 5 月 6 日

實驗室上次測試日期:2024 年 5 月 6 日

Copyright 2024 Google LLC 保留所有權利。Google 和 Google 標誌是 Google LLC 的商標,其他公司和產品名稱則有可能是其關聯公司的商標。

此内容目前不可用

一旦可用,我们会通过电子邮件告知您

太好了!

一旦可用,我们会通过电子邮件告知您