本連載では、Web APIの公開/構築に興味のある方向けに、Web APIの設計や実装の課題とその解決策をご紹介します。第2回の記事では、開発者に愛されるREST APIの設計について解説しました。今回は、APIのインターフェースをSwagger仕様で定義し、それをaws-apigateway-importerというツールを使ってAmazon API Gatewayにインポートする方法について説明します。
Amazon API Gatewayとは
Amazon API GatewayはAWSの提供するマネージド・サービスです。AWS Lambdaや任意のAPIを公開するためのエントリーポイントとなり、認証、スロットリング、モニタリング、バージョン管理などのWeb API公開に一般的に必要だと考えられている機能を提供しています。この記事では、APIアプリケーションを公開するためにAmazon API GatewayをHTTPプロキシとして使います。
APIを公開するために、必ずしもAmazon API Gatewayのような独立したサービスや製品が必要なわけではありません。例えば、公開するAPIがひとつだけであれば、認証機能をAPIの機能の一部として実装することもあります。しかしながら、複数のAPIを公開する場合に、個々のAPIに依存しない共通の機能をAPIゲートウェイが提供し、クライアントはAPIゲートウェイを経由し実際のAPIにアクセスするというアーキテクチャは一般的です。1

Amazon API Gatewayの設定の主要部分は、リソースのパスとメソッドの組み合わせに対する、Amazon API Gatewayの入出力(Method Request、Method Response)とバックエンドとの統合のための入出力(Integration Request、Integration Response)の定義です。
次のスクリーンショットはAWS管理コンソールのAmazon API Gatewayの設定画面です。/usersというリソースパスのGETメソッドに対して、Method Request、Method Response、Integration Request、Integration Responseを設定するようになっているのがわかるでしょう。

Swagger仕様とは
Swagger仕様は、REST APIのインターフェースを記述するための仕様です。元々は、Swagger仕様を使ったコード生成やインタラクティブなドキュメント用のツールなどと一緒にWordnik社によって開発されました。その後、SmartBear社によってメンテナンスされ、2016年1月にOpen API Initiativeに寄贈されました。2
Swagger仕様は、JSON、あるいはYAML形式をサポートしています。以下の例は、この記事で使うAPIをYAML形式で記述したものです。RESTのAPIを使ったことのある開発者であれば、ざっと目を通すだけで簡単に理解できるはずです。リソースのURLのベースとなるのはhost、schemes、basePathです。
paths以下はリソース固有のパスとサポートしているHTTPメソッドとURLのパラメータ、レスポンスのボディに含まれるデータのモデルを定義しています。$ref: ’#/definitions/Users'は、レスポンスのHTTPステータスが200の場合、このファイルの後半部分に定義されているUsersスキーマのデータを返すことを定義しています。
swagger: '2.0'
info:
  title: Sample
  description: aws-apigateway-swagger-importer用のサンプルAPI
  version: '1.0.0'
host: ec2-192-0-2-1.ap-northeast-1.compute.amazonaws.com
schemes:
  - http
basePath: /
tags:
  - name: user
    description: Users
produces:
  - application/json
paths:
  /users:
    get:
      tags:
        - user
      summary: Users
      description: ユーザのコレクションを返す
      parameters:
        - name: offset
          in: query
          description: オフセット
          type: integer
          format: int64
      responses:
        200:
          description: ユーザのコレクション
          schema:
            $ref: '#/definitions/Users'
省略
definitions:
  User:
    type: object
    properties:
      id:
        type: integer
        description: ユーザid
      name:
        type: string
        description: 名前
      email:
        type: string
        description: メールアドレス
  Metadata:
    type: object
    properties:
      total:
        type: integer
        format: int64
        description: トータル件数
      limit:
        type: integer
        format: int64
        description: リミット
      offset:
        type: integer
        format: int64
        description: オフセット
  Users:
    type: object
    properties:
      metadata:
        $ref: '#/definitions/Metadata'
      users:
        type: array
        items:
          $ref: '#/definitions/User'
省略
Swagger仕様と一緒に開発されたツールのひとつにSwagger UIがあります。Swagger UIはインタラクティブなAPIのドキュメントを生成するツールです。Swagger仕様を読み込みドキュメントを表示するだけでなく、実際にAPIを呼び出し、その結果を見ることができます。

