01. BaaS
BaaS란
Backend as a System
웹과 모바일 앱 개발을 쉽고 빠르게 할 수 있게 도와주는 클라우드 기반 백엔드 서비스
BaaS를 이용하면 프론트엔드 개발에 더 집중 가능
웹 애플리케이션의 필수 구성요소 3가지
- 프론트엔드 : 사용자가 보고 상호작용하는 면, 웹 사이트의 모든 시각적 요소를 담당
- 백엔드 : 서버 측에서 데이터 처리, 사용자 관리, 로직 처리 등을 맡음, 보이지 않는 곳에서 많은 일
- 데이터베이스 : 사용자 정보, 게시글 등 모든 데이터를 저장하고 필요할 때 불러오는 저장소
BaaS의 필요성 : 프론드엔드 개발에만 집중가능
BaaS의 예시 : Firebase, Parse, AWS Amplify, Supabase ..
BaaS 장단점
장점
- 개발 속도 향상 : BaaS를 쓰면 백엔드를 직접 만들 필요없음
이미 준비된 기능들을 바로 사용할 수 있으니, 개발 시간을 크게 단축
- 유지보수 간편 : 서버 운영이나 백엔드 시스템 관리에 대한 걱정이 줄어들어, 유지보수가 훨씬 편함
- 자동 확장 : 사용자가 늘어나도 서비스가 자동으로 스케일 업 => 서버 부하 걱정 없이 안정적인 서비스를 제공
단점
- 유연성 부족 : 표준화된 기능 외의 특별한 요구사항을 충족시키기 어려울 수 있음
- 비용 예측 어려움 : 사용량이 많아질수록 비용도 늘어남
- 플랫폼 의존성 : 한 플랫폼에 의존하게 되면 나중에 다른 서비스로 이전하기 어려워질 수 있음
02. Supabase
Supabase란
Supabase는 PostgreSQL을 기반으로 하는 오픈 소스 BaaS 플랫폼
관계형(SQL) 데이터베이스를 사용
실시간으로 데이터 변화를 감지하고 반응
=> 데이터베이스가 업데이트가 필요할 때마다 UI가 자동으로 반응해서 변경사항을 보여줌
Supabase 필요성 (firebase와 비교)
관계형 데이터 모델과 실무적인 역량
실무에서는 데이터의 일관성과 정확성이 매우 중요 => 많은 기업에서 관계형 데이터베이스 사용
관계형 데이터베이스에서 데이터를 저장하는 방법은 엑셀과 매우 흡사
실시간 기능의 실무적 적용
Firebase도 실시간 데이터베이스 기능을 제공, Supabase는 이 기능을 관계형 데이터베이스의 장점과 결합하여 제공
실시간 데이터 처리가 중요한 주식 거래 플랫폼, 실시간 대시보드, 협업 도구 등에 유용
확장성, 보안, 오픈소스 커뮤니티 등의 장점
React에서 사용
설치 및 세팅
설치
터미널
yarn add @supabase/supabase-js
Supabase 클라이언트 초기화 코드 작성
1. 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
2. 로그인 후 Start your project에 들어가 new project 생성
3. Table Editor에서 new table 생성
4. 열을 필요한 만큼 추가 후 데이터 명과 타입을 지정 후 저장
5. 코드로 돌아와 src 폴더에 supabaseClient.js 파일 생성 후 API 키와 URL로 데이터베이스 연결
supabaseClient.js
import { createClient } from "@supabase/supabase-js";
const SUPABASE_PROJECT_URL = "YOUR_SUPABASE_URL"; // supabase URL
const SUPABASE_ANON_KEY = "YOUR_SUPABASE_KEY"; // supabase API KEY
const supabase = createClient(SUPABASE_PROJECT_URL, SUPABASE_ANON_KEY);
export default supabase;
6. 데이터베이스 읽기
supabase데이터베이스에 만들어뒀던 테이블에 row를 inset해 데이터 추가
데이터베이스에서 데이터를 읽어올 FetchData 컴포넌트 생성 및 코드 작성
FetchData.jsx
import React, { useEffect } from 'react'
import supabase from '../supabaseClient'
const FetchData = () => {
// 데이터베이스를 읽어오는 역할
// 컴포넌트가 mount된 후에 어떤 동작을 수행 => useEffect 및 의존성 배열을 빈 배열
// 비동기 작업이므로 async - await 사용
useEffect(() => {
const fetchData = async () => {
const { data, error } = await supabase.from("NBCAMP_SAMPLE").select("*");
if (error) {
console.log("error => ", error);
} else {
console.log("data => ", data);
}
};
fetchData();
}, [])
return (
<div>FetchData</div>
)
}
export default FetchData
App.jsx에 연결하고 데이터를 잘 가져오는지 콘솔창 확인
데이터를 잘 가져오는 것을 확인 가능
가져온 데이터를 화면에 나타내기
FetchData.jsx
import React, { useEffect, useState } from 'react'
import supabase from '../supabaseClient'
const FetchData = () => {
// 컴포넌트를 뿌려주기 위해 state
const [users, setUsers] = useState([]);
// 데이터베이스를 읽어오는 역할
// 컴포넌트가 mount된 후에 어떤 동작을 수행 => useEffect 및 의존성 배열을 빈 배열
// 비동기 작업이므로 async - await 사용
useEffect(() => {
const fetchData = async () => {
const { data, error } = await supabase.from("NBCAMP_SAMPLE").select("*");
if (error) {
console.log("error => ", error);
} else {
console.log("data => ", data);
setUsers(data); // user 안에 DB로부터 받아온 값을 저장
}
};
fetchData();
}, [])
return (
<div>
<h3>유저정보</h3>
{
users.map(user => {
return (
<div key={user.id}>
<h5>{user.name}</h5>
<h5>{user.age}</h5>
<h5>{user.address}</h5>
</div>
);
})
}
</div>
)
}
export default FetchData
supabase의 테이블에 새로운 값을 추가해보고 화면에 나오는지 확인
DB에 데이터를 추가하니 화면에 잘 나타나는 것을 확인 가능
7. 코드상에서 데이터 추가하기
데이터를 추가하는 로직을 가진 AddData 컴포넌트 생성 및 코드 작성
AddData 컴포넌트에서는 이름, 나이, 주소를 가진 데이터가 입력되어야 함
AddData.jsx
import React, { useState } from 'react'
import supabase from '../supabaseClient';
const AddData = () => {
// 이름, 나이, 주소 3개의 state 필요
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [address, setAddress] = useState("");
// 데이터를 추가하는 로직
// 가져오는 것은 select, 데이터를 추가하는 것은 insert
// 이름, 나이, 주소를 가진 객체형태로 DB에 추가
const handleAdd = async () => {
const { data, error } = await supabase.from("NBCAMP_SAMPLE").insert({
name,
age,
address,
});
if (error) {
console.log("error => ", error);
} else {
alert("데이터가 정삭적으로 입력됐습니다.");
console.log("data => ", data);
}
};
return (
<div>
<h2>데이터 추가 로직</h2>
<div>
이름 : <input type='text' value={name} onChange={(e) => {
setName(e.target.value);
}} />
</div>
<div>
나이 : <input type='text' value={age} onChange={(e) => {
setAge(e.target.value);
}} />
</div>
<div>
주소 : <input type='text' value={address} onChange={(e) => {
setAddress(e.target.value);
}} />
</div>
<button onClick={handleAdd}>등록</button>
</div>
)
}
export default AddData
DB에 데이터를 추가하고 추가한 데이터가 화면에 잘 나타나는지 확인
인풋에 값을 입력하고 등록버튼을 누르면 DB에 추가되고 새로고침하면 화면에 잘 나타나는 것을 확인 가능
8. 데이터 수정하기
UpdateData 컴포넌트 생성
UpdateData에서는 id를 입력받아서 해당되는 데이터의 주소를 바꿔줄 것
(FetchData 컴포넌트에서 id도 화면에 나타나도록 코드 수정)
UpdateData 컴포넌트에서는 어떤 id에 대한 값을 수정할지, 그 주소는 어떻게 바뀔지를 input으로 받을 것
UpdateData.jsx
import React, { useState } from 'react'
import supabase from '../supabaseClient';
const UpdateData = () => {
// id와 주소를 state로
const [targetId, setTargetId] = useState(0);
const [address, setAddress] = useState("");
// 데이터 수정 로직
// 데이터 수정은 update
const handleChange = async () => {
const { error } = await supabase.from("NBCAMP_SAMPLE").update({
address,
}).eq('id', targetId); // id가 targetId랑 동일한 것을 update
if (error) {
console.log("error => ", error);
}
}
return (
<div style={{
border: "1px solid blue",
}}>
<h2>데이터 수정 로직</h2>
아이디: <input type='number' value={targetId} onChange={(e) => {
setTargetId(e.target.value);
}} />
<br />
수정주소: <input type='text' value={address} onChange={(e) => {
setAddress(e.target.value);
}} />
<button onClick={handleChange}>수정</button>
</div>
)
}
export default UpdateData
App.jsx에 연결한 후 id와 수정할 주소를 입력하고 버튼을 누르면 해당하는 id의 주소가 변경되는지 확인
id와 수정주소를 입력하고 버튼을 누른 후 새로고침하면 해당하는 id의 주소가 잘 변경되는 것을 확인 가능
9. 데이터 삭제하기
데이터를 삭제하는 컴포넌트 DeleteData를 생성
DeleteData 컴포넌트는 UpdateData 컴포넌트와 유사
id를 입력받아 해당하는 id의 정보를 DB에서 삭제
DeleteData.jsx
import React, { useState } from 'react'
import supabase from '../supabaseClient';
const DeleteData = () => {
// 데이터 삭제는 수정과 비슷하므로 수정 로직을 복사 후 필요한 부분 수정
const [targetId, setTargetId] = useState(0);
// 데이터 삭제 로직
// 데이터 삭제는 delete
const handleDelete = async () => {
const { error } = await supabase
.from("NBCAMP_SAMPLE")
.delete()
.eq('id', targetId); // id가 targetId랑 동일한 것을 delete
if (error) {
console.log("error => ", error);
}
else {
alert("삭제가 완료되었습니다.");
}
}
return (
<div style={{
border: "1px solid blue",
}}>
<h2>데이터 삭제 로직</h2>
아이디: <input type='number' value={targetId} onChange={(e) => {
setTargetId(e.target.value);
}} />
<button onClick={handleDelete}>삭제</button>
</div>
)
}
export default DeleteData
삭제하려는 데이터의 id를 input에 입력하고 삭제 버튼을 눌렀을 때, 해당하는 id의 데이터가 삭제되는지 확인
2를 입력하고 삭제버튼을 눌렀을 때
id가 2인 데이터가 DB에서 삭제되고 새로고침했을 때 화면에서 제거되는 것을 확인가능