この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
好物はインフラとフロントエンドのかじわらゆたかです。
本記事はSORACOM Advent Calendar 2015の8日目です。
7日目の延長で、生成したSDKを使ってみたといった軽めのネタを考えていた、そんな時期もありました。
SDKの生成・CORSによるアクセス制御に引っかかる。
前回のNode.jsとほぼ同一になります。
リポジトリ取得・モジュール取得・自動生成
$ git clone hogehogehoge
$ npm install
$ node angularGenerate.js
soracom SDK for angular.js Generated
生成に成功すると以下のディレクトリに生成されたSDKが配置されます。
$ ls ./soracom-sdk/angularjs
soracomSdk.js
生成されたSDKをAngular側から呼んでみます。
LoginCtrl.js
function LoginCtrl($scope,SoracomSDK,$log) {
'ngInject';
// ViewModel
const vm = this;
vm.doLogin = function(){
doLogin();
};
var doLogin = function(){
var option = {};
var formData = $scope.loginForm;
var email = formData.mail.$modelValue;
var password = formData.password.$modelValue;
var soracomService = new SoracomSDK(option);
var authRequest = {
'email' : email,
'password': password,
'tokenTimeoutSeconds':0
};
var req = {};
req.auth = authRequest;
var promise = soracomService.auth(req);
promise.then(successHandler);
promise['catch'](failHandler);
};
var successHandler = function(){
$log.debug('login success');
};
var failHandler = function(){
$log.debug('login fail');
};
}
Login.html
<form class="form-signin" name="loginForm">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" name = "mail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus ng-model="login.mail">
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required ng-model="login.password">
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" ng-click="login.doLogin()">Sign in</button>
</form>
上記を動かしたところ、以下のようになりました。
フロントエンド開発でよくあるCORSによるアクセス制御で引っ掛かっています。
SORACOMのAPIが異なるドメインから呼び出される前提で作られていないため、
このようなエラーになっているものと想定できます。
アドベントカレンダーのネタがCORSによるアクセス制御でWEBブラウザ上からは呼べませんでした、
では流石にあかんと思ったので、呼べる方法を検討してみたいと思います。
要はWebブラウザからAPI直接呼ぶからエラーになるわけで、
それならば手前にサーバーを立てて呼べば良いのですが、それも芸がありません。
というわけで、API GatewayでSORACOMのAPIをラップして呼び出してみればと思い、実施してみました。
Amazon API Gatewayを用いたCORSによるアクセス制御回避
基本編
まずは、以下のエントリーを参考にラップしていきます。
Amazon API Gateway を使って AWS 以外のサービスの API をラップする | Developers.IO
その際、ResouceはラップするAPIと同一にしてください。
/auth をラップするAPIのResouceはauthとします。
また、Method同一に、Endpoint URLも対応するようにします。
以前、API GatewayCORSに対応するためには、以下の様な手順を踏む必要がありました。
Amazon API Gateway をクロスオリジンで呼び出す (CORS) | Developers.IO
11/3のAPI Gatewayの更新でCORSを有効にする機能が追加されました。
Amazon Web Services ブログ: 週刊AWS - 2015年11月2日
今回はその機能を使ってみたいと思います。
作成したResouceを選択し、EnableCORSを押下します。
その後、表示されたEnable CORS and replace existing CORS Headers を押下します。
最後の確認ダイアログもそのままYes,replace existing valuesを押下します。
上記のようにすることで、CORS対応のAPIを作ることができます。
リソースベースのルーティング
SORACOMのAPIをAPI Gatewayでラップするにあたり、
/groups/{group_id}といった形でURL内に操作対象のリソースを埋め込まれている場合、
以下のようにすることでラップすることが可能です。
- API GatewayのResouceとして、/groupsとその配下に/{group-id}を作成します。
-
GETメソッドを作成し、EndpoitURLのリソースを指定する個所を{}で囲みます。
今回の場合group-idがパラメータのため、
Endpointはhttps://api.soracom.io/v1/groups/{group-id} となります。 -
Integration Request内のURL Path ParametersでAdd pathを押下し、以下のように設定します。
Name | Mapped from |
---|---|
group-id | method.request.querystring.group-id |
HeaderへのRequestTokenの埋め込み
SORACOMのAPIを呼び出す際に、ほとんどのAPIでAPIKeyとTokenをHeaderに設定する必要があります。
SORACOM API 利用ガイド
上記のリソースベースのルーティングでラップした https://api.soracom.io/v1/groups/{group-id}
に対しても設定が必要な為、設定したいと思います。
今回の作例では、フロントからの呼び出しを容易にするため、フロントで設定するheaderはapiKeyとtokenとし、
API Gatewayの中で、soracom用のheader(X-Soracom-API-Key・X-Soracom-Token)に変換することにします。
- Method Request内にてHTTP Request Headers → Add Headerと進み、以下の項目を追加します。
Name | Mapped from |
---|---|
X-Soracom-API-Key | method.request.header.apiKey |
X-Soracom-Token | method.request.header.token |
- Integration Request内にてHTTP Headers内でAdd headerと進み、以下の項目を追加します。
Name | Mapped from |
---|---|
X-Soracom-API-Key | method.request.header.apiKey |
X-Soracom-Token | method.request.header.token |
- 最初に書いた基本編に基づき、作成したResouceをCORS対応にします。
その際今回はRequest HeaderにapiKeyとtokenが増えているので、その旨を記載する必要があります。
Enable CORSを押下後に、Access-Control-Allow-Headersの中にapiKeyとtokenを追記します。
また、自動生成したSDKがoperatoridという項目のRequestもするため、その旨も追記します。
設定が完了したら、Deploy APIを押下し、設定したAPIを使えるようにします。
実装例
生成したSDKで上記で作成したAPIを用いる際は、払いだされたAPIのURLをSDKに指定する必要があります。
ログインして、Headerに埋め込んでGroupの情報を参照するといった流れは以下になります。
LoginCtrl.js
function LoginCtrl($scope,SoracomSDK,$log) {
'ngInject';
// ViewModel
const vm = this;
var doLogin = function(){
var option = {'domain':'API Gatewayで払いだされたURL'};
var soracomService = new SoracomSDK(option);
var formData = $scope.loginForm;
var email = formData.mail.$modelValue;
var password = formData.password.$modelValue;
var authRequest = {
'email' : email,
'password': password,
'tokenTimeoutSeconds':0
};
var req = {};
req.auth = authRequest;
var promise = soracomService.auth(req);
promise.then(successHandler);
promise['catch'](failHandler);
};
var successHandler = function(result){
$log.debug('login success',result);
getGroupInfo(result);
};
var failHandler = function(){
$log.debug('login fail');
};
var getGroupInfo = function(soracomTokenObj){
var option = {'domain':'API Gatewayで払いだされたURL'};
var soracomService = new SoracomSDK(option);
soracomService.setTokenObj(soracomTokenObj);
var param = {};
param['group_id'] = '参照対象のGroup ID';
var promise = soracomService.get_group(param);
promise.then(successGetGroupHandler);
promise['catch'](failGetGroupHandler);
};
var successGetGroupHandler = function(result){
vm.result = result;
$log.debug('Get Group Info success',result);
};
var failGetGroupHandler = function(){
$log.debug('Get Group Info fail');
};
vm.doLogin = doLogin;
}
まとめ
AngularからSORACOMのAPIが簡単に呼べました、みたいなネタにするはずが、
API Gatewayを使ってSORACOM APIをラップするといった内容になってしまいました。
今回はSORACOMのAPIを対象にしましたが、
Swaggerが公開されているAPIならば同様の方法を用いることができるかと思います。