Edited at

AWS LambdaをiOSアプリから直接叩く

More than 3 years have passed since last update.


EC2を使わずにちょっとしたAPIを叩きたい

iOS等のモバイルアプリから叩くWebAPIはいつもEC2で実装していましたが、ちょっとしたAPIを作るにもいちいちサーバを立てなければいけないのは大変。と思っていたところLambdaがMobile SDKから叩けるようになっていたようなので、どんなものなのか試してみました。


全体像

今回登場するAWSサービスは、Amazon Cognito、Lambda、IAMです。CognitoでiOSのMobile-SDKからのアクセス権限と認証の制御を行い、直接Lambdaを叩きます。IAMはCognitoの権限登録を行う時に出てくるので一応書いています。

Lambda.png


0. 手順

iPhoneアプリからLambdaを叩くまでのセットアップは以下の流れで行います。


  1. Amazon CognitoでIdentity Poolを作成する

  2. iOSアプリから叩くLambda Functionを作成する

  3. Cognitoのアクセス権限にLambda Functionへのアクセス権を追加

  4. iOSからLambdaを叩く


1. Amazon CognitoでIdentity Poolを作成する

Cogniteは2015/06/21現在「米国東部(バージニア北部)」と「EU(アイルランド)」でのみ利用可能です。今回は「米国東部(バージニア北部)」で作成しました。

Create new identity poolをクリックします。

Identity pool nameを自由に入力し、Unauthenticated identitiesのEnable access to unauthenticated identitiesにチェックを入れます。ここにチェックを入れることによって、iOSからゲストユーザとしてアクセスできるようになります。Cognitoでは他の複数のIDプロバイダとも連携できますが、今回は使用しないのでAuthentication providers のところは何もいじらずに Create poolをクリックします。

poolid_s.png

次に作成したIdentity Poolに対応するIAM Roleをアサインします。Cognitoは認証済みのユーザと未認証のユーザで別々にアクセス権限を与えられるようになっています。今回はそれぞれCognito_TestAppAuth_RoleとCognito_TestAppUnauth_Roleという名前でロールを新規作成しています。

poolIam.png

これで一旦Identity Poolの作成は終わりです。またLambdaファンクションを登録した後に、IAM Roleを追加しに戻ってきます。


2. iOSアプリから叩くLambda Functionを作成する

Lambdaは2015/06/21現在「米国東部(バージニア北部)」と「米国西武(オレゴン)」、「EU(アイルランド)」でのみ利用可能です。今回はCognitoと同様の「米国東部(バージニア北部)」で作成しました。

Create a Lambda functionをクリックし、Lambda関数を作成します。

FunctionNameを入力します。今回は"TestFunction"としました。この名前は後でiOSから叩く時に使用するので覚えておいてください。

肝心の関数内の処理ですが、今回はテンプレートを使用しました。引数をAWS上のログに出力し、一部の変数をリターンするだけの処理を行っています。

RoleではこのLambda関数から叩けるサービスの権限設定が出来ます。例えばこのLambda関数からDynamoDBにデータを投入したい場合等は、このIAM RoleにDynamoDBへのアクセス権限を与えれば良いでしょう。今回はとりあえず"Basic execution role"でIAM Roleを新規作成しました。デフォルトでログへのアクセス権限が付与されているようです。ここでRoleを新規作成する時に別タブが開くので、ブラウザのポップアップを許可しないと作成できません。(それに気づかず30分くらいはまった)

LambdaCreate_s.png

設定できたらCreate Lambda functionをクリックします。

LambdaFunction_s.png

作成したLambda関数のFunction ARNをコピーしておきます。この後Cognitoのアクセス権限を追加する時に使用します。


3. Cognitoのアクセス権限にLambda Functionへのアクセス権を追加

ここでは1.で作成したCognitoのIdentity poolに2.で作成したLambda関数へのアクセス権限を付与します。IAMを開くと、以下のように1.で作成したRoleが確認できます。

