본문 바로가기

개발

React 서버리스 함수 개발 및 배포

서버리스 함수란 서버를 직접 관리하지 않고, 클라우드 플랫폼에서 제공하는 함수형 서비스를 이용하여 애플리케이션의 로직을 실행하는 방식입니다. 서버리스 함수는 다음과 같은 장점을 가집니다.

 

- 서버의 프로비저닝, 스케일링, 보안, 유지보수 등의 작업을 신경 쓰지 않아도 됩니다.

- 요청이 발생할 때만 함수가 실행되고, 사용한 자원만큼만 비용이 발생합니다.

- 다양한 이벤트 소스와 트리거를 통해 함수를 실행할 수 있습니다.

 

React에서 백엔드 로직을 수행하기 위해서는 별도의 서버가 필요합니다. 서버리스 함수를 사용하면, React 애플리케이션에서 필요한 백엔드 로직을 간단하고 효율적으로 구현할 수 있습니다. 예를 들어, 인증, 데이터베이스, 파일 업로드, 메일 전송 등의 작업을 서버리스 함수로 처리할 수 있습니다.

서버리스 함수를 개발하고 배포하는 방법은 다양하지만, 이 글에서는 Firebase라는 클라우드 플랫폼을 사용해보겠습니다. Firebase는 구글에서 제공하는 모바일 및 웹 애플리케이션 개발 플랫폼으로, 다음과 같은 기능을 제공합니다.

- Cloud Functions for Firebase: 서버리스 함수를 개발하고 배포할 수 있는 기능입니다. Node.js, Python, Go, Java 등의 언어를 지원하며, HTTP 요청, 파이어베이스 데이터베이스 변경, 파이어베이스 인증 이벤트 등을 트리거로 사용할 수 있습니다.

- Firebase Hosting: 정적 웹 애플리케이션을 배포할 수 있는 기능입니다. SSL 인증서와 CDN을 제공하며, Cloud Functions와 연동하여 동적인 웹 애플리케이션을 구현할 수 있습니다.

 

이 예제에서는 간단한 카운터 애플리케이션을 생성하겠습니다.

Firebase를 사용하여 React 애플리케이션에 서버리스 함수를 개발하고 배포하는 방법은 다음과 같습니다.

1. React 애플리케이션을 생성합니다. 

2. Firebase 프로젝트를 생성하고 초기화합니다. Firebase CLI를 설치하고, Firebase 프로젝트를 생성하고, 로컬 프로젝트와 연결합니다.

3. 서버리스 함수를 개발합니다. Cloud Functions for Firebase를 사용하여 서버리스 함수를 개발하고, 로컬에서 테스트합니다. 이 예제에서는 카운터 값을 증가시키는 함수와 감소시키는 함수를 개발하겠습니다.

4. React 애플리케이션과 서버리스 함수를 배포합니다. Firebase Hosting을 사용하여 React 애플리케이션과 서버리스 함수를 배포하고, 웹 브라우저에서 확인합니다.

 

React 카운터 애플리케이션 생성하기

먼저, React 애플리케이션을 생성해보겠습니다. 이 예제에서는 간단한 카운터 애플리케이션을 생성하겠습니다. 카운터 애플리케이션은 다음과 같은 기능을 가집니다.

- 카운터 값은 파이어베이스 데이터베이스에 저장됩니다.

- 버튼을 클릭하면, 서버리스 함수를 호출하여 카운터 값을 1 증가시킵니다.

- 버튼을 클릭하면, 서버리스 함수를 호출하여 카운터 값을 1 감소시킵니다.

 

React 애플리케이션을 생성하기 위해서는 다음과 같은 작업을 수행해야 합니다.

 

- Node.js와 npm을 설치합니다. Node.js는 자바스크립트 런타임 환경이고, npm은 자바스크립트 패키지 매니저입니다. Node.js와 npm은 공식 홈페이지에서 다운로드할 수 있습니다.

