본문 바로가기
Development/Unreal Engine

[언리얼엔진 #3] Firebase를 통한 무료 데이터베이스 구축(Firebase Functions, REST API, express)

by 남디윤 2023. 10. 6.

안녕하세요 오늘은 Firebase Functions와 REST API를 활용해서

데이터베이스를 구축한 이야기를 해보려고 합니다.

firebase 유로 플러그인이 아닌 rest api 와 varest 플러그인을 사용하는 무료 방법입니다.

 

 

0. 배경

원래는 MySQL 무료 플러그인을 사용해서 GCP MySQL 인스턴스를 연결했었는데

패키징 중에 에러가 있는 것을 확인했습니다.

원래 플러그인이 언리얼 4.26버전이여서 그런지 몰라도 제가 쓰는 5.1에서는 패키징 에러가 났고

다른 방법을 찾기로 결심했습니다.최후의 보루를 유료 플러그인으로 생각하고 이런 저런 방법을 찾았습니다. 

 

* mysql 포스팅

https://uni-datastudy.tistory.com/9?category=1131242

 

처음에 알아본 것은 EOS랑 Playfab 서비스였습니다.

EOS는 c++코드를 많이 수정해야하는 것 같아서 중도 포기를 결정했고

Playfab의 경우 회원가입, 로그인 등은 구축했지만 채팅 기록 데이터베이스를 만드려면 cloud script 부분을 수정해야 해서 역시 중도포기를 결정했습니다. 정확히는 데이터베이스는 firebase를 쓰고 회원가입, 로그인은 playfab을 쓰기로 했습니다.

(확실하지 않습니다. 제가 알아본 바로는 플레이어의 공격력: 50 과 같은 단순 key:value 데이터는 생성, 수정, 삭제가 쉬운데 저의 경우에는 로우를 계속 추가해야해서 복잡한듯 하여 포기했습니다.)

 

그러다가 든 생각이 데이터베이스에 rest api 형태로 데이터를 추가, 조회하는건 어떨까라는 생각을 하였습니다.

왜냐면 varest 라는 api 는 확실히 잘 작동하기 때문에... (모든걸 rest api 로 해결하려는 병에 걸리게됨)

원래는 GCP MySQL을 rest api로 연결할까 했지만 검색하다보니 Firebase가 많이 보이게 되었고 Firebase 사용을 결정하게 되었습니다.

 

꺾였지만 계속 알아봤고 시도했고 결론적으로는 Firebase Rest Api 로 데이터베이스 부분을 완성하였습니다.

 

* Firebase에서 꼭 functions를 써야하는건 아닙니다만 저는 로컬이 아니라 서버로 api를 올리고 싶었기에 진행했습니다.

 


간단히 제가 만들었던 과정을 소개해드릴게요!

저도 많은 블로그와 유튜브를 참고했습니다.

특히 많이 참고한 유튜브는 아래 링크에서 확인하실 수 있습니다.

https://www.youtube.com/watch?v=bs_xs9-RJvc&t=3145s 

 

1. 파이어베이스 시작하기

구글 로그인하고 firebase 들어가서 시작하기 누르면 됩니다.

 

 2. 데이터베이스 시작하기

전 테스트 모드로 시작했고 멀티리전 nam5 으로 진행했습니다.

여기서 "예상치 못한? 예기치 못한 오류가 발생했다" 라는 에러가 있었는데

새로고침하니 이미 만들어져있었습니다.

 

제가 튜토리얼 영상을 찍느냐고 (전 대학원생이라 ^^) 아예 새로운 컴+새로운 구글아이디에서 진행했는데

첫번째에서는 에러가 안났는데 두번째에서는 왜인지 에러가 나더라구요

 

 

 

3. Cloud Function 설정

저는 vs code상에서 작업했습니다.

Postman, nodeJS는 웹브라우저 검색을 통해 설치했고

[npm i express, cors] 를 통해 라이브러리 설치가 필요합니다.

[npm install -g firebase-tools]를 사용해 Firebase CLI 도구를 전역으로 설치합니다

 

 

4. Firebase Login init

[firebase login] 하고 구글 로그인 화면 뜨면 로그인 및 승인

[firebase init]

이 과정에서도 새로운 컴에서는 에러가 떴는데 구글에서 검색한 결과

powershell을 관리자 권한으로 열고, [Set-ExecutionPolicy RemoteSigned]을 입력해서 설정을 변경하였습니다.

그러고 다시 vs code 에 재접속 후 진행하니 에러없이 잘 진행되었습니다.

여기서 저는 

진행 언어는 Javascript를 선택했는데

언어를 자바스크립트로 진행한것은 대부분의 블로그와 유튜브에서 자바스크립트를 썼기에 동일하게 진행하고자 자바스크립트를 썼습니다만 파이썬 코드로도 진행 가능은 한 것으로 알고 있습니다.

저도 자바스크립트 거의 모르는데,, 유튜브 보고 대략적으로 이렇게 돌아가는구나 하면서 따라했고

부분부분 직접 수정 + gpt 채찍질하면서 무사히 코드 작성 완료..했습니다.^^

 

그리고 저는 ESLint는 No를  선택했습니다.

이미 자바스크립트 짜시는 분들은 자신만의 ESLint가 있다고 해서 No 하시기도 하는데

저는 그런건 없지만 Yes를 하니 너무 에러가 떠서 그냥 No를 했습니다.

* ESLint : JavaScript 코드에서 일관된 스타일을 유지하고 버그를 예방하기 위한 정적 코드 분석 도구입니다 (GPT 슨생님 왈)

 

 

 

 

5. Firebase Admin SDK 설정

유튜브에서 보고 그대로 진행한 부분입니다

Firebase 에서 프로젝트 세팅 - 서비스 계정 부분에서 코드 복사 및 새 비공개 키 생성 (=json 파일 다운) 후 파일 이동 및 index.js부분에 코드 작성해줍니다.

 

 

 

6. CRUD 작성

7번에서 테스트, 배포하는 내용 나옵니다

전 3개의 기능?을 만들었습니다.

POST 2개와 GET 1개

전반적인 코드는 유튜브를 참고했고

특정 부분은 제가 수정했으며

또 특정부분은 gpt가 해주었습니다...ㅎㅎ

 

블러가 중앙에 잘못 들어갔네용..

 

아래는 제 전체 index.js 코드입니다.

const functions = require("firebase-functions");

const admin = require("firebase-admin");

var serviceAccount = require("./serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors({origin:true}));

const db=admin.firestore();

// Routes
app.get('/', (req, res)=> {
    return res.status(200).send('Hai there how you doing?....');
});

// Create
app.post("/create", (req, res)=> {
    (async ()=>{
        try{
            await db.collection('userDetails').doc(req.body.id).create({
                id: req.body.id
            })

            return res.status(200).send({status:'Sucess', msg:'Data Saved'});
        } catch(error) {
            console.log(error)
            return res.status(500).send({status:'Failed', msg:error});
        }
    })();
})

// id값과 채팅 기록 넣기
app.post("/userChat/:id", (req, res)=>{
    const {id} = req.params;

    const chatData={
        chatId: Date.now(),
        subject: req.body.subject,
        content:req.body.content
    };
    (async () =>{
        try {
            const userRef = db.collection('userDetails').doc(id);
            const userDoc = await userRef.get();
    
            if (!userDoc.exists) {
                return res.status(404).send({ status: 'Failed', msg: 'User not found' });
            }
    
            const userData = userDoc.data();
            const updatedChats = [...(userData.chats || []), chatData]; // 추가된 부분

            await userRef.update({ chats: updatedChats }); // chats 필드 업데이트
    
            return res.status(200).send({ status: 'Success', msg: 'Chat created successfully' });
        } catch (error) {
            console.log(error);
            return res.status(500).send({ status: 'Failed', msg: error });
        }
    })();    
});

// id값에 따라서 데이터 가져오기
app.get("/userChat/:id", (req, res) => {
    (async () => {
      try {
        const reqDoc = db.collection("userDetails").doc(req.params.id);
        let userDetail = await reqDoc.get();
        let response = userDetail.data();
  
        return res.status(200).send({ status: "Success", data: response });
      } catch (error) {
        console.log(error);
        res.status(500).send({ status: "Failed", msg: error });
      }
    })();
  });


exports.app = functions.https.onRequest(app);

 

 

7. 테스트, 배포하기

cd functions를 통해 폴더 이동이 필요합니다.

 

테스트는 간단히 [npm run serve]를 터미널에 입력하면 로컬 주소가 뜨고 포스트맨에서 테스트 가능합니다.

 

배포의 경우 firebase 요금제를 업그레이드 시켜야합니다만

무료 요금제를 포함한 요금제이고 무료 요금제가 비상업적인 목적에서는 넘길일이 없을 것으로 예상됩니다.

한도도 설정할 수 있어서 전 500원 설정했습니다...ㅎㅎㅎㅎㅎ

요금제 변경 이후 다시 터미널로 돌아와서 firebase deploy 를 하면 주소가 나옵니다. 

 

 

+) 그리고 언리얼엔진에서는 이런식으로 구성했습니다.

위에서 말씀드린것처럼 저는 로그인 자체는 playfab을 쓰기 때문에

playfab 에서 회원가입에 성공할 때 그 username을 firebase api 에 post하는 방식으로 구성했습니다.

 

 

 

추후에 playfab 내용도 가지고 올 수 있으면 가져오겠습니다.

제 인생에도 드디어 api 를 만들어보는 일을 했네요 ㅎㅎㅎ

신난당

나중에는 gcp 나 aws 에도 올려보는게 꿈?목표?입니다 ㅎㅎ

그럼 여기서 글을 마칩니다