구현 목표
매일 특정 시간마다 특정 사이트를 스크래핑해서 원하는 데이터가 올라왔는지 확인하고,
데이터가 올라왔다면 DB에 저장 후, 앱 푸시를 보내는 기능을 구현하고 싶다.
일단 Functions가 어떻게 작동하는지 직접 코드를 작성하고 실행해 보면서 배워보려고 한다.
이번 글에서는 Firebase Functions를 초기화하고, 함수를 작성 후 배포까지 해 보았다.
프로젝트 초기화 및 구조 변경
npm install -g firebase-tools
Firebase CLI를 설치한다.
firebase login
다음 명령어를 실행하여 Google 계정으로 Firebase에 로그인한다.
firebase init
`firebase init`을 실행한다.

Firestore와 Fuctions를 선택한다.
참고로 Firebase 콘솔에서 이 두 개의 제품을 사용하기 위한 초기 설정을 해줘야 한다.
또한 Functions를 사용하기 위해서는 사용한 만큼만 요금을 지불하는 Blaze 요금제로 업그레이드해야 한다.

Funtions는 JavaScript, TypeScript, Python 세 가지 언어를 지원하는데 이 중 하나를 선택한다.

프로젝트 초기화가 완료되면 `Firebase CLI`에서
자동으로 `Firebase Admin SDK` 및 `Cloud Functions용 Firebase SDK` 모듈을 설치하고,
루트 디렉터리에 `functions` 폴더가 생성된다.
myproject
+- .firebaserc # Hidden file that helps you quickly switch between
| # projects with `firebase use`
|
+- firebase.json # Describes properties for your project
|
+- functions/ # Directory containing all your functions code
|
+- .eslintrc.json # Optional file containing rules for JavaScript linting.
|
+- package.json # npm package file describing your Cloud Functions code
|
+- index.js # Main source file for your Cloud Functions code
|
+- node_modules/ # Directory where your dependencies (declared in
# package.json) are installed
수정된 프로젝트 구조는 다음과 같다.
테스트 함수 작성
// functions/index.js
// The Cloud Functions for Firebase SDK to create Cloud Functions and triggers.
const { logger } = require("firebase-functions/v2");
const { setGlobalOptions } = require("firebase-functions/v2");
const { onRequest } = require("firebase-functions/v2/https");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
// The Firebase Admin SDK to access Firestore.
const { initializeApp } = require("firebase-admin/app");
const { getFirestore } = require("firebase-admin/firestore");
initializeApp();
setGlobalOptions({ region: "asia-northeast3" });
// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addmessage = onRequest(async (req, res) => {
// Grab the text parameter.
const original = req.query.text;
// Push the new message into Firestore using the Firebase Admin SDK.
const writeResult = await getFirestore()
.collection("messages")
.add({ original: original });
// Send back a message that we've successfully written the message
res.json({ result: `Message with ID: ${writeResult.id} added.` });
});
// Listens for new messages added to /messages/:documentId/original
// and saves an uppercased version of the message
// to /messages/:documentId/uppercase
exports.makeuppercase = onDocumentCreated("/messages/{documentId}", (event) => {
// Grab the current value of what was written to Firestore.
const original = event.data.data().original;
// Access the parameter `{documentId}` with `event.params`
logger.log("Uppercasing", event.params.documentId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing
// asynchronous tasks inside a function
// such as writing to Firestore.
// Setting an 'uppercase' field in Firestore document returns a Promise.
return event.data.ref.set({ uppercase }, { merge: true });
});
`onRequest()`를 사용해서 HTTP 이벤트를 처리하는 `addmessage` 함수를 만들었다.
쿼리 파라미터에서 텍스트 값을 추출하고,
`/messages/:documentId/original` 경로의 데이터베이스에 삽입한다.
`maekuppercase` 함수는 `onDocumentCreated()`를 통해
`messages` 컬렉션에 문서가 생성될 때마다 자동 실행되는데,
원본 메시지를 대문자로 변환한 필드를 추가로 생성한다.
함수 리전 변경
const { setGlobalOptions } = require("firebase-functions/v2");
initializeApp();
setGlobalOptions({ region: "asia-northeast3" });
함수는 기본적으로 `us-central1`에서 실행되기 때문에 이를 서울로 변경해야 한다.
리전은 함수가 배포되는 지역으로, 사용자와 가까운 리전에 배포해야 네트워크 지연 시간이 최소된다.
이미 배포된 함수의 리전을 변경하는 것은 다음 링크를 참고한다. 함수 리전 변경
로컬 에뮬레이터로 함수 테스트하기
Firebase Local Emulator Suite을 사용하면
Firebase 프로젝트에 배포하기 전에 로컬에서 앱을 빌드하고 테스트할 수 있다.
firebase emulators:start
로컬 에뮬레이터를 실행한다.

브라우저에 URL을 입력하여 Firebase Emulator Suite에 들어간다.

HTTP 함수의 URL을 복사해서, URL 끝에 쿼리 문자열 `?text=uppercaseme`를 추가한다.
(포트는 로컬 머신에 따라 다를 수 있다.)

브라우저의 새 탭에서 쿼리 파라미터를 추가한 URL을 열면 Firestore에 새 메시지가 만들어진다.

Firestore 탭에서 `messages` 컬렉션에 새로운 문서가 생성된 것을 확인할 수 있다.
프로덕션 환경에 함수 배포하기
firebase deploy --only functions
로컬 환경에서 함수가 잘 작동된다는 것을 확인했으니
이제 상단의 명령어를 실행하여 프로덕션 환경에 함수를 배포해 보자.

`addmessage`와 `makeuppercase` 함수 모두 배포가 완료되었다.

`addmessage` 함수의 URL을 복사해서 끝에 `?text=uppercaseme`를 추가한 후
브라우저에서 열어 보면 실제로 Firestore에 데이터가 잘 생성되는 것을 확인할 수 있다.
Firebase Cloud Functions 연동 시리즈
- [JavaScript] Firebase Cloud Functions 연동(2) - 지정된 시간마다 호출되는 함수
- [JavaScript] Firebase Cloud Functions 연동(3) - DB 조회 후 FCM 알림 전송
참고 문서