concept/DataBase

Firebase 의 상위 버전이 나왔다고? Supabase 알아보고 세팅하기

오연 : Oana 2024. 12. 4. 17:35

2년 전 쯤이었나..

프론트엔드 개인 프로젝트를 해 보려고 서버리스 서비스인 파이어베이스를 활용했던 적이 있었다.

웹 쪽 레퍼런스가 많지는 않았어서 힘들었지만 나름대로 만족했었던 툴.

 

Firebase 는 비관계형 데이터베이스(nosql)로 제공이 되었었고,

Supabse 는 PostgreSQL을 기반으로 관계형 데이터 베이스 구축이 가능하다는 점이 가장 큰 차이점이었는데

조금 더 장단점을 살펴보자.

 

Firebase 장점

- Google의 강력한 생태계와 통합되어 있어 Google Cloud 서비스와 쉽게 연동됩니다.
- 실시간 데이터베이스와 NoSQL 데이터베이스 기능이 뛰어나며, 인증, 호스팅, 클라우드 함수 등 풍부한 기능을 제공합니다.
- 모바일 및 웹 앱 개발에 특화되어 있고, SDK가 매우 안정적입니다.
- 큰 커뮤니티와 풍부한 문서화로 학습 리소스가 많습니다.

Firebase 단점

- 대규모 데이터나 복잡한 쿼리에서는 성능과 비용 효율성이 떨어질 수 있습니다.
- 벤더 락인(Vendor Lock-in)의 위험이 있으며, 다른 플랫폼으로의 마이그레이션이 어렵습니다.
- 상세한 데이터베이스 스키마 설계와 관계형 데이터베이스 기능이 제한적입니다.

Supabase 장점

- PostgreSQL 기반으로 관계형 데이터베이스의 강력한 기능을 제공합니다.
- 오픈소스 접근 방식으로 더 높은 유연성과 커스터마이징 옵션을 제공합니다.
- 실시간 변경 감지, Row Level Security 등 현대적인 데이터베이스 기능을 지원합니다.
- Firebase보다 더 저렴한 가격 정책을 가지고 있습니다.

Supabase 단점

- Firebase에 비해 상대적으로 커뮤니티와 생태계의 규모가 작습니다.
- 일부 기능들이 아직 완전히 성숙하지 않았을 수 있습니다.
- Google의 광범위한 클라우드 통합 기능만큼 포괄적이지 않을 수 있습니다.

 

사실 Firebase 의 아쉬운 점이 복잡한 쿼리작업에 한계가 있다는 점 정도라면 내가 할 프로젝트에는 그정도의 쿼리가 필요하지는 않기 때문에 큰 의미는 없지만, Firebase 를 한번 써 보기도 했었고, 비관계형 데이터 베이스가 개인적으로는 살짝 불편한 느낌이라 이번 사이드 프로젝트에는 Supabase 를 활용해보기로 결정!

 

 

 

프로젝트 Setting

 

나는 Next.js 프로젝트에 세팅 예정이다. 우선 Supabase 사이트에 접속하자.

https://supabase.com/

 

Supabase | The Open Source Firebase Alternative

Build production-grade applications with a Postgres database, Authentication, instant APIs, Realtime, Functions, Storage and Vector embeddings. Start for free.

supabase.com

 

 

 

 

Supabase 에 회원가입, 로그인을 했다면 Organization과 Project 생성이 필요하다.

생성을 완료했다면 제공되는 API key와 Project URL 을 복사해두자.

 

 

그리고 내 Next.js 프로젝트의 env 파일에 해당 값들을 넣어둔다.

 

 

그리고 supabase 웹 사이트에서 자체적으로 테스트용 테이블들을 생성해서 row 들을 추가해 두었다.

 

 

 

그리고 난 후

Next.js 프로젝트에 @supabase/supabase-js 패키지를 설치하자.

yarn add @supabase/supabase-js

 

 

그리고 supabse 를 불러올 파일을 내 Next.js 프로젝트에 하나 생성한다.

나는 utils 라는 폴더를 만들고 그 안에 파일을 생성했다.

 

// src/utils/supabase/client.ts

import { createClient } from "@supabase/supabase-js";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL as string;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY as string;
export const supabase = createClient(supabaseUrl, supabaseKey);

 

 

이렇게 생성된 supabase 클라이언트를 export 해서 서버 요청 시 활용할 수 있는데,

이 요청을 하기 위한 폴더를 api 라는 이름으로 새로 생성했다.

 

// src/api/test/test.ts

import { supabase } from "@/utils/supabase/client";

export default async function handler() {
  const { data: user, error } = await supabase.from("user").select("*");

  console.log(user);
  console.log(error);

  return user;
}

 

 

이렇게 supabase 에 접근해서 user 라는 테이블에 모든 rows 를 가지고 오라는 명령어를 입력하고 콘솔창에 잘 나오는지 확인

 

만든 handler 함수를 활용하기 위해서 React Component 페이지에서 해당 함수를 호출했다.

 

"use client";

import { useEffect } from "react";
import handler from "@/api/test/test";

export default function Server() {

  useEffect(() => {
    const testFunction = async () => {
      await handler();
    };

    fetchUser();
  }, []);

  return (
    <div>
      <h1>Server Test Page</h1>
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </div>
  );
}

 

이렇게 supabase 테스트 완료! 인 줄 알았는데...

 

 

에러 핸들링 - 테이블 데이터 조회를 하는데 빈 배열이 나오는 현상

 

왜 빈 배열이 나오는거지???????

분명히 테스트 테이블에 2개의 데이터를 넣어두었는데 말이다...

 

RLS policy 문제인 것으로 의심

 

여기서 잠깐 RLS 란? Row Level Security 정책의 약자로 데이터베이스 수준에서 테이블의 각 행에 대한 접근 권한을 세밀하게 제어하는 PostgreSQL의 보안 기능이다.

 

쉽게 말해서 권한이 없어서 그렇다는 것

 

 

우선 Add RLS policy 버튼을 클릭해서 정책을 추가해주자.

 

 

 

이렇게 RLS 정책을 disable 하니까 테이블 데이터 조회는 잘 됨

그런데 찝찝하자나,,

 

권한 정책 설정을 해 보자.

 

 

 

요렇게 Policy Name 을 설정하고 using 에 원하는 값을 넣어주면 정책 설정이 가능하다.

권한에 따라 이렇게 다양하게 설정할 수 있으니 참고!

 

1. 공개 읽기 권한 정책 생성

-- 모든 사용자에게 읽기 권한 부여
CREATE POLICY "Allow public read" 
ON your_table 
FOR SELECT 
USING (true);



2. 인증된 사용자에게만 권한 부여

CREATE POLICY "Allow authenticated users to read" 
ON your_table 
FOR SELECT 
USING (auth.uid() IS NOT NULL);



3. 특정 조건부 접근 정책

CREATE POLICY "Allow specific conditions" 
ON your_table 
FOR SELECT 
USING (
  -- 예: 특정 컬럼 값에 따른 접근 제어
  some_column = current_user_id()
);



4. Supabase 클라이언트 측 권한 설정

const supabase = createClient('YOUR_SUPABASE_URL', 'YOUR_SUPABASE_ANON_KEY', {
  auth: {
    persistSession: true
  }
})