15
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

株式会社サイバー・バズAdvent Calendar 2021

Day 12

GoogleAppsScript(GAS)で効率化する時になんだかんだよく使うコードスニペット10選

Last updated at Posted at 2021-12-12

この記事は株式会社サイバー・バズ Advent calendar 2021の記事です。

前置き

GASって便利ですよね。
ちょっとした業務改善に、サイバー・バズでもよく使われています。
claspを使えばTypeScriptで書けるしGitHubで管理できるので、保守性も高いです。

ただ、GASで何回も同じコードを使ってるなあと思ったので
汎用的に役に立ちそうなコード片をまとめてみることにしました。

  1. 外部APIから値取得
  2. Slackへ投稿
  3. メールの送信
  4. シートの取得または作成
  5. シートへの値追加
  6. カスタムメニューの追加
  7. トリガーの追加
  8. フォーム回答内容取得
  9. ファイルの取得
  10. プロパティの取得

1. 外部APIから値取得

おそらくGASで最も使われていてもおかしくない、UrlFetchAppでのデータ取得です。
headersはobject型、dataはany型でこのままでは使いづらいので、
好みに応じて型情報を設定して使うのが良いでしょう。

export const fetch = (url: string, accessToken: String) => {
  const res: GoogleAppsScript.URL_Fetch.HTTPResponse = UrlFetchApp.fetch(url, {
    headers: { Authorization: `Bearer ${accessToken}` }
  })
  const data = JSON.parse(res.getContentText())
  const headers = res.getHeaders()
  return {
    headers,
    data
  }
}

2. Slackへ投稿

何らかのトリガーの実行後、成功/失敗の通知などにSlackを活用することが多いです。
attachmentsも駆使することで、より綺麗で見やすいフォーマットで送信可能です。

export type SlackAttachment = {
  title: string
  title_link: string
  fields: SlackAttachmentField[]
}
export type SlackAttachmentField = {
  title: string
  value: string
  short: boolean
}
export type SlackUser = {
  username: String
  icon_url?: string
}
export const postToSlack = (params: {
  channel: string
  webhookUrl: string
  user: SlackUser
  attachments: SlackAttachment[]
}): string => {
  const res = UrlFetchApp.fetch(params.webhookUrl, {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    payload: JSON.stringify({
      channel: params.channel,
      username: params.user.username,
      icon_url: params.user.icon_url,
      attachments: params.attachments.length > 0 ? params.attachments : undefined
    })
  })
  return res.getContentText()
}

3. メールの送信

定番中の定番ですが。toやcc,bccにはカンマ区切りで好きな値を設定できます。
システムから送られるメールとして、noReply設定は重宝します。

const to = 'to1@gmail.com,to2@gmail.com'
const cc = 'cc1@gmail.com,cc2@gmail.com'
const subject = '件名件名件名件名件名件名件名'
const body = `
お世話になっております。
テストメールです。
`

GmailApp.sendEmail(to, subject, body, {
  cc,
  noReply: true
})

4. シートの取得または作成

シート名とテンプレート名を指定して新規作成、もしくは当てはまる名前のシートを取得します。

export const createSheetIfNotExists = (
  sheetName: string,
  templateName?: string
): GoogleAppsScript.Spreadsheet.Sheet => {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  const existSheet = spreadsheet.getSheetByName(sheetName)
  const sheet = existSheet
    ? existSheet
    : templateName
    ? spreadsheet.insertSheet(sheetName, { template: spreadsheet.getSheetByName(templateName) })
    : spreadsheet.insertSheet(sheetName)
  return sheet.showSheet()
}

5. シートへのデータ挿入

取得したデータをとにかくシートの末尾に一括挿入する。
APIからの取得データをrawデータとしてシートに貯めておく際に使ったりします。

export const insertRows = (sheet: GoogleAppsScript.Spreadsheet.Sheet) => (data: Object[][]) => {
  const lastIndex = sheet.getLastRow()
  const insertRange = sheet.getRange(
    lastIndex + 1,
    1,
    data.length,
    Math.max(...data.map(d => d.length))
  )
  return insertRange.setValues(data)
}