- create-react-app 명령어를 사용하여 React 애플리케이션을 생성합니다. create-react-app은 React 애플리케이션의 보일러플레이트 코드를 생성해주는 도구입니다. create-react-app 명령어는 다음과 같은 구조로 사용합니다.

npx create-react-app react-firebase-serverless

 

React 애플리케이션의 소스 코드를 작성합니다. React 애플리케이션의 소스 코드는 src 폴더에 위치합니다. 이 예제에서는 src 폴더 내의 모든 파일을 삭제하고, 새로운 파일들을 작성하겠습니다. 작성할 파일들은 다음과 같습니다.

- index.js: React 애플리케이션의 진입점입니다. App 컴포넌트를 렌더링합니다.

- App.js: React 애플리케이션의 최상위 컴포넌트입니다. Counter 컴포넌트를 렌더링합니다.

- Counter.js: 카운터 기능을 구현한 컴포넌트입니다. 파이어베이스 데이터베이스와 서버리스 함수와 통신합니다.

 

다음은 각 파일의 코드입니다.

 

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

App.js

import React from 'react';
import Counter from './Counter';

function App() {
  return (<div className="App">
  <h1>React Firebase Serverless</h1>
  <Counter />
	</div>);
}

export default App;

Counter.js

import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/database';
import 'firebase/functions';

// 파이어베이스 프로젝트의 설정 정보를 입력합니다.
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID"
};

// 파이어베이스 앱을 초기화합니다.
firebase.initializeApp(firebaseConfig);

// 파이어베이스 데이터베이스를 사용하기 위한 참조를 생성합니다.
const database = firebase.database();

// 파이어베이스 서버리스 함수를 사용하기 위한 참조를 생성합니다.
const functions = firebase.functions();

function Counter() {
  // 카운터 값을 상태로 관리합니다.
  const [count, setCount] = useState(0);

  // 컴포넌트가 마운트될 때, 파이어베이스 데이터베이스에서 카운터 값을 가져옵니다.
  useEffect(() => {
    // 카운터 값을 저장하는 노드의 참조를 생성합니다.
    const counterRef = database.ref('counter');

    // 노드의 값이 변경될 때마다, 상태를 업데이트합니다.
    counterRef.on('value', (snapshot) => {
      setCount(snapshot.val());
    });

    // 컴포넌트가 언마운트될 때, 이벤트 리스너를 제거합니다.
    return () => {
      counterRef.off();
    };
  }, []);

  // + 버튼을 클릭하면, 카운터 값을 증가시키는 서버리스 함수를 호출합니다.
  const handleIncrement = async () => {
    // 서버리스 함수의 참조를 생성합니다.
    const incrementCounter = functions.httpsCallable('incrementCounter');

    // 서버리스 함수를 호출하고, 응답을 받습니다.
    const response = await incrementCounter();

    // 응답에 에러가 있으면, 콘솔에 출력합니다.
    if (response.data.error) {
      console.error(response.data.error);
    }
  };

  // - 버튼을 클릭하면, 카운터 값을 감소시키는 서버리스 함수를 호출합니다.
  const handleDecrement = async () => {
    // 서버리스 함수의 참조를 생성합니다.
    const decrementCounter = functions.httpsCallable('decrementCounter');

    // 서버리스 함수를 호출하고, 응답을 받습니다.
    const response = await decrementCounter();

    // 응답에 에러가 있으면, 콘솔에 출력합니다.
    if (response.data.error) {
      console.error(response.data.error);
    }
  };
  
  return (
  	<div className="Counter">
  		<h2>Counter: {count}</h2>
  		<button onClick={handleIncrement}>+</button>
  		<button onClick={handleDecrement}>-</button>
	</div>)
}

export default Counter;

 

Firebase 프로젝트 생성하고 초기화하기

다음으로, Firebase 프로젝트를 생성하고 초기화해보겠습니다. Firebase 프로젝트는 파이어베이스의 모든 기능을 사용할 수 있는 컨테이너입니다. Firebase 프로젝트를 생성하고 초기화하기 위해서는 다음과 같은 작업을 수행해야 합니다.

