Firebase SDK with Cloud Run Callable

前陣子開發的 Google Cloud Functions 除了都是建構在第一代的環境上,也都是採用 HTTP 直接觸發的方式進行,而 Google Cloud Functions 在撰寫時可以撰寫另一種 HTTP 供應用程式呼叫使用的函數,它們類似但並不完全相同。

先看 Node.js 定義的差別

import { onRequest } from "firebase-functions/v2/https";

export const hello = onRequest({region: 'asia-east1'},
	async (req, res) => {
    	res.status(200).send('Hello Google Functions');
    }
);
一般的 HTTP 函數
import { HttpsError, OnCall } from "firebase-functions/v2/https";

export const hello = onCall({region: 'asia-east1'},
	async request => {
    	if (!request.auth) {
        	throw new HttpsError('unauthenticated', 'Request had invalid credentials.')
        }
        
        return {
        	message: 'Hello Google Functions'
        }
	}
);
類似的 HTTP 呼叫函數

這種的可以叫他 Callable 函數,從程式碼看它不像一般的 HTTP 函數,只要有網址就可以在任意地方任意裝置呼叫使用,雖然它也有一個 HTTP 的呼叫網址,但它必須攜帶

  • 身份驗證令牌
  • FCM 令牌
  • App Check 令牌 (Options)

否則呼叫都會傳回 401 的授權錯誤。

透過 HttpsError 的第一個參數,會自動回傳相關錯誤給呼叫端,它不像一般的 HTTP 函數可以透過

res.status(401).send('error message');

來傳遞要給客戶端的訊息,而是用 gRPC code

throw new HttpsError('unauthentcated', 'erroe message');
grpc/statuscodes.md at master · grpc/grpc
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) - grpc/statuscodes.md at master · grpc/grpc
gRPC Status Code

透過 Callable 的函數,可以很輕易的讓使用者認證的客戶端才能呼叫的 API。


客戶端問題

這幾天再擴充伺服器的功能性,並且製作符合其新功能的 APP,由於 iPhone 實機的輸出只有五天的憑證,每五天就要重新輸出一次,實屬煩人所以打算將 APP 上架到 App Store,但又要避免隨意一個人下載就能控制我父親的農場?就來製作身份驗證及相關的 API 呼叫。

在 Swift 開發過程中,我怎麼樣呼叫 Callable Xcode 都會出現一條錯誤

Error Domain=com.firebase.functions Code=5 "NOT FOUND" UserInfo={NSLocalizedDescription=NOT FOUND}
function not found

最後發現因為我在寫 http 或 callable 函數時,都會指定部署在台灣的機房

region: 'asia-east1'

就是因為我使用非預設的地區,所以在 callable 呼叫時也需要帶上地區

import FirebaseFunctions

Button {
	lazy var functions = Functions.functions(region: "asia-east1")
    
    // 建立函數引用
    let helloFunction = functions.httpsCallable("hello")
    
    // 傳遞參數
    helloFunction.call(["message": "Test msg"]) { result, error in
    	if let error = error as NSError? {
        	print(error)
            return
        }
        
        if let data = result?.data as? [String: Any] {
        	print(data)
        }
    }
} label: {
	Text("測試 Hello Function")
}
Firebase callable

由於我使用 Firebase 來做身份驗證,採用 Firebase SDK 的呼叫 callable 會自動帶上相關使用者的認證資料。