Amazon API Gateway の API のクライアント SDK を生成して iOS アプリから呼び出す
API のクライアントの SDK を生成して呼び出す
Amazon API Gateway (以下 API Gateway) はマネージドな API を簡単に作成することが出来る素晴らしいサービスです。
API Gateway の機能はそれだけに留まらず、API クライアントの SDK を iOS や Android、Javascript 向けに生成する機能も持っています。これを使うと非常に簡単に API クライアントまでも実装することができます。
今回はこの機能を使って、API Gateway で作成した API のクライアントを iOS 向けに生成し、iOS アプリに組み込んで呼び出すところまでをやってみたいと思います。
API の作成
今回は OpenWeatherMap の Weather API をラップした API を作り、この API のクライアントを作ります。API の作成手順は以下のブログにまとめてありますので、こちらの手順通りに作成してください。
Model の作成
API のレスポンスをクライアントで受け取るには、API のレスポンスボディとして渡される JSON オブジェクトをパースする必要がありますが、API Gateway には Model を定義しておくことにより、その Model のクラスを各種 SDK 向けに生成する機能があります。この Model クラスも含めて、API クライアントの SDK としてまとめて生成することができます。
ということで Model を作成します。API Gateway のヘッダーのメニューの一番右側のドロップダウンから「Models」を選択します。
左側に表示されているのは Model 一覧です。デフォルトで Error
と Empty
というモデルが作成されています。ここに Weather API のレスポンスの Model を作成しましょう。「Create」をクリックします。
右側に新規作成フォームが表示されます。Model name は Model の名前を入力します。ここでは Weather
とします。Content type はレスポンスボディとして返すときのフォーマットで、レスポンスヘッダの Content-Type
になります。通常、application/json
で良いでしょう。Model description は任意項目ですので、必須ではありません。
一番大事な設定が、一番下にある Model schema です。ここには Model の定義を JSON Schema 形式で記述します。JSON Schema は、JSON のデータ構造を記述するための書式のことです。JSON のデータに含まれる値のデータ型や説明などを記述することができます。日本語では、以下の記事が詳しいです。
ということで、Model schema を用意する必要があります。といっても一から自力で記述する必要はありません。以下のツールを使うと、実際の JSON データから JSON Schema を生成することができます。
左上の JSON に実際の JSON データを入れて「Generate Schema」をクリックすると右側に JSON Schema が生成されます。Force required がデフォルトで有効になっていますが、今回の Model 作成には不要なので無効にしておきます。
OpenWeatherMap の Weather API の実際のレスポンスボディは以下の様な感じです。これをインプットとして JSON Schema を生成します。
{ "coord": { "lon": 139.69, "lat": 35.69 }, "weather": [ { "id": 800, "main": "Clear", "description": "Sky is Clear", "icon": "01n" } ], "base": "cmc stations", "main": { "temp": 298.43, "pressure": 1011, "humidity": 83, "temp_min": 294.82, "temp_max": 300.93 }, "wind": { "speed": 5.7, "deg": 190 }, "clouds": { "all": 0 }, "dt": 1436613100, "sys": { "type": 1, "id": 7619, "message": 0.0048, "country": "JP", "sunrise": 1436556845, "sunset": 1436608744 }, "id": 1850147, "name": "Tokyo", "cod": 200 }
JSON Schema に変換すると、以下のようになりました。ちょっと長くなってしまってすみません…。
{ "$schema": "http://json-schema.org/draft-04/schema#", "id": "/", "type": "object", "properties": { "coord": { "id": "coord", "type": "object", "properties": { "lon": { "id": "lon", "type": "number" }, "lat": { "id": "lat", "type": "number" } } }, "weather": { "id": "weather", "type": "array", "items": { "id": "0", "type": "object", "properties": { "id": { "id": "id", "type": "integer" }, "main": { "id": "main", "type": "string" }, "description": { "id": "description", "type": "string" }, "icon": { "id": "icon", "type": "string" } } } }, "base": { "id": "base", "type": "string" }, "main": { "id": "main", "type": "object", "properties": { "temp": { "id": "temp", "type": "number" }, "pressure": { "id": "pressure", "type": "integer" }, "humidity": { "id": "humidity", "type": "integer" }, "temp_min": { "id": "temp_min", "type": "number" }, "temp_max": { "id": "temp_max", "type": "number" } } }, "visibility": { "id": "visibility", "type": "integer" }, "wind": { "id": "wind", "type": "object", "properties": { "speed": { "id": "speed", "type": "number" }, "deg": { "id": "deg", "type": "integer" } } }, "clouds": { "id": "clouds", "type": "object", "properties": { "all": { "id": "all", "type": "integer" } } }, "dt": { "id": "dt", "type": "integer" }, "sys": { "id": "sys", "type": "object", "properties": { "type": { "id": "type", "type": "integer" }, "id": { "id": "id", "type": "integer" }, "message": { "id": "message", "type": "number" }, "country": { "id": "country", "type": "string" }, "sunrise": { "id": "sunrise", "type": "integer" }, "sunset": { "id": "sunset", "type": "integer" } } }, "id": { "id": "id", "type": "integer" }, "name": { "id": "name", "type": "string" }, "cod": { "id": "cod", "type": "integer" } } }
API Gateway の設定画面に戻り、Model schema に貼り付けて「Create model」をクリックして終わりです。
Method Response の設定
Model が出来上がったら、レスポンスに設定します。Method Execution 画面に移動して Method Response をクリックします。
HTTP Status に 200
が表示されているので、これを展開すると Response Models for 200 セクションの中に一つだけ Model が設定されていると思います。デフォルトでは Empty
が設定されているので、これを Weather
に変更します。最後にチェックマークをクリックして終わりです。
Method Response の設定が終わったら、デプロイを行います。「Deploy API」をクリックします。Method Execution から選ぶとデプロイできないバグがあるので、Resource 一覧 または Method 一覧から行ってください(分かりやすいバグなので、きっと近いうちに直ると思います)。
SDK の生成
デプロイが終わったらいよいよ SDK を生成します。デプロイが完了すると Stage の 設定画面が表示されていると思いますので、SDK Generation タブをクリックします。
Platform は iOS、Android、JavaScript から選べます。今回は iOS を選択します。Prefix に設定した文字列は、生成する各クラスの Prefix になります。今回は CLI
としました。
ここまでできたら「Generate SDK」をクリックし、Zip ファイルをダウンロードします。
Xcode プロジェクトへの組み込み
次に、生成した SDK を Xcode プロジェクトに組み込みましょう。なお、Xcode プロジェクトは作成済みの前提で進めさせていただきますので、作成しておいてください。
まず Xcode プロジェクトに API Gateway の SDK である AWSAPIGateway
を CocoaPods 経由でインストールしておきましょう。
pod 'AWSAPIGateway'
$ pod install Analyzing dependencies Downloading dependencies Installing AWSAPIGateway (2.2.1) Installing AWSCore (2.2.1) Generating Pods project Integrating client project
次に、生成したファイルを組み込みましょう。ダウンロードした Zip ファイルを解凍すると次のようなフォルダ構成になっています。
この中の「generated-src」フォルダに、Client クラスと Model クラスのヘッダファイルとソースファイルが入っているのですべてドラッグアンドドロップで Xcode プロジェクトに追加します。
ここで、生成したクラスを軽く覗いてみましょう。Model のルートにあたる CLIWeather
クラスは以下のような感じです。iOS では JSON オブジェクトのマッピングに Mantle が利用されています。
#import <Foundation/Foundation.h> #import <AWSCore/AWSCore.h> #import "CLIWeather_coord.h" #import "CLIWeather_main.h" #import "CLIWeather_sys.h" #import "CLIWeather_wind.h" #import "CLIWeather_weather_item.h" #import "CLIWeather_clouds.h" @interface CLIWeather : AWSModel @property (nonatomic, strong) CLIWeather_coord *coord; @property (nonatomic, strong) NSArray *weather; @property (nonatomic, strong) NSString *base; @property (nonatomic, strong) CLIWeather_main *main; @property (nonatomic, strong) NSNumber *visibility; @property (nonatomic, strong) CLIWeather_wind *wind; @property (nonatomic, strong) CLIWeather_clouds *clouds; @property (nonatomic, strong) NSNumber *dt; @property (nonatomic, strong) CLIWeather_sys *sys; @property (nonatomic, strong) NSNumber *_id; @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSNumber *cod; @end
#import "CLIWeather.h" @implementation CLIWeather + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"coord": @"coord", @"weather": @"weather", @"base": @"base", @"main": @"main", @"visibility": @"visibility", @"wind": @"wind", @"clouds": @"clouds", @"dt": @"dt", @"sys": @"sys", @"_id": @"id", @"name": @"name", @"cod": @"cod" }; } + (NSValueTransformer *)weatherJSONTransformer { return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[CLIWeather_weather_item class]]; } @end
API を呼び出してみる
それでは呼び出してみましょう。API 呼び出すには CLIWeatherAPIClient
クラスを使います(API のクライアントのクラスは XXXAPIClient
という形式になります)。weatherGet
というメソッドが用意されているので、このメソッドをコールします。Bolts を利用した非同期処理で実装されている (BFTask
は AWSTask
になっています) ので、weatherGet
の戻り値は AWSTask
オブジェクトになります。continueWithExecutor:withBlock:
を呼び出すとコールバックを受け取れます。
#import "ViewController.h" #import "CLIWeatherAPIClient.h" @interface ViewController () @end @implementation ViewController - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; CLIWeatherAPIClient *client = [CLIWeatherAPIClient defaultClient]; [[client weatherGet:@"London"] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) { if (task.error) { NSLog(@"Error: %@", task.error); } else if (task.exception) { NSLog(@"Exception: %@", task.exception); } else { CLIWeather *weather = task.result; CLIWeather_weather_item *item = weather.weather.firstObject; NSString *message = [NSString stringWithFormat:@"Weather: %@", item.main]; [[[UIAlertView alloc] initWithTitle:@"Get response" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Close", nil] show]; } return nil; }]; } @end
実行してみましょう。レスポンスを受け取ることができました!
まとめ
生成された SDK の使いかたは、AWS Mobile SDK とほぼ変わらないので、触れたことがあるかたは使いやすいものとなっています。API Gateway で作られる API は AWS の特別なものではないので、HTTP クライアントに別なライブラリ (AFNetworking とか) を使用している場合は SDK の生成機能を必ずしも使う必要はありません。
なお、今回は Public な API として設定しましたが、この方法以外に API キーを利用する方法や IAM を利用する方法などもあります。これらの利用方法は別途ご紹介できればと思います。