6. カスタムメニューの追加

スプレッドシートやフォーム、ドキュメントのメニューを追加したいときに使う。

export type MenuParam = { title?: string; items: MenuListItem[] }
export type MenuItemParam = { label: string; functionName: string }
export type MenuListItem = MenuParam | MenuItemParam

const isMenuItem = (value): value is MenuItemParam => 'label' in value && 'functionName' in value

export const createMemu = (
  { title = 'カスタムメニュー', items }: MenuParam,
  ui: GoogleAppsScript.Base.Ui = SpreadsheetApp.getUi()
): GoogleAppsScript.Base.Menu => {
  const menu = items.reduce((m, item) => {
    return isMenuItem(item)
      ? m.addItem(item.label, item.functionName)
      : m.addSubMenu(createMemu(item, ui))
  }, ui.createMenu(title))
  menu.addToUi()
  return menu
}

// Usage
global.onOpen = () => {
  createMemu({
    items: [
      { label: '実行する', functionName: 'myFunction1' },
      { title: 'サブメニュー', items: [{ label: '実行する', functionName: 'myFunction2' }] }
    ]
  })
}

7. トリガーの更新

特に時間ベーストリガーを自分ではない誰かの権限で設定したい時。
担当者に設定方法を案内するよりも、設定する関数を書いて、メニュー等から設定してもらいましょう。
トリガーの設定は冪等になるようにしておくと尚良いです。

export const updateTrigger = (functionName: string): GoogleAppsScript.Script.Trigger => {
  ScriptApp.getProjectTriggers()
    .filter((_) => _.getHandlerFunction() === functionName)
    .forEach((_) => ScriptApp.deleteTrigger(_))
  // トリガー設定値は要調整
  return ScriptApp.newTrigger(functionName).timeBased().everyDays(1).atHour(9).create()
}

8. フォーム回答内容取得

フォームの回答のタイミングで、フォームの回答内容を取得して何らかの処理を行う。
フォームの回答TriggerのハンドラとしてonSubmit関数を設定して使いましょう。

type FormSubmitEvent = {
  authMode: GoogleAppsScript.Script.AuthMode
  response: GoogleAppsScript.Forms.FormResponse
  source: GoogleAppsScript.Forms.Form
  triggerUid: string
}
export const onSubmit = (event: FormSubmitEvent) => {
  const sender = event.response.getRespondentEmail()
  const itemResponses = event.response.getItemResponses()
  const qAndA = itemResponses.map((r) => ({
    question: r.getItem().getTitle(),
    answer: r.getResponse().toString()
  }))
}

9. ファイルの取得

HTMLメールのテンプレート取得であったり、
指定フォルダ内の該当ファイル取得であったり

const id: string = 'idididid'

const folder = DriveApp.getFolderById(id)
const file = DriveApp.getFileById(id)

const name: string = 'namename'

const folders = DriveApp.getFoldersByName(name)
const files = DriveApp.getFilesByName(name)

10. プロパティの取得

ScriptPropertyはユーザー間で共有されつつ、GASからのみ利用可能なので使い勝手が良いです。

export const properties = (
  prop: GoogleAppsScript.Properties.Properties = PropertiesService.getScriptProperties()
) => {
  return {
    set: (key: string, value: string) => prop.setProperty(key, value),
    get: (key: string) => prop.getProperty(key),
    delete: (key: string) => prop.deleteProperty(key)
  }
}

// Usage
const prop = properties()
prop.set('EXAMPLE_KEY', 'hoge')
prop.get('EXAMPLE_KEY') // => 'hoge' 
prop.delete('EXAMPLE_KEY')

終わりに

GASの効率化のパワーは侮れません。
うまく使って、快適な業務環境を作りましょう :muscle:
初学者にも手軽に試せて、TypeScriptの練習にもなりますね!

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?