, , ,

Firebase SDK with Cloud Run Callable

把自己寫 Client 的 Google Cloud Functions Callable 在呼叫時遇上 NOT FOUND 的問題記錄一下。

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 會自動帶上相關使用者的認證資料。