1. 소개
이 Codelab의 목표는 Cloud Storage에 CSV 파일이 업로드될 때 반응하고, 콘텐츠를 읽고, Sheets API를 사용하여 Google Sheets를 업데이트하는 Cloud 함수를 작성하는 방법을 이해하는 것입니다.

이는 그렇지 않으면 수동으로 실행해야 하는 'CSV로 가져오기' 단계를 자동화한 것으로 볼 수 있습니다. 이렇게 하면 다른 팀에서 생성한 데이터를 스프레드시트에서 사용할 수 있게 되는 즉시 분석할 수 있습니다.
구현은 다음과 같습니다.

2. 설정 및 요구사항
자습형 환경 설정
- Cloud Console에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. (Gmail 또는 G Suite 계정이 없으면 만들어야 합니다.)
모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 ID는 나중에 이 Codelab에서 PROJECT_ID라고 부릅니다.
- 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.
이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.
3. Google Sheets를 만들고 구성하고 API를 사용 설정합니다.
먼저 새 Sheets 문서를 만듭니다 (이 시트는 모든 사용자가 소유할 수 있음). 생성되면 식별자를 기억하세요. 이 식별자는 작성할 함수의 환경 변수로 사용됩니다.

GCP 콘솔에서 'API 및 서비스'와 'API 라이브러리' 섹션으로 이동하여 새로 만든 프로젝트에서 Google Sheets API를 사용 설정합니다.

'IAM 및 관리자' 섹션에서 '서비스 계정'으로 이동하여 App Engine 기본 서비스 계정의 이메일을 확인합니다. your-project-id@appspot.gserviceaccount.com 형식이어야 합니다. 물론 이 작업 전용 서비스 계정을 직접 만들 수도 있습니다.

마지막으로 '공유' 버튼을 사용하여 이 서비스 계정에 스프레드시트 수정 권한을 부여합니다.

이제 이 설정으로 Cloud 함수를 작성하고 이 서비스 계정을 사용하도록 구성할 수 있습니다. 방금 만든 이 스프레드시트 문서에 쓸 수 있습니다.
4. 스토리지 버킷 만들기
Cloud 함수가 새 CSV 파일을 모니터링할 버킷을 만들어 보겠습니다.
콘솔에서 왼쪽 메뉴를 사용하여 '스토리지'로 이동합니다. :

... 그리고 다른 모든 설정이 기본값으로 설정된 csv2sheet-POSTFIX라는 새 버킷을 만듭니다 (POSTFIX를 고유한 것으로 대체).

5. Cloud 함수 만들기
이제 특정 Cloud Storage 버킷에 파일이 업로드될 때 트리거되는 csv2sheet라는 Cloud 함수를 만들 수 있습니다. 코드는 Cloud Console의 인라인 편집기를 사용하여 비동기 함수와 함께 Node.js 8로 작성됩니다.

트리거를 'Cloud Storage'로 설정하고 버킷 이름을 이전 단계에서 만든 이름으로 조정해야 합니다.
또한 작성할 함수의 진입점을 csv2sheet로 업데이트합니다.

이제 함수 본문을 다음과 같이 변경합니다.
- Cloud Storage 및 Sheets API 사용
csv2sheet함수를async로 표시- Cloud Storage 이벤트 메타데이터에서
fileName를 가져와 새로 만들 시트의 이름을 파생시킵니다.
const {google} = require("googleapis");
const {Storage} = require("@google-cloud/storage")
exports.csv2sheet = async (data, context) => {
var fileName = data.name;
// basic check that this is a *.csv file, etc...
if (!fileName.endsWith(".csv")) {
console.log("Not a .csv file, ignoring.");
return;
}
// define name of new sheet
const sheetName = fileName.slice(0, -4);
// TODO!
};
여기에서 async를 사용하는 것은 잠시 후에 살펴보겠지만 await를 사용하기 위한 것입니다.
이 함수를 만드는 동안 사용할 수 있는 몇 가지 중요한 옵션은 다음과 같습니다 (화면 하단의 '더보기' 링크 클릭).
- 드롭다운을 사용하여 위에 설명된 서비스 계정을 선택합니다.
- 이전에 만든 시트 문서와 일치해야 하는
SPREADSHEET_ID이라는 환경 변수를 정의합니다.

