kintone.proxyの使い方
kintone の JavaScript カスタマイズから外部の Web サービスや API にリクエストを送るには、kintone.proxy メソッドを使用します。ブラウザの Same-Origin Policy(同一オリジンポリシー)の制約を受けずに、kintone のサーバーを経由して外部 API を呼び出すことができます。
この記事では、kintone.proxy の基本的な使い方から、実践的な活用方法まで詳しく解説します。
kintone.proxy とは
通常、ブラウザ上の JavaScript から外部ドメインの API を呼び出す場合、CORS(Cross-Origin Resource Sharing)の制約を受けます。しかし、kintone.proxy を使うと、kintone のサーバーが中継役となってリクエストを送信するため、CORS の問題を回避できます。
ブラウザ → kintone サーバー(中継) → 外部 API
kintone.proxy で送信されたリクエストは、kintone のサーバーから送信されます。そのため、外部 API
側では kintone サーバーの IP アドレスからのアクセスとして処理されます。
基本的な構文
kintone.proxy(url, method, headers, body)
.then((args) => {
const [body, statusCode, headers] = args;
console.log(statusCode, body, headers);
})
.catch((error) => {
console.error(error);
});
パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
url | string | リクエスト先の URL |
method | string | HTTP メソッド(GET, POST, PUT, DELETE) |
headers | object | リクエストヘッダー |
body | string | object | リクエストボディ(GET の場合は {} を指定) |
レスポンス
kintone.proxy は Promise を返します。成功時には配列で 3 つの値を受け取ります。
| インデックス | 内容 | 説明 |
|---|---|---|
[0] | body | HTTP レスポンスボディ(文字列) |
[1] | statusCode | HTTP ステータスコード(数値) |
[2] | headers | レスポンスヘッダー(オブジェクト) |
GET リクエスト
外部 API からデータを取得する基本的な例です。
(() => {
'use strict';
/**
* 外部APIからデータを取得する
* @param { string } url - リクエスト先のURL
* @param { Object } headers - リクエストヘッダー
* @returns { Promise<any> } パース済みのレスポンスデータ
*/
const fetchFromApi = async (url, headers = {}) => {
const [body, statusCode] = await kintone.proxy(url, 'GET', headers, {});
if (statusCode !== 200) {
throw new Error(`APIリクエストが失敗しました: ${statusCode}`);
}
return JSON.parse(body);
};
kintone.events.on('app.record.index.show', async (event) => {
try {
const data = await fetchFromApi('https://api.example.com/data', {
Authorization: 'Bearer your-api-token',
});
console.log('取得したデータ:', data);
} catch (error) {
console.error('データ取得に失敗しました:', error);
}
return event;
});
})();
POST リクエスト
外部 API にデータを送信する例です。
(() => {
'use strict';
/**
* 外部APIにデータを送信する
* @param { string } url - リクエスト先のURL
* @param { Object } data - 送信するデータ
* @param { Object } headers - リクエストヘッダー
* @returns { Promise<any> } パース済みのレスポンスデータ
*/
const postToApi = async (url, data, headers = {}) => {
const requestHeaders = {
'Content-Type': 'application/json',
...headers,
};
const [body, statusCode] = await kintone.proxy(
url,
'POST',
requestHeaders,
JSON.stringify(data)
);
if (statusCode < 200 || statusCode >= 300) {
throw new Error(`APIリクエストが失敗しました: ${statusCode} - ${body}`);
}
return JSON.parse(body);
};
kintone.events.on('app.record.detail.show', async (event) => {
// ヘッダスペースにボタンを設置
const button = document.createElement('button');
button.textContent = '外部システムに送信';
button.onclick = async () => {
try {
const record = kintone.app.record.get().record;
const result = await postToApi(
'https://api.example.com/items',
{
title: record['タイトル'].value,
description: record['説明'].value,
},
{ Authorization: 'Bearer your-api-token' }
);
alert('送信が完了しました');
console.log(result);
} catch (error) {
alert('送信に失敗しました');
console.error(error);
}
};
kintone.app.record.getHeaderMenuSpaceElement().append(button);
return event;
});
})();
Content-Type による body の指定方法
kintone.proxy に渡す body の形式は、Content-Type ヘッダーの値によって異なります。
JSON 形式の場合
const headers = { 'Content-Type': 'application/json' };
const body = JSON.stringify({ key: 'value' });
kintone.proxy(url, 'POST', headers, body);
フォームデータ形式の場合
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
const body = new URLSearchParams({ key: 'value' }).toString();
kintone.proxy(url, 'POST', headers, body);
Content-Type と body の形式が一致しない場合、外部 API
側でリクエストが正しく解釈されない可能性があります。API
のドキュメントを確認して、適切な形式を使用してください。
エラーハンドリング
kintone.proxy のエラーハンドリングでは、ネットワークエラーと HTTP エラーの両方を考慮する必要があります。
/**
* kintone.proxy のラッパー関数(エラーハンドリング付き)
* @param { string } url - リクエスト先のURL
* @param { string } method - HTTPメソッド
* @param { Object } headers - リクエストヘッダー
* @param { string | Object } body - リクエストボディ
* @returns { Promise<{ body: any; statusCode: number; headers: Object }> }
*/
const safeProxy = async (url, method, headers, body) => {
try {
const [responseBody, statusCode, responseHeaders] = await kintone.proxy(
url,
method,
headers,
body
);
// HTTPステータスコードが400以上の場合はエラーとして扱う
if (statusCode >= 400) {
const errorMessage = (() => {
try {
return JSON.parse(responseBody).message || responseBody;
} catch {
return responseBody;
}
})();
throw new Error(`HTTP ${statusCode}: ${errorMessage}`);
}
return {
body: (() => {
try {
return JSON.parse(responseBody);
} catch {
return responseBody;
}
})(),
statusCode,
headers: responseHeaders,
};
} catch (error) {
// kintone.proxy 自体のエラー(ネットワークエラー等)
console.error('kintone.proxy でエラーが発生しました:', error);
throw error;
}
};
kintone.proxy は HTTP ステータスコードが 400 以上でも Promise を reject
しません。ステータスコードは正常に返されるため、自分でステータスコードを確認してエラー処理を行う必要があります。
制限事項
kintone.proxy にはいくつかの制限事項があります。
| 制限項目 | 内容 |
|---|---|
| リクエストサイズ | リクエストボディの上限は 10 MB |
| レスポンスサイズ | レスポンスボディの上限は 10 MB |
| タイムアウト | 外部 API からのレスポンスが返るまでの制限時間は 60 秒 |
| 同時リクエスト数 | 同一ドメインへの同時リクエスト数に上限あり |
| HTTPS | リクエスト先の URL は HTTPS のみ対応 |
kintone.proxy は HTTPS の URL のみサポートしています。HTTP(非暗号化)の URL
にはリクエストを送信できません。
kintone.proxy.upload
ファイルを外部サービスにアップロードする場合は、kintone.proxy.upload を使用します。
// Blobオブジェクトを作成
const blob = new Blob(['ファイルの内容'], { type: 'text/plain' });
kintone.proxy.upload(
'https://api.example.com/upload',
'POST',
{ Authorization: 'Bearer your-api-token' },
{ format: 'RAW', value: blob }
).then((args) => {
const [body, statusCode] = args;
console.log('アップロード結果:', statusCode, body);
});
実践例: 外部 API のデータを kintone レコードに反映する
外部の住所検索 API を使って、郵便番号から住所を自動入力する例です。
(() => {
'use strict';
/**
* 郵便番号から住所を検索する
* @param { string } zipCode - 郵便番号(ハイフンなし7桁)
* @returns { Promise<{ address1: string; address2: string; address3: string } | null> }
*/
const searchAddress = async (zipCode) => {
const url = `https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipCode}`;
const [body, statusCode] = await kintone.proxy(url, 'GET', {}, {});
if (statusCode !== 200) {
return null;
}
const data = JSON.parse(body);
if (!data.results || data.results.length === 0) {
return null;
}
return data.results[0];
};
// 郵便番号が変更されたら住所を自動入力
const events = [
'app.record.create.change.郵便番号',
'app.record.edit.change.郵便番号',
];
kintone.events.on(events, (event) => {
const record = event.record;
const zipCode = (record['郵便番号'].value || '').replace(/-/g, '');
if (zipCode.length !== 7) {
return event;
}
// 注意: change イベントでは async/await は使えないため、
// 住所の自動入力はボタンクリックなど別のトリガーで実装するのが確実です
return event;
});
})();
上記の例では郵便番号検索 API(zipcloud)を使用しています。change イベントでは非同期処理がサポートされていないため、実際のプロダクションコードではボタンクリックや submit イベントで住所検索を実行する設計が推奨されます。
まとめ
kintone.proxyを使うことで、CORS の制約を受けずに外部 API を呼び出せる- レスポンスは
[body, statusCode, headers]の配列で返される - HTTP ステータスコードが 400 以上でも Promise は reject されないため、自分でエラー処理を行う必要がある
- リクエストサイズ・レスポンスサイズ・タイムアウトに上限がある
- HTTPS の URL のみサポートされている
- ファイルアップロードには
kintone.proxy.uploadを使用する