뒤로
심은광
·
GoogleSheets를 데이터 베이스로 활용하기 (feat. nextjs)
최근에 랜딩 페이지 제작 의뢰를 받게 되었는데,
데이터를 어디에 저장하는 게 좋을까 고민하다가 GoogleSheets API를 알게 되었고 바로 적용해 봤습니다.
현재 바로 활용할 수 있는 데이터베이스 서버가 없거나,
일회성 데이터인데 테이블까지 만들어서 사용하기가 번거롭게 느껴지시는 분이 계시다면 활용해 보시는 것을 적극 추천드립니다.
적용 결과부터 보여 드리고, 간단한 사용법을 설명해 보겠습니다.
[적용결과]
1. Google Sheets API 등록하기
API 등록과 관련해서 잘 정리된 블로그 글이 있어서 아래 포스팅 참고해주시면 좋을 것 같아요 !!
2. NEXTJS API 활용하기
아래 코드는 nextjs api를 활용해서,
googleSheetAPI 권한을 인증하고, Sheet에 등록정보를 입력해 주는 간단한 api 코드입니다.
이해가 조금 어려울 수 있는 부분에는 주석을 남겨놨습니다.
import { NextApiRequest, NextApiResponse } from "next";
import { GoogleSpreadsheet } from "google-spreadsheet";
import { JWT } from "google-auth-library";
async function loadGoogleDoc() {
try {
// formattedKey: vercel에서 환경변수에 저장한 값은 \n이 \\n으로 인코딩되어 있어서 다시 디코딩해줘야함
const formattedKey = process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, "\n");
// Google Sheets API를 등록하는 과정에서 발급받은 키, 이메일을 입력해주세요.
const serviceAccountAuth = new JWT({
key: formattedKey,
email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
scopes: ["https://www.googleapis.com/auth/spreadsheets"],
});
// Google Doc의 SheetId를 입력해주세요.
const doc = new GoogleSpreadsheet(
process.env.GOOGLE_SHEET_ID || "",
serviceAccountAuth
);
await doc.loadInfo();
return doc;
} catch (error) {
console.log(error);
}
}
export default async function googleSheet(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
try {
const doc = await loadGoogleDoc();
if (!doc)
return res
.status(200)
.json({ ok: false, error: "사전등록에 실패했습니다." });
// "유저등록정보" 라는 이름의 sheet가 존재하는지 확인하고, 없다면 만들어줍니다.
let sheet = doc.sheetsByTitle["유저등록정보"];
if (!sheet) {
sheet = await doc.addSheet({
headerValues: ["email", "createdAt"],
title: "유저등록정보",
});
}
// sheet에서 모든row 정보를 가져옵니다.
const rows = await sheet.getRows();
// 이미 등록된 이메일인지 검증합니다.
const isRegistered = rows.some(
(row) => row.get("email") === req.body.email
);
if (isRegistered) {
return res
.status(200)
.json({ ok: false, error: "이미 등록된 이메일입니다." });
}
const now = new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 60 * 1000;
const koreaTimeDiff = 9 * 60 * 60 * 1000;
// sheet에 새로운 정보를 등록해줍니다.
await sheet.addRow({
email: req.body.email,
createdAt: new Date(utc + koreaTimeDiff).toLocaleString(),
});
return res.status(200).json({ ok: true });
} catch (error) {
console.log(error);
return res.status(500).json({ error: "Internal server error" });
}
}
}
위에서 작성한 api를 프론트엔드에서 활용하는 예시코드입니다.
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
try {
e.preventDefault();
if (isLoading) return;
if (email === "") return;
setIsLoading(true);
const { data } = await axios.post("/api/googleSheet", {
email: email,
});
if (data.ok) return message.success("사전등록이 완료되었습니다.");
message.error(data.error);
} catch (e) {
console.log(e);
message.error("사전등록에 실패했습니다.");
} finally {
setIsLoading(false);
}
};마치며..
데이터 저장을 위한 서버를 따로 띄우는게 굉장히 번거롭게 느껴져서 저는 google sheets api를 활용해봤습니다 !!
혹시 이것보다 더 간편하고 좋은 방법을 알고계시는 분이 있으시면 저도 알려주세요 ㅎㅎ
읽어주셔서 감사합니다 !!
프론트엔드 개발자들
그룹의 글
0
댓글
로그인 후 댓글을 남길 수 있습니다.
은광님은 대체 24시간을 얼마나 알차게 사용하시는거에요
최근에 부쩍 이것저것 하는게 많아졌네요 ㅎㅎ.. 물 들어올때 열심히 해야죠!!
최고 이십니다 은광님 :D !!
오 현세님 디스콰이엇에서 뵙게 될 줄이야.. 감사합니다!!
구글시트가 임시데이터베이스 개념으로 사용하기 좋은것 같습니다. 저희도 고객분들이 데이터베이스에 대한 비슷한 피드백을 주시기도 해서 구글시트나 Supabase, 셀렉트 자체 디비 등 여러 대안들을 설명드리고 있었는데 비슷한 경험을 하신것 같아서 반가운 글이었습니다. 은광님 경험, 글로 써주셔서 감사합니다. 잘 읽었습니다!
구글시트를 사용해보면서 이게 괜찮은 방법인가 의구심이 들기도 했었는데, 꽤나 많이 사용되고 있는 방식인 것 같아서, 안심이되네요ㅎㅎ Supabase는 처음 들어봤는데 한번 알아봐야겠어요. 감사합니다 !!
에어테이블이나 nocodb도 괜찮더라구여!
오.. 두개다 처음 들어봤는데 한번 알아봐야겠어요 ㅎㅎ 꿀팁 정말 감사합니다.
저는 405 Method Not Allowed가 뜨는데 이유가 뭘까요? ㅜㅠ