Reputation: 9571
Using Google Apps Script's UrlFetchApp, how can I use the Google Calendar v3 API to insert events in batches?
Google lists this example batch request, but I don't understand how exactly to convert it.
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:[email protected]>
GET /farm/v1/animals/pony
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:[email protected]>
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:[email protected]>
GET /farm/v1/animals
If-None-Match: "etag/animals"
--batch_foobarbaz--
Upvotes: 2
Views: 1759
Reputation: 474
I really couldn't find documentation to perform batch requests.
Here's my implementation for NodeJS. It's a bit Hacky but seems to work:
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;
}
Upvotes: 1
Reputation: 201358
I believe your goal as follows.
In this case, in the current stage, it is required to create the request body as shown in your question. The sample request body can be seen at the official document. This has already been mentioned in your question.
When the request body is created and request it, the script becomes as follows.
Before you use this script, 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
. So please modify it for your actual situation.In the current stage, the batch request can run the 100 requests by one API call. So when you requests more than 100 using above script, please modify it. Please be careful this.
In this case, I thought that when the request body is created, it might be a bit complicate. So I created this as a Google Apps Script library. When this library is used, above script becomes as follows. In this library, even when the number of requests is more than 100, this can be run by processing in the internal library.
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);
Upvotes: 4