クライアント側の人間がAWS Lambdaを使ってみるまでの道のり #アドカレ2015

2015.12.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、田中孝明です

AWSモバイルアドベントカレンダー11日目の記事になります。

普段業務ではモバイル側(iOS)の実装をしているのですが、サーバー側も勉強しようということで、今回AWS Lambda + Amazon API Gatewayに挑戦してみました。

※といってもほんのちょっとです。

やること

Lambda functionをREST API化し、iOSアプリ側からアクセスした結果を表示するところまでやってみます。

今回利用するAWSのサービスは以下の通りです。

iOSアプリ側の開発環境は以下の通りです。

  • Xcode 7.1.1
  • Swift 2.1
  • CocoaPods 0.39.0
  • APIKit

Lambda functionの実装

今回はGETメソッドのみ実装してみます。

まずはサービスからLambdaを選択し、以下のようなLambda functionを実装しました。

console.log('Loading event');
 
exports.handler = function(event, context) {
    context.done(null, 
    [
        {
            id: 1,
            title: 'AAA',
            message: 'Hello Lambda 1!'
        }, 
        {
            id: 2,
            title: 'BBB',
            message: 'Hello Lambda 2!'
        }, 
        {
            id: 3,
            title: 'CCC',
            message: 'Hello Lambda 3!'
        }
    ]); 
};

Lambda

API Gatewayの設定

先ほど作成したLambda functionに対してAPI Gatewayを設定します。

api gateway

API Keyの設定

このままだとURLを知っている人なら誰でもアクセスできてしまいますのでAPI Keyを設定します。

SELECT_API_KEY

先ほど作成したAPI Gatewayと紐付けします。

api key

iOSアプリの実装

iOSアプリはUITableViewControllerを使ったシンプルなものにしました。 APIとの通信周りはAPIKitを利用しました。 インストールはCocoaPods経由で行います。

レスポンス部分に関しては以下のように実装しました。

HTTPHeaderFieldsのキー「x-api-key」にAPI Gatewayで設定したAPI Keyを記入しておきます。 レスポンスヘッダにキーが含まれていない、もしくは間違ったキーが指定されている場合はアクセスエラーが返ってくるようになります。

struct GetCardRequest: AdventCalendarRequestType {
    typealias Response = Cards<[String: AnyObject]>
    
    var method: HTTPMethod {
        return .GET
    }

    var HTTPHeaderFields: [String: String] {
        return ["x-api-key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
    }
    
    var path: String {
        return "/card"
    }
    
    func responseFromObject(object: AnyObject, URLResponse: NSHTTPURLResponse) -> Response? {
        guard let dictionaries = object as? [[String: AnyObject]] else {
            return nil
        }
        return Cards(cards: dictionaries)
    }
}

次にUIRefreshControlでpullしたときにリクエストが実行され結果が返ってくるようにします。

func refresh() {
    let request = GetListRequest()    

    Session.sendRequest(request) { result in
        switch result {
            case .Success(let cards):
                self.objects = cards.cards
                self.tableView.reloadData()
            case .Failure(let error):
                print("error: \(error)")
            }
            self.refreshControl!.endRefreshing()
        }
    }
}

取得した内容に応じてTableViewを描画するように実装します。

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return objects.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    let object = objects[indexPath.row] as Card
    cell.textLabel!.text = object.title
    cell.detailTextLabel!.text = object.message
    return cell
}

実行

それではアプリを実行してみます。 TableViewをpullしてみると...

application pull

結果に応じてTableViewが更新されました。

application

参考

まとめ

以上で簡単ではありますが、Lambda functionで実装したAPIをiOSアプリからアクセスすることが確認できました。 感想としては月並みですが「え、これだけでできるの?」ですね。

サーバーレスアーキテクチャと一言でいってもなかなか全体像が湧いてこないもありましたが、実際に手を動かして実装してみると frameworkの選定、routeの設定、デプロイの煩わしさ等が無く手軽に使えるのではないかと思っています。

今回はGETメソッドだけでしたが、そのうちPOSTメソッド、PUTメソッドも実装したいですね!

明日(12/12)は、大瀧隆太さんの AWS IoT についての記事です。よろしくお願いします!