Skip to content

Instantly share code, notes, and snippets.

@ds1dbx
Created December 3, 2025 16:12
Show Gist options
  • Select an option

  • Save ds1dbx/a7c6379c66e04e7204f38e5c1583bc10 to your computer and use it in GitHub Desktop.

Select an option

Save ds1dbx/a7c6379c66e04e7204f38e5c1583bc10 to your computer and use it in GitHub Desktop.
AI 카페 도우미 - 구글 앱 스크립트 코드
/*
apps_script_questions_api.gs
Google Apps Script single-file API server that reads a Google Sheet named
'질문답변' and returns the sheet data as JSON. Designed to be called by a
Vercel API proxy (or any HTTP client).
특징:
1) Vercel에서 실행되는 API 프록시 서버가 이 웹앱을 호출합니다.
2) 시트의 각 행을 { row, question, answer } 형태의 객체로 반환합니다.
3) 질문과 답변이 둘 다 비어있는(빈 행) 경우 무시합니다.
4) 에러 발생 시 에러 내용을 JSON으로 반환합니다.
5) 단일 파일로 작성되어 있으며, 아래 설명을 따라 배포하면 됩니다.
사용법 요약:
- 스프레드시트 ID를 SPREADSHEET_ID 상수에 넣으세요.
- 필요한 경우 SHEET_NAME을 변경하세요 (기본값: '질문답변').
- 배포: "새로 배포 -> 웹 앱"으로 배포하고 접근 권한은 "Anyone" (또는 적절히 설정)
- 배포된 URL을 Vercel 프록시에 연결해서 사용하세요.
예시 응답 JSON:
{
"count": 3,
"items": [
{ "row": 2, "question": "질문1", "answer": "답변1" },
...
]
}
주의:
- 이 스크립트는 서버사이드에서 호출하는 용도로 설계되어 있으므로
브라우저의 CORS 제한은 Vercel 프록시(서버)가 호출할 때 문제되지 않습니다.
*/
/**
* 설정: 여기에 스프레드시트 ID를 넣으세요.
* - 스프레드시트 URL 예: https://docs.google.com/spreadsheets/d/<<<THIS_ID>>>/edit
*/
const SPREADSHEET_ID = 'PUT_YOUR_SPREADSHEET_ID_HERE'; // <<-- 여기에 ID 넣기
const SHEET_NAME = '질문답변'; // 시트 이름이 다르면 변경
/**
* HTTP GET/POST 모두 처리합니다. (Vercel 프록시는 GET 또는 POST를 사용할 수 있으므로 둘 다 지원)
*/
function doGet(e) {
return handleRequest(e);
}
function doPost(e) {
return handleRequest(e);
}
/**
* 실제 요청 처리기
*/
function handleRequest(e) {
try {
// 스프레드시트 열기
if (!SPREADSHEET_ID || SPREADSHEET_ID.indexOf('PUT_YOUR') !== -1) {
throw new Error('SPREADSHEET_ID가 설정되지 않았습니다. 코드를 수정하여 SPREADSHEET_ID를 입력하세요.');
}
var ss = SpreadsheetApp.openById(SPREADSHEET_ID);
var sheet = ss.getSheetByName(SHEET_NAME);
if (!sheet) {
throw new Error("시트 '" + SHEET_NAME + "'을(를) 찾을 수 없습니다. 시트 이름을 확인하세요.");
}
// 전체 범위 읽기
var values = sheet.getDataRange().getValues(); // 2차원 배열
if (!values || values.length === 0) {
return jsonSuccess({ count: 0, items: [] });
}
// 헤더 존재 여부 감지: 첫 행에 '질문' 또는 'question' 같은 텍스트가 있으면 헤더로 간주
var headerRowIndex = 0;
var firstRowJoined = values[0].map(function(c){ return (c||'').toString().trim(); }).join('|');
if (/질문|question|답변|answer/i.test(firstRowJoined)) {
headerRowIndex = 1; // 데이터는 1부터 시작
}
var items = [];
for (var i = headerRowIndex; i < values.length; i++) {
var row = values[i];
// 첫 두 열을 질문/답변으로 간주. 필요하면 인덱스 조정 가능.
var question = (row[0] || '').toString().trim();
var answer = (row[1] || '').toString().trim();
// 둘 다 비어있으면 빈 행으로 간주하고 무시
if (question === '' && answer === '') {
continue;
}
items.push({
row: i + 1, // 실제 스프레드시트의 행 번호(1-indexed)
question: question,
answer: answer
});
}
return jsonSuccess({ count: items.length, items: items });
} catch (err) {
// 에러 발생 시 에러 정보를 JSON으로 반환
var errObj = {
error: true,
message: err.message || String(err),
// 스택은 배포 환경에서 민감할 수 있으니 디버깅 목적으로만 포함
stack: err.stack ? String(err.stack).split('\n').slice(0,10) : null
};
return jsonError(errObj);
}
}
/**
* 성공 응답 helper
*/
function jsonSuccess(payload) {
var out = ContentService.createTextOutput(JSON.stringify({ success: true, data: payload }));
out.setMimeType(ContentService.MimeType.JSON);
return out;
}
/**
* 에러 응답 helper (HTTP status code를 직접 설정할 수는 없으므로 JSON body로 에러를 전달)
*/
function jsonError(errObj) {
var out = ContentService.createTextOutput(JSON.stringify({ success: false, error: errObj }));
out.setMimeType(ContentService.MimeType.JSON);
return out;
}
/*
배포 가이드 (단계별)
1) 스프레드시트 ID 설정
- 스프레드시트 URL에서 ID 부분을 복사하여 SPREADSHEET_ID 상수에 붙여넣으세요.
2) 앱 스크립트 프로젝트 생성
- https://script.google.com 에서 새 프로젝트 생성
- 이 파일의 내용을 붙여넣고 저장
3) 권한 설정
- 실행 시 처음으로 SpreadsheetApp.openById를 호출하면 권한 요청이 발생합니다.
- 배포 전에 스크립트를 직접 실행하여 권한을 승인하세요(예: handleRequest를 수동으로 실행).
4) 웹 앱으로 배포
- 상단 메뉴: Deploy -> New deployment
- "Select type"에서 "Web app" 선택
- Description 입력
- "Execute as"는 보통 "Me (your-email)"로 설정
- "Who has access"는 "Anyone" 또는 프로젝트 요구사항에 맞게 설정 (Vercel에서 호출하려면 공개 접근이 더 간편)
- 배포 후 생성되는 URL(예: https://script.google.com/macros/s/XXXXX/exec)을 복사
5) Vercel 프록시 연동 예시 (Node.js)
- Vercel API 라우트에서 아래처럼 fetch로 Apps Script URL 호출
// pages/api/qa-proxy.js (Next.js API route 예시)
export default async function handler(req, res) {
try {
const appsScriptUrl = 'YOUR_DEPLOYED_WEBAPP_URL_HERE';
const r = await fetch(appsScriptUrl, { method: 'GET' });
const data = await r.json();
res.status(200).json(data);
} catch (err) {
res.status(500).json({ error: String(err) });
}
}
6) 테스트
- 브라우저나 curl로 웹앱 URL에 접속하면 JSON 응답을 확인할 수 있습니다.
- Vercel 프록시를 통해 호출하면 동일한 JSON이 반환됩니다.
추가 팁:
- 질문/답변 열의 위치가 달라지면 코드 내 row[0], row[1] 인덱스를 조정하세요.
- 입력 데이터에 메타(카테고리, 작성자 등)가 있으면 items 객체에 해당 칼럼을 추가하도록 확장하면 됩니다.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment