問題
Google Apps Script で kintone REST API を実行する際、
GET の query が長くなるなどで下記エラーとなることがあります。
Exception: Limit Exceeded: URLFetch URL Length.
Google Apps Script では URL の長さは 2kB に制限されているようです。
https://developers.google.com/apps-script/guides/services/quotas
回避案
カーソルを用いたレコード一括取得で回避する例です。
カーソルAPIの本来の目的は、大量のレコード取得を高速に行うことだと思いますが、
https://developer.cybozu.io/hc/ja/articles/360028843531
query を POST でリクエストできることを利用しました。
https://developer.cybozu.io/hc/ja/articles/360029152012
以下は typescript(clasp)での実装例ですが
公式ドキュメントの方が分かりやすいかと思います。
KintoneApi.ts
type Method = GoogleAppsScript.URL_Fetch.HttpMethod;
type Payload = GoogleAppsScript.URL_Fetch.Payload;
type Options = GoogleAppsScript.URL_Fetch.URLFetchRequestOptions;
export default class KintoneApi {
private host = 'foo-host';
private user = {
id : '',
password: ''
};
constructor(userId: string, password: string) {
this.user.id = userId;
this.user.password = password;
}
private fetch(endpoint: string, method: Method, payload?: Payload) {
const options: Options = {
method : method,
headers : {'X-Cybozu-Authorization': Utilities.base64Encode(this.user.id + ':' + this.user.password)},
};
if (method != 'get') options.contentType = 'application/json';
if (payload) options.payload = JSON.stringify(payload);
const resp = UrlFetchApp.fetch(`https://${this.host}.cybozu.com/k/v1/${endpoint}`, options);
return JSON.parse(resp.getContentText());
}
public getByCursor<T>(appId: number, query: string, fields?: string[]): T[] {
const payload: Payload = {
app : appId,
query : query,
size : 500
};
if (fields) payload.fields = fields;
const cursor: {id: string} = this.fetch(`records/cursor.json`, 'post', payload);
try {
type CursorResp = {records: T[], next: boolean};
const ret: CursorResp = {records: [], next: true};
while (ret.next) { //GASでは非同期とならない
Utilities.sleep(1000);
const resp: CursorResp = this.fetch(`records/cursor.json?id=${cursor.id}`, 'get');
ret.records.push(...resp.records);
ret.next = resp.next;
}
return ret.records;
} catch (err) {
try {
Utilities.sleep(1000);
this.fetch(`records/cursor.json`, 'delete', {id: cursor.id});
} catch (delErr) {
// do nothing
}
throw err;
}
}
}
exec.ts
import KintoneApi from 'path/to/KintoneApi';
const kintone = new KintoneApi('fooId', 'fooPassword');
const records = kintone.getByCursor<any>(0 /* appId */, 'very long query string over 2kB...');