개발/FrontEnd

Next.js에서 Firebase Remote Config(원격 구성) 수정하기

꾸럭 2021. 12. 22. 07:57

Firebase Remote Config란 애플리케이션의 각종 기본값들을 Firebase를 통해 손쉽게 관리할 수 있도록 하는 클라우드 툴이다.

 

Firebase 원격 구성  |  Firebase Documentation

앱 업데이트를 게시하지 않고도 일일 활성 사용자 수 제한 없이 무료로 앱의 동작과 모양을 변경할 수 있습니다.

firebase.google.com

 

각종 기본값들의 경우 애플리케이션의 탭 리스트가 될 수도 있고 각종 스태틱한 값들이 될 수 있다. 이러한 값들의 경우 서비스 기획이나 정책에 따라 언제든지 변경될 수 있다.

이럴 경우 보통 데이터베이스와 백엔드를 통해 관리를 하게 되는데 이것을 구현하는게 어렵지는 않지만 번거롭고 시간이 걸릴 수 있어서 프로덕트 스케줄에서 우선순위에서 밀릴 수 있다.

그래서 이러한 값들은 처음에는 하드코딩해서 들어가는 경우가 왕왕 있다.

 

웹 애플리케이션의 경우 조금 귀찮긴 하지만 언제든지 수정 배포가 가능하다.

그런데 iOS나 Android 애플리케이션의 경우 배포 단계에서 구글 또는 애플의 심사 과정이 있으며, 사용자가 앱을 업데이트하는 데까지 시간이 걸리며, 일부 유저들은 끝까지 업데이트를 하지 않는 경우도 있기 때문에 서버 사이드를 통한 기본값 관리가 필수적이다.

 

그래서 규모가 작은 프로덕트 팀에서는 이러한 원격 구성 툴을 많이들 쓰곤 한다.

이런 식으로 매개변수를 추가/수정 등이 가능하고 값을 바꾸면 애플리케이션에도 동적으로 반영이 된다.

 

문제는 처음에는 좋다고 쓰지만 나중에는 파이어베이스 콘솔에 들어와서 저걸 또 수정하고 하는 작업들이 번거로워지게 된다.

또한 정말 자유롭게 수정할 수 있기 때문에 담당자가 혹시라도 잘못 건들면 그 순간 애플리케이션에서는 에러가 발생할 수 있다.

여기서 담당자는 엔지니어가 아닐 확률이 매우 높으며, 이런 실수를 방지하기 위해 엔지니어에게 매번 요청하는 것도 번거롭다.

보통 이러한 값들을 변경할 때는 엔지니어링 관점에서 구조적으로 뜯어고치는 것보다 운영팀에서 의사결정 후 빠르게 변경하는 경우가 많은데 매번 엔지니어에게 요청할 수는 없지 않은가.

 

그래서 내부 백오피스를 통해서 이러한 값들을 열람하고 수정하고 추가하는 등의 수요가 있을 수밖에 없다. 백오피스를 통해 개발을 하게 되면 특정 값들의 구조적인 제한도 자유롭게 걸 수 있고 이에 따른 UI도 편안하게 마련할 수 있기 때문에 일단 만들어 놓으면 운영팀에서 자유롭게 관리가 가능하다.

 

이 포스트에서는 백오피스가 Next.js로 되어 있는 케이스에서 어떻게 적용하면 될지 다룬다.

 

우선 Firebase에서 제공하는 API나 SDK가 필요한데 다행히 둘 다 있으며, 여기에서는 SDK를 사용하는 방식을 다룬다.

 

프로그래매틱 방식으로 원격 구성 수정  |  Firebase Documentation

의견 보내기 프로그래매틱 방식으로 원격 구성 수정 이 문서에서는 JSON 형식의 매개변수 및 조건 집합을 프로그래매틱 방식으로 읽고 수정할 수 있는 원격 구성 템플릿에 대해 설명합니다. 이

firebase.google.com

 

우선 파이어베이스 콘솔에 들어가서 아래 스크린샷과 같이 설정 아이콘을 누르고 "프로젝트 설정"에 접근한다.

그리고 "서비스 계정" 탭으로 들어가면 아래와 같은 화면이 보인다.

여기서 "새 비공개 키 생성"을 누르면 json 파일이 다운로드되는데 이제 이걸 가지고 인증을 하고 SDK를 활용할 것이다.

이 json 파일만 있으면 누구든지 나의 파이어베이스에 접근해 무슨 짓이든 할 수 있으니 반드시 잘 보관해야 하며,

이 파일이 절대로 Public으로 호스팅 되거나 클라이언트 사이드에서 접근할 수 있게 하면 안 된다.

 

우선 프로젝트에서 다음과 같이 firebase-admin을 설치한다.

$ npm install firebase-admin

 