- Firebase CLI를 설치합니다. Firebase CLI는 파이어베이스 프로젝트를 관리하고, 서버리스 함수를 개발하고 배포할 수 있는 도구입니다. Firebase CLI는 다음과 같은 명령어로 설치할 수 있습니다.

npm install -g firebase-tools

-Firebase 프로젝트를 생성합니다. Firebase 프로젝트는 Firebase 콘솔에서 생성할 수 있습니다. 콘솔에 접속한 후에, 프로젝트 추가 버튼을 클릭하고, 프로젝트의 이름과 설정을 입력합니다.

-로컬 프로젝트와 Firebase 프로젝트를 연결합니다. 로컬 프로젝트의 루트 폴더에서 다음과 같은 명령어를 실행합니다.

firebase init

 

명령어를 실행하면, 다음과 같은 질문들에 답해야 합니다.

- Which Firebase CLI features do you want to set up for this folder? : 파이어베이스의 어떤 기능을 사용할 것인지 선택하는 질문입니다. 이 예제에서는 Database와 Functions, Hosting을 선택합니다.

- Please select an option: : 파이어베이스 프로젝트를 선택하는 옵션입니다. 이 예제에서는 Use an existing project를 선택하고, 앞서 생성한 프로젝트를 선택합니다.

- What file should be used for Database Rules? : 데이터베이스 규칙을 정의한 파일의 이름을 입력하는 질문입니다. 기본값인 database.rules.json을 그대로 사용합니다.

- What language would you like to use to write Cloud Functions? : 서버리스 함수를 작성할 언어를 선택하는 질문입니다. 이 예제에서는 JavaScript를 선택합니다.

- Do you want to use ESLint to catch probable bugs and enforce style? : ESLint를 사용할 것인지 묻는 질문입니다. ESLint는 자바스크립트 코드의 오류나 스타일을 검사하는 도구입니다. 이 예제에서는 No를 선택합니다.

- Do you want to install dependencies with npm now? : npm으로 의존성 패키지를 설치할 것인지 묻는 질문입니다. 이 예제에서는 Yes를 선택합니다.

- What do you want to use as your public directory? : 정적 웹 애플리케이션을 배포할 폴더의 이름을 입력하는 질문입니다. 이 예제에서는 build를 입력합니다.

- Configure as a single-page app (rewrite all urls to /index.html)? : 단일 페이지 애플리케이션으로 설정할 것인지 묻는 질문입니다. 이 예제에서는 Yes를 선택합니다.

- Set up automatic builds and deploys with GitHub? : GitHub와 연동하여 자동으로 빌드하고 배포할 것인지 묻는 질문입니다. 이 예제에서는 No를 선택합니다.

 

명령어가 완료되면, 다음과 같은 파일들이 생성됩니다.

.firebaserc: 파이어베이스 프로젝트의 정보를 저장하는 파일입니다.

firebase.json: 파이어베이스 프로젝트의 설정을 저장하는 파일입니다.

database.rules.json: 파이어베이스 데이터베이스의 규칙을 정의하는 파일입니다.

functions/package.json: 서버리스 함수의 의존성 패키지를 정의하는 파일입니다.

functions/index.js: 서버리스 함수의 소스 코드를 작성하는 파일입니다.

 

서버리스 함수 개발하기

다음으로, 서버리스 함수를 개발해보겠습니다. 서버리스 함수는 Cloud Functions for Firebase를 사용하여 개발하고, 로컬에서 테스트할 수 있습니다. 서버리스 함수를 개발하기 위해서는 다음과 같은 작업을 수행해야 합니다.

 

서버리스 함수의 소스 코드를 작성합니다. 서버리스 함수의 소스 코드는 functions/index.js 파일에 작성합니다. 이 예제에서는 카운터 값을 증가시키는 함수와 감소시키는 함수를 작성하겠습니다. 작성할 함수들은 다음과 같은 기능을 가집니다.