IAM_list.png

今回はゲストユーザからLambdaを叩くために、"Cognito_TestAppUnauth_Role"にLambda関数へのアクセス権限を追加します。

Roleの詳細を開き、ロールポリシーの作成をクリックします。

RoleIam.png

Policy GeneratorでLambdaの権限を追加します。アクションには関数を叩くための"InvokeFunction"にチェックし、ARNには2.でコピーしたFunction ARNを入力します。

role.png

これでゲストユーザから2.で作成したLambda関数が叩けるようになりました。


4. iOSからLambdaを叩く

最後にiOSからLambdaを叩きます。まずAWSのSDKをiOSに組み込みます。

以下を参考にCocoaPodsでインストールすると楽でしょう。

http://docs.aws.amazon.com/mobile/sdkforios/developerguide/install-ios-sdk.html

Xcodeからプロジェクトを作成し、プロジェクトのルートディレクトリに"Podfile"を作成。


Podfile

source 'https://github.com/CocoaPods/Specs.git'

pod 'AWSCore'
pod 'AWSAutoScaling'
pod 'AWSCloudWatch'
pod 'AWSDynamoDB'
pod 'AWSEC2'
pod 'AWSElasticLoadBalancing'
pod 'AWSKinesis'
pod 'AWSLambda'
pod 'AWSMachineLearning'
pod 'AWSMobileAnalytics'
pod 'AWSS3'
pod 'AWSSES'
pod 'AWSSimpleDB'
pod 'AWSSNS'
pod 'AWSSQS'
pod 'AWSCognito'

あとはプロジェクトのルートディレクトリで以下叩けばOKです。

pod install

CocoaPodsのインストールは以下等を参考にさせていただきました。

http://qiita.com/satoken0417/items/479bcdf91cff2634ffb1

インストールが終わったら、xcworkspaceを開き、コードを追記していきます。

まずCognitoの初期化を行います。AWS Management Console上から対象のIdentity Poolを選択すればサンプルコードがコピペ出来るようになっています。とりあえずAppDelegateに貼付けて初期化してみます。

#import "AppDelegate.h"

#import <AWSCore/AWSCore.h>
#import <AWSCognito/AWSCognito.h>

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Initialize the Amazon Cognito credentials provider
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1
identityPoolId:@"us-east-1:xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;

// Override point for customization after application launch.
return YES;
}

次にLambdaを叩きたいクラスに以下をインポートします。

#import <AWSLambda/AWSLambda.h>

AWSLambdaInvokerでLambda関数を叩きます。invokeFunctionの引数に2.で作成したLambda関数のFunction Nameが対応しています。

AWSLambdaInvoker *lambdaInvoker = [AWSLambdaInvoker defaultLambdaInvoker];

NSDictionary *parameters = @{@"key1" : @"value1",
@"key2" : @"value2",
@"key3" : @"value3",
@"isError" : @NO};

[[lambdaInvoker invokeFunction:@"TestFunction" JSONObject:parameters] continueWithBlock:^id(BFTask *task) {
if (task.error) {
NSLog(@"Error: %@", task.error);
if ([task.error.domain isEqualToString:AWSLambdaInvokerErrorDomain]
&& task.error.code == AWSLambdaInvokerErrorTypeFunctionError) {
NSLog(@"Function error: %@", task.error.userInfo[AWSLambdaInvokerFunctionErrorKey]);
}
}
if (task.exception) {
NSLog(@"Exception: %@", task.exception);
}
if (task.result) {
NSLog(@"Result: %@", task.result);
}
return nil;
}];

Xcodeのログに以下が出力されれば成功です。

Result: value1


まとめ

今回はiOSアプリからLambdaを叩くまでをやりました。これだけだとまだ何も出来ていないので、引き続きLambda経由で色々なAWSサービスを叩いてみようと思います。


参考