aws-apigateway-importer とは
aws-apigateway-importerは、Amazonの開発しているOSSのコマンドラインツールです。Swagger仕様やRAMLで書かれたAPIの定義をAmazon API Gatewayにインポートすることができます。この記事ではSwaggerを使ってインポートする方法を説明します。
Amazon API Gatewayの設定はAWSマネジメントコンソールからもおこなうことができます。しかし、RESTリソースや環境が増えてくると、設定内容や手順をドキュメント化し、人手で設定するのは苦痛です。aws-apigateway-importerのようなツール3を使い、できる限り自動化すべきです。ツールを使うと、設定ファイルをバージョン管理することができるようになるのもメリットのひとつです。

aws-apigateway-importerの使いかた
概要
aws-apigateway-importerはJavaで書かれたコマンドラインツールです。この記事の内容はOS X El Capitan上で動作を確認しています。但し、ソースコードの中には起動用のシェルスクリプトとバッチファイルが含まれているので、おそらく他のUnix系のOSとWindowsでも動くと思われます。現在のところソースコードのみの提供ですので、ビルド方法を後ほど説明します。
では、ヘルプを表示させるために、–helpオプションを指定して起動用のシェルスクリプトを実行してみましょう。4
% ./aws-api-import.sh --help
Usage: aws-api-import [options] Path to API definition file to import
  Options:
    --create, -c
       Create a new API
       Default: false
    --deploy, -d
       Stage used to deploy the API (optional)
        --help
       Default: false
    --profile, -p
       AWS CLI profile to use (optional)
       Default: default
        --raml-config
       RAML file for API Gateway metadata (optional)
    --region, -r
       AWS region to use (optional)
    --test, -t
       Delete the API after import (create only)
       Default: false
    --update, -u
       API ID to import swagger into an existing API
aws-apigateway-importerがサポートしているのはAPIのインポートとアップデートの2つの操作で、それぞれ-c、-uオプションに対応しています。それ以外のオプションは必須ではありません。基本形は以下の2つです。
% ./aws-api-import.sh -c ファイル名 % ./aws-api-import.sh -u APIのid ファイル名
AWSのアクセスキー
実際にAmazon API Gatewayを操作するためにはAWSのアクセスキーが必要です。アクセスキーを持っていない場合は、Amazonのドキュメント「IAM ユーザーのアクセスキーの管理」を参照し、アクセスキーを作成してください。デフォルトのアクセスキーは、環境変数、Javaシステムプロパティ、AWS SDK/CLIの設定ファイル、インスタンスプロファイルのいずれかの方法で設定することができます。詳細は、Amazonのドキュメント「Providing AWS Credentials in the AWS SDK for Java」を参照してください。ここでは、環境変数を使います。
% export AWS_ACCESS_KEY_ID=アクセスキー % export AWS_SECRET_ACCESS_KEY=シークレットアクセスキー
Amazon API Gateway用の定義
Swagger仕様はベンダーによる拡張をサポートするために「x-」ではじまるフィールドを予約しています。aws-apigateway-importerはこの拡張仕様を使いAmazon API Gateway固有の設定を可能にしています。以下は、この記事で使う設定の一部です。x-amazon-apigateway-integration以外にも、認証定義のためにx-amazon-apigateway-authフィールドを使うことができます。
省略
paths:
  /users:
    get:
省略
      x-amazon-apigateway-integration:
        type: HTTP
        httpMethod: GET
        uri: https://ec2-192-0-2-1.ap-northeast-1.compute.amazonaws.com/users
        requestParameters:
          integration.request.querystring.offset: method.request.querystring.offset
        responses:
          200:
            statusCode: '200'
          404:
            statusCode: '404'
省略
先にも説明したように、Amazon API Gatewayの設定はリソースのパスとメソッドの組み合わせに対しておこないます。この例では、/usersというパスとGETメソッドの組み合わせです。typeはIntegration RequestのIntegration typeに、uriはEndpoint URLに相当します。次のスクリーンショットは、上の定義をインポートした時に、Integration Requestに設定された内容です。

requestParametersは、Method RequestのURL Query String ParametersとIntegration RequestのURL Query String Parametersのマッピングです。AWS管理コンソールでは2つに分かれていますが、ここではまとめて指定します。キーはintegration.request.{location}.{name}という形式で指定します。locationにはquerystring、path、headerのいずれかを使うことができます。それぞれ、URLのクエリストリング、URLのパス、HTTPヘッダーを意味しています。nameはユニークな任意のパラメータ名です。値の部分はmethod.request.{location}.{name}という形式で指定します。locationとnameはintegrationと同様です。次のスクリーンショットはMethod Requestに設定された内容です。

