Google 日历 API 使用 Apps 脚本批量插入事件

Google Calendar API batch insert events with Apps Script

使用 Google Apps 脚本的 UrlFetchApp, how can I use the Google Calendar v3 API to insert events in batches?

Google 列出 this example batch request,但我不明白如何转换它。

POST /batch/farm/v1 HTTP/1.1
Authorization: Bearer your_auth_token
Host: www.googleapis.com
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item1:12930812@barnyard.example.com>

GET /farm/v1/animals/pony

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:12930812@barnyard.example.com>

PUT /farm/v1/animals/sheep
Content-Type: application/json
Content-Length: part_content_length
If-Match: "etag/sheep"

{
  "animalName": "sheep",
  "animalAge": "5"
  "peltColor": "green",
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item3:12930812@barnyard.example.com>

GET /farm/v1/animals
If-None-Match: "etag/animals"

--batch_foobarbaz--

我相信你的目标如下。

  • 您想使用带有 Google Apps 脚本的批处理请求将多个事件插入 Google 日历。

在这种情况下,在当前阶段,需要创建请求正文,如您的问题所示。示例请求正文可在 the official document 处查看。这在你的问题中已经提到了。

创建请求体并请求后,脚本如下

示例脚本:

在您使用此脚本之前,please enable Calendar API at Advanced Google services

function myFunction() {
  const calendarId = "###";  // Please set the calendar ID.
  
  // Please set the object for inserting the calendar events. Each request body can be seen at https://developers.google.com/calendar/v3/reference/events/insert
  const events = [
    {start: {date: "2021-01-21"}, end: {date: "2021-01-21"},summary: "sample event 1"},
    {start: {date: "2021-01-22"}, end: {date: "2021-01-22"},summary: "sample event 2"}
  ];

  const boundary = "xxxxxxxxxx";
  const payload = events.reduce((s, e, i, a) => s += `Content-Type: application/http\r\n` +
    `Content-ID: ${i}\r\n\r\n` +
    `POST https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events\r\n` +
    `Content-Type: application/json; charset=utf-8\r\n\r\n` +
    `${JSON.stringify(e)}\r\n` +
    `--${boundary + (i == a.length - 1 ? "--" : "")}\r\n`
  , `--${boundary}\r\n`);
  const params = {
    method: "post",
    contentType: "multipart/mixed; boundary=" + boundary,
    payload: payload,
    headers: {Authorization: `Bearer ${ScriptApp.getOAuthToken()}`},
    muteHttpExceptions: true,
  };
  const res = UrlFetchApp.fetch("https://www.googleapis.com/batch/calendar/v3", params);
  console.log(res)

  // CalendarApp.getCalendarById();  // This is used for automatically detecting the scope of https://www.googleapis.com/auth/calendar
}
  • 在此示例脚本中,示例请求正文用于 events。所以请根据自己的实际情况修改。

注:

  • 现阶段批量请求可以运行一次API调用100个请求。所以当你使用上面的脚本请求超过100个时,请修改它。请注意这一点。

  • 在这种情况下,我认为创建请求主体时可能会有点复杂。所以我将其创建为 a Google Apps Script library。当使用这个库时,上面的脚本变成如下。在本库中,即使请求数超过100个,也可以运行通过内部库处理

      const calendarId = "###";  // Please set the calendar ID.
      const requests = {
        batchPath: "batch/calendar/v3",
        requests: [
          {
            method: "POST",
            endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`,
            requestBody: {start: {date: "2021-01-21"}, end: {date: "2021-01-21"},summary: "sample event 1"},
          },
          {
            method: "POST",
            endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`,
            requestBody: {start: {date: "2021-01-22"}, end: {date: "2021-01-22"},summary: "sample event 2"},
          }
        ]
      };
      const res = BatchRequest.EDo(requests);
      console.log(res);
    

参考文献:

我真的找不到执行批量请求的文档。

这是我对 NodeJS 的实现。这有点 Hacky 但似乎有效:

const axios = require('axios');

async function batchRequest({
  events,
  token,
  method = 'POST',
}) {
  const batchSize = 50;

  const batchCount = Math.ceil(events.length / batchSize);

  const responses = [];

  for (let b = 0; b < batchCount; b += 1) {
    const boundary = 'xxxxxxxxxx';
    const payload = events.slice(b * batchSize, (b + 1) * batchSize).reduce((s, e, i, a) => s += 'Content-Type: application/http\r\n'
      + `Content-ID: ${i}\r\n\r\n`
      + `${method} https://www.googleapis.com/calendar/v3/calendars/${e.calendarId}/events${method === 'PATCH' ? `/${e.calendarEventId}` : ''}\r\n`
      + 'Content-Type: application/json; charset=utf-8\r\n\r\n'
      + `${JSON.stringify({ ...e, calendarEventId: undefined })}\r\n`
      + `--${boundary + (i === a.length - 1 ? '--' : '')}\r\n`,
    `--${boundary}\r\n`);

    const req = {
      url: 'https://www.googleapis.com/batch/calendar/v3',
      method: 'POST',
      headers: {
        'Content-Type': `multipart/mixed; boundary=${boundary}`,
        Authorization: `Bearer ${token}`,
      },
      data: payload,
    };
    const res = await axios(req);

    res.data.split('--batch_').forEach((batch) => {
      const resp = batch.split('\r\n\r\n');
      if (resp.length > 2) {
        try {
          responses.push(JSON.parse(resp.slice(2).join('\r\n')));
        } catch (e) {
          //
        }
      }
    });
  }

  return responses;
}