incrementCounter: 파이어베이스 데이터베이스에서 카운터 값을 가져와서 1 증가시키고, 다시 저장합니다. HTTP 요청을 트리거로 사용하며, 요청에 에러가 있으면 응답에 에러 메시지를 전달합니다.

decrementCounter: 파이어베이스 데이터베이스에서 카운터 값을 가져와서 1 감소시키고, 다시 저장합니다. HTTP 요청을 트리거로 사용하며, 요청에 에러가 있으면 응답에 에러 메시지를 전달합니다.

다음은 각 함수의 코드입니다.

 

functions/index.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');

// 파이어베이스 앱을 초기화합니다.
admin.initializeApp();

// 파이어베이스 데이터베이스를 사용하기 위한 참조를 생성합니다.
const database = admin.database();

// 카운터 값을 증가시키는 함수입니다.
exports.incrementCounter = functions.https.onCall(async (data, context) => {
  try {
    // 카운터 값을 저장하는 노드의 참조를 생성합니다.
    const counterRef = database.ref('counter');

    // 노드의 값을 읽고, 1 증가시킨 후, 다시 저장합니다.
    await counterRef.transaction((current) => {
      return (current || 0) + 1;
    });

    // 응답에 성공 메시지를 전달합니다.
    return { message: 'Counter incremented successfully' };
  } catch (error) {
    // 응답에 에러 메시지를 전달합니다.
    return { error: error.message };
  }
});

// 카운터 값을 감소시키는 함수입니다.
exports.decrementCounter = functions.https.onCall(async (data, context) => {
  try {
    // 카운터 값을 저장하는 노드의 참조를 생성합니다.
    const counterRef = database.ref('counter');

    // 노드의 값을 읽고, 1 감소시킨 후, 다시 저장합니다.
    await counterRef.transaction((current) => {
      return (current || 0) - 1;
    });

    // 응답에 성공 메시지를 전달합니다.
    return { message:‘Counter decremented successfully’ }; 
    
    } catch (error) { 
        // 응답에 에러 메시지를 전달합니다.
        return { error: error.message }; 
    } 
    });

 

- 서버리스 함수를 로컬에서 테스트합니다. `firebase emulators:start` 명령어를 사용하여 서버리스 함수를 로컬에서 테스트할 수 있습니다

- 웹 브라우저에서 http://localhost:4000 에 접속하면, Firebase Emulator Suite의 대시보드를 볼 수 있습니다. 대시보드에서 Functions 탭을 클릭하면, 작성한 서버리스 함수들의 정보와 로그를 확인할 수 있습니다.

 

React 애플리케이션과 서버리스 함수를 배포하기

마지막으로, Firebase Hosting을 사용하여 React 애플리케이션과 서버리스 함수를 배포해보겠습니다. Firebase Hosting은 정적 웹 애플리케이션을 배포할 수 있는 기능입니다. Firebase Hosting은 SSL 인증서와 CDN을 제공하며, Cloud Functions와 연동하여 동적인 웹 애플리케이션을 구현할 수 있습니다. React 애플리케이션과 서버리스 함수를 배포하기 위해서는 다음과 같은 작업을 수행해야 합니다.

- React 애플리케이션을 빌드합니다. `npm run build` 명령어를 사용하여 React 애플리케이션을 빌드할 수 있습니다. 빌드된 파일들은 `build` 폴더에 저장됩니다.

- Firebase 프로젝트에 로그인합니다. `firebase login` 명령어를 사용하여 Firebase 프로젝트에 로그인할 수 있습니다. 로그인 후에 웹 브라우저에서 인증 절차를 완료해야 합니다.

- React 애플리케이션과 서버리스 함수를 배포합니다. `firebase deploy` 명령어를 사용하여 React 애플리케이션과 서버리스 함수를 배포할 수 있습니다. 배포가 완료되면, 파이어베이스 콘솔에서 배포된 사이트의 URL을 확인할 수 있습니다.

여기까지 React에서의 서버리스 함수 개발과 배포에 대해 알아보았습니다.