外部サイトから直接kintone APIを実行したい

kintoneと異なるドメインのサイト（HTMLページ）からkintone APIを直接実行してもエラーが発生して実行できません。

```lang:kintone_test.html
(function() {
	$.ajax({
		type: 'GET',
		url: 'https://subdomain.cybozu.com/k/v1/records.json?app=アプリID',
		success: function(data) {
			console.log(data);
		}
	});
})();
```

上のコードを含んだHTMLページをlocalhost上で表示すると、以下のエラーがブラウザのコンソールに出力されます。
![origin.png](https://qiita-image-store.s3.amazonaws.com/0/30557/708a9e88-d02e-6e77-8bc0-430964095b6d.png)

ブラウザにはクロスドメインでの通信を拒否する仕組みがあり、それを回避するためにはJSONPとかCORSといった方法があるのですが、kintoneはどちらも利用できないため、サーバーを用意してそこからAPIを実行する必要があります。

```
ブラウザ <-> サーバー <-(API)-> kintone
```

Amazon API GatewayにはCORSの仕組みがあるので、API Gatewayを使ってブラウザからのAPI実行を実現してみたいと思います。
構成はこんな感じ。

```
ブラウザ <-> API Gateway <-> Lambda <-(API)-> kintone
```

## Lambdaからkintoneの呼び出し

[こちら](http://qiita.com/ha_ru_ma_ki/items/7b7f96ad90f776e9967e)を参考に作ります。

今回は以下のコードでkintoneのレコードを取得してみたいと思います。

```lang:index.js
var aws = require('aws-sdk');
var request = require('request');

/* kintone用のパラメータ（変更が必要） */
var DOMAIN = 'subdomain.cybozu.com'; //kintone環境のドメイン
var APP_ID = 1;   //アプリID
var LOGIN_NAME = 'Administrator';
var PASSWORD = 'secret';

/* 変更は不要 */
var BASE_URL = "https://" + DOMAIN + '/k/v1/';
var AUTH_VALUE = new Buffer(LOGIN_NAME + ':' + PASSWORD).toString('base64');
var headers = {'X-Cybozu-Authorization': AUTH_VALUE};

exports.handler = function(event, context) {
    var body_getrecords = {
        app: APP_ID
    }
    //販売実績アプリからレコードを取得する際のヘッダー
    var options_getrecords = {
        url: BASE_URL + 'records.json',
        method: 'GET',
        headers: headers,
        'Content-Type': 'application/json',
        json: body_getrecords
    }
    //レコードを取得
    request(options_getrecords, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            //取得した結果から販売実績を取得し、レコードの数だけ合算する
            var records = body.records;
            console.log(records);
            context.done(null, records);
        }
    })
};
```

## API GatewayからLambdaの呼び出し

クラメソさんのブログが分かりやすかったので[こちら](http://dev.classmethod.jp/cloud/aws/api-gateway/)を参照。（「2.Amazon API Gateway画面へ」の辺り）

リソース名は適当（今回はkintonerecordsとした）、メソッドはGETにします。
Integration typeに「Lambda Function」を選び、先程作ったファンクションを選びます。

Testを実行して、結果が返る事を確認します。（日本語化けてる・・・）
![FireShot Screen Capture #113 - 'API Gateway' - ap-northeast-1_console_aws_amazon_com_apigateway_home_region=ap-northeast-1#_apis_8rvhf5thtg_resources_nmabpk_methods_GET.png](https://qiita-image-store.s3.amazonaws.com/0/30557/1916cb8f-193d-128b-a151-b376ecd4f7b0.png)

デプロイして発行されたエンドポイントにアクセスすると、レコードが取得できます。
（Chromeだと文字化けしまくってるけど、Firefoxだと問題無かった）
![FireShot Screen Capture #114 - '' - 8rvhf5thtg_execute-api_ap-northeast-1_amazonaws_com_prod_kintonerecords.png](https://qiita-image-store.s3.amazonaws.com/0/30557/84c449ea-ea6b-fda0-9c7b-9d938a5d76d1.png)

## CORSの設定

さぁ、HTMLから実行しよう！と思いたいところだけど、このままだとAPI Gatewayのクロスオリジンのエラーになるので、API GatewayにCORSの設定をしてあげる必要がある。
詳細は[こちら](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors.html)に書いてある。

実際の手順は[こちら](http://dev.classmethod.jp/cloud/aws/amazon-api-gateway-cors/)の方が分かりやすい。
※手元の環境では、「メソッドのCORS設定」で「Integration Response」の「Header Mappings」の設定で、「Access-Control-Allow-Origin」に対して「'*'」を設定する必要があった

[Create Method]でメソッドを追加する際、GETやPOSTだけで無く、OPTIONSも追加しましょう。
Integration typeはMock IntegrationでOK。

こんな感じになるはず。
![FireShot Screen Capture #115 - 'API Gateway' - ap-northeast-1_console_aws_amazon_com_apigateway_home_region=ap-northeast-1#_apis_8rvhf5thtg_resources_nmabpk_methods_GET.png](https://qiita-image-store.s3.amazonaws.com/0/30557/d1659782-34e1-8c0b-18cd-e523e5ebdbc0.png)
![FireShot Screen Capture #116 - 'API Gateway' - ap-northeast-1_console_aws_amazon_com_apigateway_home_region=ap-northeast-1#_apis_8rvhf5thtg_resources_nmabpk_methods_GET.png](https://qiita-image-store.s3.amazonaws.com/0/30557/2e22de07-9ba7-e53d-4a8a-aa2be597d484.png)

この状態でHTMLからエンドポイントを実行すると、kintoneのレコードが取得されている事が分かる。
（見づらいのでconsole.logをconsole.tableにしてる）
![console.png](https://qiita-image-store.s3.amazonaws.com/0/30557/7f8cf1b9-f385-4c9b-689c-92a7063528ca.png)

## 余談

このままだとURL叩くだけでレコードが見えちゃうので、API Gateway側でAPIキー認証を設定しておくと良いかもしれない。
[Amazon API GatewayでAPIキー認証を設定する](http://dev.classmethod.jp/cloud/apigateway-apikey-auth/)

~~と思って試したけど、JavaScriptからうまくAPIキーがヘッダーに乗ってくれず成功していない・・・。
JavaScript SDKを使ってもうまくいかずで原因調査中。~~

当初うまくいかなかったのは、preflightリクエスト（OPTIONSメソッド）が403 Forbiddenになっていた事が原因っぽい。
OPTIONSメソッドのAPI Key Requiredをfalseにする事で解決。
![FireShot Screen Capture #117 - 'API Gateway' - ap-northeast-1_console_aws_amazon_com_apigateway_home_region=ap-northeast-1#_apis_8rvhf5thtg_resources_nmabpk_methods_OPTIONS.png](https://qiita-image-store.s3.amazonaws.com/0/30557/4047f7d6-8286-9f63-d53b-0c8fb0771048.png)

APIキーを送信する場合のコードはこんな感じ。

```lang:kintone_test.html
(function() {
	$.ajax({
		type: 'GET',
		url: 'https://subdomain.cybozu.com/k/v1/records.json?app=アプリID',
		headers: {
			'x-api-key': 'APIキー'
		},
		success: function(data) {
			console.log(data);
		}
	});
})();
```

参考までにヘッダー情報も。（余計なヘッダーも追加されている可能性はある・・・）
**OPTIONSメソッド**
![options.png](https://qiita-image-store.s3.amazonaws.com/0/30557/c66afc1d-fb85-a077-218e-75fd743cad80.png)
（POSTメソッドを実行した際は、Access-Control-Request-Method:POSTとなる）

**GET**
![GET.png](https://qiita-image-store.s3.amazonaws.com/0/30557/ecb2317d-ab0a-4467-dbeb-bb52057ba420.png)