Admin SDK의 로직은 절대로 클라이언트 사이드에서 돌면 안 되기 때문에 이 로직은 src/pages/api/ 하위에 둘 것이며, 클라이언트 사이드, 즉 React 컴포넌트에서는 이러한 Next.js의 api 라우트를 활용하여 콜 해서 쓸 것이다.

 

아래부터 설명하는 예시는 말 그대로 아주 간단한 예시일 뿐이며, 파일이나 세부 로직은 각 프로덕트의 성격이나 코딩 규칙에 따라 적절히 바꾸고 응용해서 쓰면 된다.

그야말로 돌아가게끔만 만든 코드일 뿐 각종 예외처리 등은 별도로 해야 한다.

 

일단 다운로드한 json 파일을 프로젝트에 넣자.

여기에서는 src/keys/config-adminsdk.json에 넣었다.

팀의 보안 정책에 따라서 프로젝트 내부에 넣지 않고 또 다른 어딘가에 저장해 두고 API로 당겨서 사용할 수도 있으니 참고하자.

 

그리고 API를 만들자

 

src/pages/api/config/parameters.ts

import type { NextApiRequest, NextApiResponse } from 'next';
import admin, { remoteConfig } from 'firebase-admin';
import serviceAccount from 'keys/config-adminsdk.json';

interface ResData {
    parameters: { [p: string]: remoteConfig.RemoteConfigParameter };
}

// WAS가 떠 있을 때 한번만 호출하면 된다. 다른 방식으로 처리할 수도 있지만 그냥 귀찮아서 try catch문으로 처리했다.
// 만약 아무런 처리가 없으면 중복으로 초기화됐다고 에러가 나면서 진행되지 않을 것이다.
try {
    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount as unknown as string),
    });
} catch (err) {}

export default async (req: NextApiRequest, res: NextApiResponse<ResData>) => {
    const config = admin.remoteConfig();
    const { parameters } = await config.getTemplate();

    res.status(200).json({ parameters });
};

 

src/pages/api/config/patch.ts

import type { NextApiRequest, NextApiResponse } from 'next';
import admin from 'firebase-admin';
import serviceAccount from 'keys/config-adminsdk.json';

try {
    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount as unknown as string),
    });
} catch (err) {}

export default async (req: NextApiRequest, res: NextApiResponse) => {
    const config = admin.remoteConfig();
    const template = await config.getTemplate();

    const { key, value } = req.body;

    template.parameters[key] = {
        defaultValue: {
            value,
        },
    };

    await config.publishTemplate(template);

    res.status(200).json({});
};

 

이제

1. /api/config/parameters를 호출하여 원격 구성의 값들을 가져올 수 있고

2. /api/config/patch를 호출하여 원격 구성의 값들을 수정할 수 있다.

3. 필요하다면 추가하는 작업까지 가능하나 여기서는 두 가지만 다룬다.

 

다음으로 클라이언트 사이드에서 폼을 만들고 이 API들을 호출하여 값을 가져오고 수정하는 코드를 보자. 이 역시 돌아가게끔만 만든 아주 간단한 예제로 적절히 응용하고 완성도 있게 바꿔서 써야 한다.

import axios from 'axios';
import { NextPage } from 'next';
import React, { useEffect, useState } from 'react';

interface ResData {
    parameters: any; // 역시 귀찮아서 이렇게 했다. 상황에 따라 타입을 잘 만들어주면 된다.
}

const Firebase: NextPage = () => {
    const [key1, setKey1] = useState('loading');
    const [inputKey, setInputKey] = useState('');

    const fetchData = async () => {
        const { parameters } = (await axios.get('/api/config/parameters')).data as ResData;

        setKey1(String(parameters.key1.defaultValue.value));
    };

    const updateData = async () => {
        setKey1('변경중...');

        await axios.patch('/api/config/patch', {
            key: 'key1',
            value: inputKey,
        });

        await fetchData();
    };

    useEffect(() => {
        fetchData().then();
    }, []);
    return (
        <div>
            <div>
                <h1>key1</h1>
                <p>{key1}</p>
                <div>
                    <input
                        type="text"
                        value={inputKey}
                        onChange={(e) => {
                            setInputKey(e.target.value);
                        }}
                    />
                    <button onClick={updateData}>변경</button>
                </div>
            </div>
        </div>
    );
};

export default Firebase;

 

처음 로드가 되면 우리가 파이어베이스 콘솔에서 세팅한 값이 보일 것이다.

그리고 텍스트 필드에 값을 넣어서 옆에 변경 버튼을 누르면 "변경중..."이라고 값이 바뀌었다가 좀 기다리면 새로 세팅한 값이 나타나면 성공이다.

파이어베이스 콘솔에 가서 보면 잘 바뀌어있다.

 

파이어베이스의 리모트 컨피그(원격 구성)를 프로덕트에서 활용할 때 백오피스에서 이런 식으로 기능을 만들면 엔지니어로서 귀찮은 일이 사라지고 운영팀에서도 보다 수월하게 프로덕트를 운영할 수 있다.

728x90