Amazon API Gatewayをブラウザから呼んでみた

2015.07.13

はじめに

好物はインフラとフロントエンドのかじわらゆたかです。

Amazon API Gatewayのノウハウがいろいろ出ているので、 ブラウザから動かして見ようと思います。

流れとしてはAWS Lambdaで、S3 Pre-Signed URLの生成を実装し、 それをAmazon API Gatewayにデプロイします。

その後、ブラウザからデプロイされたAPIを実行し、 生成されたS3 Pre-Signed URLからアップロードされた画像を取得するといった形になります。

Pre-Signed URLの生成

AWS SDKを用いて、Presigned-URLを発行します。 AWS Gateway自体はTokyoリージョンには来ていませんが、 取得するS3のオブジェクトはTokyoリージョンから取得するといったケースで実装してみます。

app.js

'use strict';
var AWS = require('aws-sdk');
var bucket = 'cm-kajiwara-image';
var region = 'ap-northeast-1';
var s3 = new AWS.S3({
'region': region
});
var key = 'classmethod-icatch.png';
var params = {
Bucket: bucket,
Key: key,
Expires: 60
};
exports.handler = function(event, context) {
s3.getSignedUrl('getObject', params, function(err, url) {
if(!err){
context.done(null,url);
}
});
};

以前紹介したAWS Lambda Functionをローカルで動かすdriver.jsを用い、 問題なく動くことを確認します。

$ node ./driver.js
https://cm-kajiwara-image.s3-ap-northeast-1.amazonaws.com/classmethod-icatch.png AWS Access Key)&Expires=1436681110&Signature=(generated Signature)

今回Lambdaパッケージを作成するに辺り、 以下のページのサンプルプロジェクトを使いました。 AWS Lambdaの関数をnpmでパッケージ管理 - Qiita

このプロジェクトを用いることで、npmからAWS Lambda用のパッケージを作成・デプロイまで行うことが可能です。 上記のパッケージを使う際にハマった点を共有しておきます。

Scriptで定義されているコマンド郡の動かし方がわからない。

npm testだけは動いたのですが、他のbuild等のコマンドがうまく動きませんでした。 以下のようにすることでScript内で定義されているコマンドを動かすことが可能でした。

$npm run build

Roleの指定方法がわからない。

AWS Lambda Functionをアップロードする際に、 設定ファイルとして作成するlambdaConfig.jsonの内のRoleの記述方法わからず悩みました。 こちらはAWS Management Console内のIAM > Roles 内のarn:aws:iam::から始まる文字列を入力する必要があります。

npm run publishがうまくできない

package.jsonで指定しているaws-sdkのバージョンを更新した際に発生しました。 Lambdaのオブジェクトを作成する際に、apiVersionを明記すること必要がありました。

./script/publish.js

var lambda = new aws.Lambda({apiVersion:'2014-11-11', region: lambdaConfig.region}),
zipPath = 'pkg/' + pkgConfig.name + '.zip';

publishしたfunctionのテストに失敗する。

npm run initLambdaで作成したひな形ファイルにはhandlerFile・handlerMethod が作成されていないのが原因です。 上記の作成と、未設定時にapp.jsに定義したhandlerでアップロードするようにしてみました。

./script/initLambda.js

var fs = require('fs');
var config = {
region: '',
description: '',
role: '',
memorySize: '128',
timeout: '3',
handlerFile:'',
handlerMethod:''
};
fs.writeFileSync('./lambdaConfig.json',JSON.stringify(config));

./script/publish.js

function buildHnadlerName(lambdaConfig){
if(!lambdaConfig.handlerFile){
lambdaConfig.handlerFile = 'app';
}
if(!lambdaConfig.handlerMethod){
lambdaConfig.handlerMethod = 'handler'
}
return lambdaConfig.handlerFile + '.' + lambdaConfig.handlerMethod;
}

なお、上記の修正を適用した版を以下のブランチに配置しました。 こちらも併せて見ていただければ幸いです。 CM-Kajiwara/myFirstLambda

Amazon API Gatewayに作ったAWS Lambda Functionをデプロイする。

Deployに関しては、下記のブログを参照していただければと思います。 また、今回の作例ではAPI認証も実施しています。 Amazon API Gateway – API作成から動作確認までやってみる | Developers.IO Amazon API GatewayでAPIキー認証を設定する | Developers.IO

ブラウザからAmazon API Gatewayを呼ぶ

今回の作例では、Amazon API GatewayとWebサーバーとクロスドメインになるため、 ブラウザからCORSの設定を行う必要があります。 Amazon API Gateway をクロスオリジンで呼び出す (CORS) | Developers.IO

CORSの設定まで行えれば、呼び出すのはjQueryからでも、 生成されたSDKからでも呼び出すことが可能です。

<!doctype html>

<button id="callSDKFunction">Sample Click callSDKFunction</button>
<button id="calljQueryAjax">Sample Click calljQueryAjax</button>
<div id="imageContainer"></div>

上記を動かした画像が下記になります。 ボタンを押下することで、Amazon API GatewayよりLambdaから S3のPre-Signed URLを取得し、imgタグに挿入しているといった流れになります。 20150712

まとめ

API Gatewayをブラウザから扱ってみました。 CORSの設定が必要ではありますが、 そこさえ押さえてしまえば普通のREST APIとして呼び出すことができました。