ボクココ

個人開発に関するテックブログ

Amazon API Gateway Importer を使って Rails x Grape から API を生成する

ども、@kimihom です。割とマニアックな記事。

以前書いた Grape Swagger で Amazon API Gateway 連携 の記事では、 grape-swagger から Amazon API Gateway に乗せるまでの手順を書いた。

しかし、このままだと 結局 Amazon API Gateway 側で Integration Request, Integration Response を1つずつ定義しなければならず、開発中にAPIが変わるたびにデプロイするのが大変だった。そこで、今回は Amazon API Gateway Importer の中にある機能をフル活用して、API Gateway 側でほとんど設定することなしにデプロイできる環境を作ろうと思う。

前準備

さて、API Gateway 側の Integaration~ 系の設定方法のサンプルはaws-apigateway-importer/tst/resources/swagger/apigateway.jsonにある。これを参考にして設定していこう。

すでに ruby-swagger を使って、doc/swagger/swagger.json にファイルがある前提だ。

このswagger.json をプログラムで読み直して、API Gateway 情報を付与した新しい swagger.json を作ろう。そうすれば、API Gateway の Web コンソール上での設定はほとんどしなくて済むようになる。 lib/tasksの rake ファイルでタスクをちょろっと追加してJSONをいじるサンプルが書く。

desc 'Swagger ドキュメントに AWS 関連情報を付加'
namespace :swagger do
  task :compile_aws_doc => :environment do

    json_file_path = 'doc/swagger/swagger.json'

    json_data = open(json_file_path) do |io|
      JSON.load(io)
    end
    json_data['paths'].each do |path, methods|
      methods.each do |method, content|
        #header settings
        # response settings
        %w{200 201 400 401 403 404 500}.each do |rc|
          next unless content['responses'][rc]
          content['responses'][rc]['headers'] = {}
          content['responses'][rc]['headers']['Access-Control-Allow-Origin'] = {}
          content['responses'][rc]['headers']['Access-Control-Allow-Origin']['type'] = 'string'
        end
        # API Gateway settings
        content['x-amazon-apigateway-integration'] = {}
        content['x-amazon-apigateway-integration']['type'] = 'http'
        content['x-amazon-apigateway-integration']['uri'] = "https://#{host}/#{json_data['info']['version']}#{path}"
        content['x-amazon-apigateway-integration']['httpMethod'] = method.upcase
        content['x-amazon-apigateway-integration']['responses'] = {}
        #...
      end
    end

    open(json_file_path, 'w') do |io|
      JSON.dump(json_data, io)
    end
  end
end

これはもうサンプルを見ながらだらだらと書いていけばいいだけだ。残りは省略するが、適宜 Amazon API Gateway 内で設定が必要な項目を書いていけばOK。基本的にWeb 上で設定する情報は全てコード化することができる。

作成した rake タスクを実行すれば、 Amazon API Gateway で設定する情報を付与した swagger.json ファイルが出来上がる。これを例の Amazon API Gateway Importer を使って API Gateway にインポートしよう。

CORS の設定

Swagger UI Rails を使っていると、API Gateway 連携したAPIとやりとりしてサンプルを動かしたくなる。ここで Swagger UI は Ajax を使っているので、基本的には同じドメインのパスからでしかAjaxで取得することはできない。しかしCORSをしっかりと設定してあげれば、Amazon API Gateway に移した URL も Ajax で操作することができるようになる。

CORSを設定するにはどうしても Web 上で設定する必要があった。Resources の左のツリーのメソッドではなくリソースをクリックすると、Enable CORS というボタンが上部に出現する。これをクリックして、 OPTIONリクエストを生成する。するとエラーになる。んで、OPTIONリクエストのMethod Response に 200 を追加してあげて(面倒...) から再度 CORSを設定すると、腫れてAPI Gateway の CORS 設定が完了となる。

ちなみに全てのレスポンスステータスのCORSを有効にするには、各Method Resopnse のResponse HeadersにAccess-Control-Allow-Originを追加し、さらにIntegration Response の Header Mappings の Access-Control-Allow-Origin に '*' を設定してあげる必要がある。いうまでもなく、これら全てをWeb上で設定すると日が暮れてしまうので、これも先ほどの rake タスクで自動で入力された状態になるよう、swagger.json を作ってからインポートさせよう。

CORS を設定すると嬉しい事

CORS を設定してあげると、先ほどの Swagger UI にある Try it! を API Gateway で生成した URL に対して行う事ができるようになる。もちろん、どんなWebサイト上からでも Ajax で通信が可能になる事を意味する。

さらに、 Amazon API Gateway で生成した JavaScript SDK も同時に利用する事ができるようになる。ちょっとだけいじってみたが、割と簡単に API から情報を取ってこれた。

<html>
  <head>
    <script type="text/javascript" src="lib/axios/dist/axios.standalone.js"></script>
    <script type="text/javascript" src="lib/CryptoJS/rollups/hmac-sha256.js"></script>
    <script type="text/javascript" src="lib/CryptoJS/rollups/sha256.js"></script>
    <script type="text/javascript" src="lib/CryptoJS/components/hmac.js"></script>
    <script type="text/javascript" src="lib/CryptoJS/components/enc-base64.js"></script>
    <script type="text/javascript" src="lib/moment/moment.js"></script>
    <script type="text/javascript" src="lib/url-template/url-template.js"></script>
    <script type="text/javascript" src="lib/apiGatewayCore/sigV4Client.js"></script>
    <script type="text/javascript" src="lib/apiGatewayCore/apiGatewayClient.js"></script>
    <script type="text/javascript" src="lib/apiGatewayCore/simpleHttpClient.js"></script>
    <script type="text/javascript" src="lib/apiGatewayCore/utils.js"></script>
    <script type="text/javascript" src="apigClient.js"></script>

<script>

var apigClient = apigClientFactory.newClient();
var params = {
  'X-API-Token': 'your token',
  'per_page': 50,
  'page': 1
};
var body = { };
var additionalParams = {  };
apigClient.contactsGet(params, body, additionalParams)
    .then(function(result){
        console.log(result);
    }).catch( function(result){
        console.log(result);
    });
</script>
</head>
<body>
    Hello.
</body>
</html>

script タグ多すぎぃ って感じだが、実際のJSはほんの数行で JSON でデータを取ってこれる。まぁこれは jQueryなり何なりでせっせと書いてもいいけども。

同様に iOS, Android SDK も生成してくれるので、これらを利用して連携するアプリが簡単に実装できそうだ。

所感

自分で作った API を Amazon API Gateway に乗せるのはそれなりに苦労があるけども、それをやることで得られるメリット(SDK生成、アクセス解析、キャッシュなど) があるので、頑張って設定する価値はあると思う。

API Gateway で最も問題になるのは、Web上での設定のめんどくささである。 これを Amazon API Gateway Importer を利用して各 API を自動で設定できるよう、ちゃんとした Swagger JSON を書いていこう。