마지막 설정 단계로 Cloud Storage 및 Google Sheets API를 사용할 두 종속 항목으로 사용하는 package.json 콘텐츠는 다음과 같습니다 (콘솔의 인라인 편집기 PACKAGE.JSON 탭 사용).
{
"name": "csv2sheet",
"version": "0.0.42",
"dependencies": {
"googleapis": "^51.0.0",
"@google-cloud/storage": "^5.0.1"
}
}
설명된 대로 모든 항목을 구성한 후 '만들기'를 클릭합니다. 잠시 후 함수가 생성되고 배포됩니다.
6. 인증 및 Sheets API 설정
인라인 편집기를 사용하여 Cloud 함수에 코드를 더 작성하기 전에 적절한 스토리지 및 시트 범위로 Google 클라이언트 API 생성을 차단해야 합니다 (async 함수의 일부임).
콘솔의 함수 편집기에서 '수정'을 클릭하고 csv2sheet 함수의 본문에 다음 코드를 추가합니다.
// block on auth + getting the sheets API object
const auth = await google.auth.getClient({
scopes: [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/devstorage.read_only"
]
});
여기에서 Sheets API 클라이언트를 만들 수 있습니다.
const sheetsAPI = google.sheets({version: 'v4', auth});
7. Sheets API를 사용하여 빈 시트 만들기
Sheets API 클라이언트를 사용하면 문서에 간단한 새 시트를 만들 수 있습니다. 하지만 더 진행하기 전에 어휘에 관한 간단한 참고사항을 확인하세요.
- 스프레드시트는 실제 문서이며 식별자 (위에서 설명했으며 문서 URL에 표시됨)로 참조됩니다.
- 시트는 문서의 탭 중 하나이며 이름 (탭 이름) 또는 시트 생성 시 생성된 식별자로 참조할 수 있습니다.
이를 염두에 두고 Sheets API 클라이언트를 사용하여 26개의 열과 2,000개의 행이 있는 빈 시트를 2번 위치 (일반적으로 기본 '시트1' 다음)에 만들고 첫 번째 행을 고정하는 함수를 살펴보세요 (인라인 편집기를 사용하여 함수에 추가).
function addEmptySheet(sheetsAPI, sheetName) {
return new Promise((resolve, reject) => {
const emptySheetParams = {
spreadsheetId: process.env.SPREADSHEET_ID,
resource: {
requests: [
{
addSheet: {
properties: {
title: sheetName,
index: 1,
gridProperties: {
rowCount: 2000,
columnCount: 26,
frozenRowCount: 1
}
}
}
}
]
}
};
sheetsAPI.spreadsheets.batchUpdate( emptySheetParams, function(err, response) {
if (err) {
reject("The Sheets API returned an error: " + err);
} else {
const sheetId = response.data.replies[0].addSheet.properties.sheetId;
console.log("Created empty sheet: " + sheetId);
resolve(sheetId);
}
}
);
});
}
스프레드시트 참조를 하드 코딩하는 대신 이전에 만든 SPREADSHEET_ID 환경 변수를 사용합니다.
이 특정 시트에 대한 추가 요청을 위해 sheetId를 기억해야 합니다. 또한 시트 이름은 고유해야 하며 sheetName라는 시트가 이미 있으면 만들기에 실패합니다.
Sheets API의 batchUpdate 함수는 문서와 상호작용하는 일반적인 방법이며 여기에 설명되어 있습니다.
8. 스토리지 CSV 파일에서 데이터 읽기
이제 데이터를 덤프할 위치가 있으므로 인라인 편집기에서 클라우드 함수를 추가로 개발하고 Cloud Storage API를 사용하여 방금 업로드된 파일에서 실제 데이터를 가져와 문자열에 저장해 보겠습니다.
function readCSVContent(sheetsAPI, file, sheetName) {
return new Promise((resolve, reject) => {
const storage = new Storage();
let fileContents = new Buffer('');
storage.bucket(file.bucket).file(file.name).createReadStream()
.on('error', function(err) {
reject('The Storage API returned an error: ' + err);
})
.on('data', function(chunk) {
fileContents = Buffer.concat([fileContents, chunk]);
})
.on('end', function() {
let content = fileContents.toString('utf8');
console.log("CSV content read as string : " + content );
resolve(content);
});
});
}
9. 새로 만든 시트 채우기
이제 동일한 시트 클라이언트 API와 방금 수집한 데이터를 사용하여 만든 시트를 채울 차례입니다. 이 기회에 시트의 열에 스타일을 추가해 보겠습니다 (상단 행의 글꼴 크기를 변경하고 굵게 표시).
function populateAndStyle(sheetsAPI, theData, sheetId) {
return new Promise((resolve, reject) => {
// Using 'batchUpdate' allows for multiple 'requests' to be sent in a single batch.
// Populate the sheet referenced by its ID with the data received (a CSV string)
// Style: set first row font size to 11 and to Bold. Exercise left for the reader: resize columns
const dataAndStyle = {
spreadsheetId: process.env.SPREADSHEET_ID,
resource: {
requests: [
{
pasteData: {
coordinate: {
sheetId: sheetId,
rowIndex: 0,
columnIndex: 0
},
data: theData,
delimiter: ","
}
},
{
repeatCell: {
range: {
sheetId: sheetId,
startRowIndex: 0,
endRowIndex: 1
},
cell: {
userEnteredFormat: {
textFormat: {
fontSize: 11,
bold: true
}
}
},
fields: "userEnteredFormat(textFormat)"
}
}
]
}
};
sheetsAPI.spreadsheets.batchUpdate(dataAndStyle, function(err, response) {
if (err) {
reject("The Sheets API returned an error: " + err);
} else {
console.log(sheetId + " sheet populated with " + theData.length + " rows and column style set.");
resolve();
}
});
});
}
이 코드를 이제 99% 완료된 Cloud 함수에 추가해야 합니다.
데이터와 스타일이 모두 여러 requests로 결합되어 단일 Sheets API batchUpdate 호출로 전송되는 방식을 확인하세요. 이렇게 하면 더 효율적이고 원자적인 업데이트가 가능합니다.
또한 생성한 시트의 크기와 일치하는 수정 범위를 정의합니다. 즉, 시트를 만들 때 사용된 columnCount 값인 26개 열을 초과하는 콘텐츠는 이 특정 코드로 인해 실패합니다.
모든 것이 정상적으로 진행되면 다음 작업을 할 수 있습니다.
- 업데이트된 함수를 저장합니다.
- CSV 파일을 버킷에 드롭
- 스프레드시트에 해당 데이터가 표시됩니다.
10. 모두 합쳐서 흐름 테스트하기
방금 설명한 함수 호출은 원래 csv2sheet 함수에서 연속적인 차단 호출로 이루어질 수 있습니다.
const sheetId = await addEmptySheet(sheetsAPI, sheetName);
const theData = await readCSVContent(sheetsAPI, data, sheetName);
await populateAndStyle(sheetsAPI, theData, sheetId);
전체 함수 소스 코드가 필요한 경우 여기에서 확인할 수 있습니다 (한 세트로 모두 가져오는 것이 더 쉬울 수 있음).
모든 준비가 완료되면 CSV 파일을 올바른 버킷에 업로드하기만 하면 파일의 콘텐츠가 포함된 새 시트로 스프레드시트가 업데이트됩니다. 샘플 CSV 파일이 없는 경우 다음 파일을 사용하세요.

버킷에 여러 파일을 업로드하여 어떤 일이 일어나는지 확인해 보세요.
11. 작업이 끝났습니다. 인프라를 해체할 시간
농담입니다. 철거할 인프라가 없습니다. 이 모든 작업은 서버리스로 진행되었습니다.
원하는 경우 만든 Cloud 함수와 버킷 또는 전체 프로젝트를 삭제할 수 있습니다.
12. 다음 단계
이 Codelab에서는 Cloud 함수에서 Cloud Storage 버킷에 대한 업로드를 수신하여 적절한 API를 사용하여 Google 시트를 업데이트하는 단계를 안내했습니다.
다음은 몇 가지 후속 단계입니다.
- Cloud Functions 방법 가이드 (일부 권장사항 포함)를 확인하세요.
- Cloud Functions 튜토리얼 중 하나를 살펴봅니다.
- Google Sheets API 자세히 알아보기
이 Codelab에 문제가 있는 경우 왼쪽 하단에 있는 링크를 사용하여 문제를 신고해 주세요.
의견을 보내주시면 도움이 됩니다.