Supabase 사용 가이드

derek·2024년 10월 21일
0

Supabase는 강력한 기능을 제공하는 오픈 소스 백엔드 솔루션으로, 데이터베이스, 인증, 스토리지 등을 쉽게 설정하고 사용할 수 있습니다. 이번 포스트에서는 Supabase를 사용하여 프로젝트를 설정하고 데이터 CRUD(Create, Read, Update, Delete) 작업을 수행하는 방법에 대해 설명하겠습니다.

1. 기본 설정

테이블을 추가할 때 RLS(Row Level Security)를 활성화하여 사이드 프로젝트에서도 안전하게 사용할 수 있도록 합니다. 사용하지 않는 부분은 Null보다는 Empty 값으로 변경하는 것을 잊지 마세요.

스크립트 추가

yarn add @supabase/ssr @supabase/supabase-js

.env.local 파일에 환경 변수 추가

NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=

utils/supabase에 파일 추가

client.ts

import { createBrowserClient } from "@supabase/ssr";

export const createClient = () =>
  createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
  );

const browserClient = createClient();

export default browserClient;

middleware.ts

import { createServerClient } from "@supabase/ssr";
import { type NextRequest, NextResponse } from "next/server";

export const updateSession = async (request: NextRequest) => {
  try {
    let response = NextResponse.next({
      request: {
        headers: request.headers,
      },
    });

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return request.cookies.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value }) =>
              request.cookies.set(name, value),
            );
            response = NextResponse.next({
              request,
            });
            cookiesToSet.forEach(({ name, value, options }) =>
              response.cookies.set(name, value, options),
            );
          },
        },
      },
    );

    await supabase.auth.getUser();

    return response;
  } catch (e) {
    return NextResponse.next({
      request: {
        headers: request.headers,
      },
    });
  }
};

server.ts

import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export const createClient = () => {
  const cookieStore = cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          } catch (error) {
          }
        },
      },
    },
  );
};

export const getIsLogin = async () => {
  const serverClient = createClient();
  const {
    data: { session },
  } = await serverClient.auth.getSession();
  return !!session;
};

2. Providers 설정 (Github)

원하는 Provider를 선택하고 Callback URL을 복사합니다.

GitHub 설정

Client ID와 Client Secret은 GitHub의 Developer Settings에서 확인할 수 있습니다. OAuth 설정 페이지에서 Callback URL을 붙여넣고 나머지를 채웁니다.

OAuth 설정

이후 버튼에 아래와 같은 함수를 추가하면 로그인 함수 구현 완료입니다

// login/page.tsx
import { createClient } from "@/utils/supabase/server";

async function signInWithGitHub() {
  await browserClient.auth.signInWithOAuth({
    provider: "github",
    options: {
      redirectTo: window.origin + "/auth/callback",
    },
  });
}

리디렉션 설정

리디렉션 URL을 추가합니다.

// auth/callback/route.ts
import { NextResponse } from 'next/server';
import { createClient } from '@/utils/supabase/server';

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get('code');
  const next = searchParams.get('next') ?? '/';

  if (code) {
    const supabase = createClient();
    const { error } = await supabase.auth.exchangeCodeForSession(code);
    if (!error) {
      const forwardedHost = request.headers.get('x-forwarded-host');
      const isLocalEnv = process.env.NODE_ENV === 'development';
      if (isLocalEnv) {
        return NextResponse.redirect(`${origin}${next}`);
      } else if (forwardedHost) {
        return NextResponse.redirect(`https://${forwardedHost}${next}`);
      } else {
        return NextResponse.redirect(`${origin}${next}`);
      }
    }
  }

  return NextResponse.redirect(`${origin}/auth/auth-code-error`);
}

클라이언트 컴포넌트에서 세션 확인

클라이언트 컴포넌트에서 세션을 확인하려면 아래 코드를 사용합니다.

useEffect(() => {
  browserClient.auth.getSession().then(console.log);
}, []);

로그아웃

로그아웃 기능은 아래와 같이 구현 가능합니다

browserClient.auth.signOut();

로그인 후 Users에 정보가 잘 들어오는지 확인하실 수 있습니다.

Users 확인

3. CRUD 작업 작성하기

RLS 추가하기

RLS를 추가하지 않으면 정책 때문에 데이터를 보거나 쓸 수 없습니다.

SELECT: 모든 유저가 데이터를 볼 수 있도록 설정합니다 - 그대로
INSERT: 로그인한 유저만 데이터를 작성할 수 있도록 설정합니다 - 그대로

Update와 DELETE 앞서서 user_id라는 column을 추가하고 uuid로 타입을 정하고 기본값을 auth.uid()로 설정합니다.

Update부분은 그대로 사용하지 못하여 RLS를 수정하여 user_id가 일치해야 업데이트가 가능하도록 설정합니다.

RLS 수정

UPDATE: user_id가 같은 유저만 변경할 수 있도록 설정합니다 - 위처럼 변경
DELETE: user_id가 같은 유저만 데이터를 지울 수 있도록 설정합니다 - 그대로

R: 데이터 읽기

await serverClient.from("products").select();

C: 데이터 삽입

await serverClient.from("products").insert({
  title,
  desc,
});

U: 데이터 업데이트

await serverClient.from("products").update({
  title: '변경됨',
}).eq('id', 1);

D: 데이터 삭제

await serverClient.from("products").delete().eq('id', 1);

4. 이미지 업로드

버킷을 만들고 정책을 설정합니다:

업로드중..

New Policy를 눌러서 정책을 생성하고 모든 권한을 열어줍니다

Policy 설정

이미지 가져오기

// Instagram 버킷에서 logo.png 파일의 URL 가져오기
serverClient.storage.from('Instagram').getPublicUrl("logo.png");

이미지 업로드

const avatarFile = event.target.files[0];
const { data, error } = await supabase.storage.from('Instagram').upload('public/avatar1.png', avatarFile);

이상으로 Supabase 사용법에 대한 간단한 가이드를 마칩니다!

profile
derek

0개의 댓글