responsesは、Method ResponseとIntegration Responseのマッピングです。ここでは、フォーマットの変換などをおこなっていないので特別な設定はおこなっていません。ソースコードに含まれているREADME.mdによると、以下のようにレスポンスのパラメータのマッピングやテンプレートの指定ができるようです。
   "responses" : {
       "2\\d{2}" : {
           "statusCode" : "200",
           "responseParameters" : {
               "method.response.header.test-method-response-header" : "integration.response.header.integrationResponseHeaderParam1"
           },
           "responseTemplates" : {
               "application/json" : "json 200 response template",
               "application/xml" : "xml 200 response template"
           }
       },
https://github.com/awslabs/aws-apigateway-importer/blob/master/README.md
残念ながら、ステージ毎に設定するキャッシュやスロットリングなどの設定はまだサポートされていません。設定可能な内容の詳細については、AmazonのドキュメントSwagger の仕様および API Gateway 拡張を使用して API を作成するを参照してください。
APIのインポート
では、APIをインポートしてみましょう。ここでは、-rオプションを使い東京リージョンにインポートします。
% ./aws-api-import.sh -c -r ap-northeast-1 apigw.yaml 2016-02-22 15:04:17,202 INFO - Using API Gateway endpoint https://apigateway.ap-northeast-1.amazonaws.com 2016-02-22 15:04:18,617 INFO - Attempting to create API from Swagger definition. Swagger file: apigw.yaml 省略 2016-02-22 15:04:20,521 INFO - Creating method parameter for api l5yjz5pos5 and method GET with name method.request.path.id 2016-02-22 15:04:20,561 INFO - Creating integration with type HTTP 2016-02-22 15:04:21,704 INFO - Creating method for api id l5yjz5pos5 and resource id v3li7u with method get
これでインポートは完了です。
APIの更新
今度はAPIを更新してみましょう。APIの更新時には、APIのidが必要です。インポート時のログ、あるいは管理コンソールでAPIを表示している時のURLを見れば、APIのidがわかります。例えば、上のインポートの例では、APIのidはl5yjz5pos5です。
% ./aws-api-import.sh -u l5yjz5pos5 -r ap-northeast-1 apigw.yaml 2016-02-22 15:04:52,659 INFO - Using API Gateway endpoint https://apigateway.ap-northeast-1.amazonaws.com 2016-02-22 15:04:54,106 INFO - Attempting to update API from Swagger definition. API identifier: l5yjz5pos5 Swagger file: apigw.yaml 省略 2016-02-22 15:04:56,192 INFO - Creating method parameter for api l5yjz5pos5 and method GET with name method.request.path.id 2016-02-22 15:04:56,237 INFO - Creating integration with type HTTP 2016-02-22 15:04:56,385 INFO - Cleaning up removed methods 2016-02-22 15:04:56,485 INFO - Cleaning up removed resources
aws-apigateway-importerのビルド
aws-apigateway-importerはソースコードでのみ提供されているため、使う前にビルドする必要があります。ここでは、ビルド方法について説明します。
事前準備
以下のソフトウェアをインストールしておく必要があります。
- Git
- JDK 8
- Apache Maven
ビルド
GitHubからaws-apigateway-importerのリポジトリをクローンして、Mavenでビルドします。
% git clone https://github.com/awslabs/aws-apigateway-importer.git % cd aws-apigateway-importer % mvn compile assembly:single [INFO] Scanning for projects... 省略 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 20.290 s [INFO] Finished at: 2016-02-17T14:39:07+09:00 [INFO] Final Memory: 32M/202M [INFO] ------------------------------------------------------------------------
正しくビルドできたことを確認するために、ヘルプを表示させてみましょう。
% ./aws-api-import.sh Usage: aws-api-import [options] Path to API definition file to import 省略
これでビルドは完了です。
まとめ
aws-apigateway-importerを使うと、設定をバージョン管理し、人手によるオペレーションを減らすことができます。まだ、成熟しているとは言いがたいツールですが、Amazon API Gatewayを使う場合には利用を検討すべきでしょう。
脚注
- 
アーキテクチャとしてのAPIゲートウェイに興味のある方は、オブジェクトの広場の記事APIゲートウェイアーキテクチャ」を参照してください。 ↩ 
- 
Swagger仕様は、Open API Initiative の設立に伴いOpenAPI仕様と改名されました。しかしながら、aws-apigateway-importerのドキュメントではまだSwaggerとして参照されています。混乱を避けるためにこの記事では、Swaggerに統一しています。 ↩ 
- 
例えば、Serverless FrameworkやFluctは、Lambdaを使ったAPI開発、Amazon API Gateway経由でのAPI公開をサポートしています。また、TerraformはAmazon API Gatewayサポートを実装中です。 ↩ 
