Firebase용 Cloud Functions 클라이언트 SDK를 사용하면 Firebase 앱에서 직접 함수를 호출할 수 있습니다. 이 방식으로 앱에서 함수를 호출하려면 Cloud Functions에서 HTTPS 호출 가능 함수를 작성 및 배포한 후 앱에서 함수를 호출하는 클라이언트 로직을 추가합니다.
HTTPS 호출 가능 함수는 HTTP 함수와 비슷하지만 동일하지 않다는 점에 주의해야 합니다. 또한 1세대 및 2세대 함수 간에 콜백 서명이 변경되었습니다.
// Adds two numbers to each other.
exports.addnumbers = onCall((request) => {
// Numbers passed from the client.
const firstNumber = request.data.firstNumber;
const secondNumber = request.data.secondNumber;
// Checking that attributes are present and are numbers.
if (!Number.isFinite(firstNumber) || !Number.isFinite(secondNumber)) {
// Throwing an HttpsError so that the client gets the error details.
throw new HttpsError("invalid-argument", "The function must be called " +
"with two arguments \"firstNumber\" and \"secondNumber\" which " +
"must both be numbers.");
}
// returning result.
return {
firstNumber: firstNumber,
secondNumber: secondNumber,
operator: "+",
operationResult: firstNumber + secondNumber,
};
});
호출 가능 함수와 HTTP 함수의 주요 차이점은 다음과 같습니다.
- 호출 가능 함수를 사용하면 Firebase 인증 토큰, FCM 토큰, 앱 체크 토큰이 있는 경우 자동으로 요청에 포함됩니다.
functions.https.onCall
트리거가 자동으로 요청 본문을 역직렬화하고 인증 토큰의 유효성을 검사합니다.
Cloud Functions(2세대) 이상용 Firebase SDK는 HTTPS 호출 가능 함수를 지원하기 위해 다음과 같은 Firebase 클라이언트 SDK 최소 버전과 연동됩니다.
- Apple 플랫폼용 Firebase SDK 10.9.0
- Android용 Firebase SDK 20.3.0
- Firebase Modular Web SDK v. 9.7.0
지원되지 않는 플랫폼에서 빌드한 앱에 비슷한 기능을 추가하려면 https.onCall
의 프로토콜 사양을 참조하세요. 이 가이드의 나머지 부분에서는 Apple 플랫폼, Android, 웹, C++, Unity용 HTTPS 호출 가능 함수를 작성, 배포, 호출하는 방법을 안내합니다.
호출 가능 함수 작성 및 배포
functions/v2/https
하위 패키지의 onCall
메서드를 사용하여 HTTP 호출 가능 함수를 만듭니다. 이 메서드는 data
, auth
, app
, instanceToken
속성이 있는 event
매개변수를 사용합니다.
// Saves a message to the Firebase Realtime Database but sanitizes the
// text by removing swearwords.
exports.addmessage = onCall((request) => {
// ...
});
실시간 데이터베이스에 SMS를 저장하는 호출 가능 함수의 경우 예를 들어 data
에 auth
의 인증 정보와 함께 메시지 텍스트가 포함될 수 있습니다.
// Message text passed from the client.
const text = request.data.text;
// Authentication / user information is automatically added to the request.
const uid = request.auth.uid;
const name = request.auth.token.name || null;
const picture = request.auth.token.picture || null;
const email = request.auth.token.email || null;
호출 가능 함수의 위치와 호출 중인 클라이언트의 위치 간의 거리로 인해 네트워크 지연 시간이 발생할 수 있습니다. 성능을 최적화하려면 함수 위치를 지정하고(해당하는 경우) 호출 가능 함수의 위치를 클라이언트 측에서 SDK를 초기화할 때 설정한 위치와 맞추세요.
필요한 경우 앱 체크 증명을 연결하여 백엔드 리소스 악용(예: 결제 사기 또는 피싱)을 방지할 수 있습니다. Cloud Functions에 대한 앱 체크 적용 사용 설정을 참조하세요.
결과 반환
데이터를 클라이언트에 다시 전송하려면 JSON으로 인코딩될 수 있는 데이터를 반환합니다. 예를 들어 추가 작업의 결과를 반환하는 방법은 다음과 같습니다.
// returning result.
return {
firstNumber: firstNumber,
secondNumber: secondNumber,
operator: "+",
operationResult: firstNumber + secondNumber,
};
비동기 작업 후에 데이터를 반환하려면 프로미스를 반환합니다. 프로미스로 반환한 데이터가 클라이언트로 다시 전송됩니다. 예를 들어 호출 가능 함수가 실시간 데이터베이스에 쓰기 처리한 정리된 텍스트를 반환할 수 있습니다.
// Saving the new message to the Realtime Database.
const sanitizedMessage = sanitizer.sanitizeText(text); // Sanitize message.
return getDatabase().ref("/messages").push({
text: sanitizedMessage,
author: {uid, name, picture, email},
}).then(() => {
logger.info("New Message written");
// Returning the sanitized message to the client.
return {text: sanitizedMessage};
})
오류 처리
클라이언트에서 유용한 오류 세부정보를 가져오려면 functions.https.HttpsError
인스턴스를 발생시키거나 거부된 프로미스를 반환하여 호출 가능 함수에서 오류를 반환합니다.
오류에는 code
속성이 있으며 이 속성은 functions.https.HttpsError
에 나열된 값 중 하나일 수 있습니다.
또한 오류에 message
문자열도 있으며 기본값은 비어 있는 문자열입니다. 임의의 값이 있는 details
필드(선택사항)도 있을 수 있습니다. 함수에서 HttpsError
외의 오류가 발생하면 클라이언트에서 INTERNAL
메시지와 internal
코드가 포함된 오류를 수신합니다.
예를 들어 함수에서 오류 메시지와 함께 데이터 유효성 검사 및 인증 오류를 발생시켜 호출 중인 클라이언트에 반환할 수 있습니다.
// Checking attribute.
if (!(typeof text === "string") || text.length === 0) {
// Throwing an HttpsError so that the client gets the error details.
throw new HttpsError("invalid-argument", "The function must be called " +
"with one arguments \"text\" containing the message text to add.");
}
// Checking that the user is authenticated.
if (!request.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new HttpsError("failed-precondition", "The function must be " +
"called while authenticated.");
}
호출 가능 함수 배포
완성된 호출 가능 함수를 index.js
에 저장한 후 firebase deploy
를 실행하면 다른 모든 함수와 함께 배포할 수 있습니다.
호출 가능 함수만 배포하려면 다음과 같이 --only
인수를 사용하여 부분 배포를 수행합니다.
firebase deploy --only functions:addMessage
함수를 배포할 때 권한 오류가 발생하면 배포 명령어를 실행하는 사용자에게 적절한 IAM 역할이 할당되었는지 확인합니다.
클라이언트 개발 환경 설정
기본 요건을 충족하는지 확인하고 필요한 종속 항목 및 클라이언트 라이브러리를 앱에 추가합니다.
iOS+
안내에 따라 Firebase를 Apple 앱에 추가합니다.
Swift Package Manager를 사용해 Firebase 종속 항목을 설치하고 관리하세요.
- 앱 프로젝트를 연 상태로 Xcode에서 File(파일) > Add Packages(패키지 추가)로 이동합니다.
- 메시지가 표시되면 Firebase Apple 플랫폼 SDK 저장소를 추가합니다.
- Cloud Functions 라이브러리를 선택합니다.
- 완료되면 Xcode가 백그라운드에서 자동으로 종속 항목을 확인하고 다운로드하기 시작합니다.
https://github.com/firebase/firebase-ios-sdk
Web version 9
- 안내에 따라 Firebase를 웹 앱에 추가합니다. 터미널에서 다음 명령어를 실행해야 합니다.
npm install firebase@9.21.0 --save
Firebase core 및 Cloud Functions를 수동으로 요청합니다.
import { initializeApp } from 'firebase/app'; import { getFunctions } from 'firebase/functions'; const app = initializeApp({ projectId: '### CLOUD FUNCTIONS PROJECT ID ###', apiKey: '### FIREBASE API KEY ###', authDomain: '### FIREBASE AUTH DOMAIN ###', }); const functions = getFunctions(app);
Kotlin+KTX
안내에 따라 Firebase를 Android 앱에 추가합니다.
모듈(앱 수준) Gradle 파일(일반적으로
<project>/<app-module>/build.gradle
)에서 Cloud Functions Android 라이브러리의 종속 항목을 추가합니다. 라이브러리 버전 관리 제어에는 Firebase Android BoM을 사용하는 것이 좋습니다.dependencies { // Import the BoM for the Firebase platform implementation platform('com.google.firebase:firebase-bom:32.0.0') // Add the dependency for the Cloud Functions library // When using the BoM, you don't specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-functions-ktx' }
Firebase Android BoM을 사용하면 앱에서 항상 호환되는 Firebase Android 라이브러리 버전만 사용합니다.
(대안) BoM을 사용하지 않고 Firebase 라이브러리 종속 항목을 추가합니다.
Firebase BoM을 사용하지 않도록 선택한 경우에는 종속 항목 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.
앱에서 여러 Firebase 라이브러리를 사용하는 경우 모든 버전이 호환되도록 BoM을 사용하여 라이브러리 버전을 관리하는 것이 좋습니다.
dependencies { // Add the dependency for the Cloud Functions library // When NOT using the BoM, you must specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-functions-ktx:20.3.0' }
Java
안내에 따라 Firebase를 Android 앱에 추가합니다.
모듈(앱 수준) Gradle 파일(일반적으로
<project>/<app-module>/build.gradle
)에서 Cloud Functions Android 라이브러리의 종속 항목을 추가합니다. 라이브러리 버전 관리 제어에는 Firebase Android BoM을 사용하는 것이 좋습니다.dependencies { // Import the BoM for the Firebase platform implementation platform('com.google.firebase:firebase-bom:32.0.0') // Add the dependency for the Cloud Functions library // When using the BoM, you don't specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-functions' }
Firebase Android BoM을 사용하면 앱에서 항상 호환되는 Firebase Android 라이브러리 버전만 사용합니다.
(대안) BoM을 사용하지 않고 Firebase 라이브러리 종속 항목을 추가합니다.
Firebase BoM을 사용하지 않도록 선택한 경우에는 종속 항목 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.
앱에서 여러 Firebase 라이브러리를 사용하는 경우 모든 버전이 호환되도록 BoM을 사용하여 라이브러리 버전을 관리하는 것이 좋습니다.
dependencies { // Add the dependency for the Cloud Functions library // When NOT using the BoM, you must specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-functions:20.3.0' }
클라이언트 SDK 초기화
Cloud Functions의 인스턴스를 초기화합니다.
Swift
lazy var functions = Functions.functions()
Objective-C
@property(strong, nonatomic) FIRFunctions *functions;
// ...
self.functions = [FIRFunctions functions];
Web version 9
const app = initializeApp({
projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
});
const functions = getFunctions(app);
Kotlin+KTX
private lateinit var functions: FirebaseFunctions // ... functions = Firebase.functions
Java
private FirebaseFunctions mFunctions; // ... mFunctions = FirebaseFunctions.getInstance();
함수 호출
Swift
let addMessageURL = URL(string: "https://addmessage-xyz1234-uc.a.run.app/addMessage")!
functions.httpsCallable(addMessageURL).call(["text": inputField.text]) { result, error in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
// ...
}
if let data = result?.data as? [String: Any], let text = data["text"] as? String {
self.resultField.text = text
}
}
Web version 9
import { getFunctions, httpsCallableFromURL } from 'firebase/functions';
const functions = getFunctions();
const addMessage = httpsCallableFromURL(
functions,
// the URL of the function
"https://addmessage-xyz1234-uc.a.run.app/addMessage"
);
addMessage({ text: messageText })
.then((result) => {
// Read result of the Cloud Function.
const data = result.data;
const sanitizedMessage = data.text;
});
Kotlin+KTX
private fun addMessage(text: String): Task<String> {
// Create the arguments to the callable function.
val data = hashMapOf(
"text" to text,
"push" to true
)
return functions
// The URL of the function
.getHttpsCallableFromUrl(URL("https://addmessage-xyz1234-uc.a.run.app/addMessage"))
.call(data)
.continueWith { task ->
// This continuation runs on either success or failure, but if the task
// has failed then result will throw an Exception which will be
// propagated down.
val result = task.result?.data as String
result
}
}
클라이언트의 오류 처리
서버에서 오류가 발생하거나 결과 프로미스가 거부되면 클라이언트가 오류를 수신합니다.
함수가 반환한 오류의 유형이 function.https.HttpsError
이면 클라이언트가 서버 오류로부터 오류 code
, message
, details
를 수신합니다. 그 외의 경우는 오류에 INTERNAL
메시지와 INTERNAL
코드가 포함됩니다. 호출 가능 함수의 오류 처리 방법에 대한 안내를 참조하세요.
Swift
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
// ...
}
Web version 9
import { getFunctions, httpsCallableFromURL } from "firebase/functions";
const functions = getFunctions();
const addMessage = httpsCallableFromURL(
functions,
// the URL of the function
"https://addmessage-xyz1234-uc.a.run.app/addMessage"
);
addMessage({ text: messageText })
.then((result) => {
// Read result of the Cloud Function.
const data = result.data;
const sanitizedMessage = data.text;
})
.catch((error) => {
// Getting the Error details.
const code = error.code;
const message = error.message;
const details = error.details;
// ...
});
Kotlin+KTX
addMessage(inputMessage) .addOnCompleteListener { task -> if (!task.isSuccessful) { val e = task.exception if (e is FirebaseFunctionsException) { val code = e.code val details = e.details } } }
권장: 앱 체크로 악용 방지
앱을 출시하기 전에 내 앱만 호출 가능 함수 엔드포인트에 액세스할 수 있도록 앱 체크를 사용 설정해야 합니다.