AWS Lambdaをブラウザから実行する。

# AWS LambdaのファンクションをAPI的に使えないか
AWS LambdaはAmazonのクラウド型アプリケーション実行のプラットフォームですが、発表されてからWebアプリのAPI的な使い方はできないのか？と思っていました。
公式のドキュメントでもモバイルアプリから実行できると書いてあるので、ブラウザからも実行できそうですが、公式サイトをみても具体的な方法を探せず、実例を検索してもなかなか出てこない。
しかし、本サービスに移行時のアップデートで、[AWS SDK for JavaScript in the Browser](http://aws.amazon.com/jp/sdk-for-browser/)から実行できるようになったみたいです。しかも同期的に実行できるので、APIとして使うことが期待できます。

# Lambdaファンクションを登録する
Lambdaファンクションの登録については、いろいろなところで、書いてあるので省略します。AWSアカウントを作って、Lambdaのサービスへ遷移して、指示に従えばとりあえず以下の図のように関数が登録されます。テンプレートとして「HelloWorld」という関数があるのでそれをそのまま使うことにします。

![関数を登録](https://qiita-image-store.s3.amazonaws.com/0/59131/50b370cb-8f05-901d-43af-9a44e9dbac12.jpeg)

ここで重要なのが、Function ARNの値です。あとで利用します。

# IAMでlambda関数実行の権限をもつユーザーを登録する
ブラウザから実行するには、lambda関数を実行する権限を持つIAMユーザーの、「Access Key Id」と「Secret Access Key」が必要です。注意しなければいけないのは、公開APIとしてブラウザからlambdaを利用するにはこの２つのキーをJavaScript内に記述する必要があることです。この2つのキーがあれば、ユーザーが権限をもつ操作は全て出来てしまうので、JavaScript内に記述するということは、基本的には誰でもできてしまうということです。

ですので、目的のlambda関数のみの実行権限をもつIAMユーザーを作成する必要があります。

## ユーザーの追加
AWSコンソールから、IAMサービスへ移動し、ユーザー > 新規作成へ進み、適当なユーザー名を指定して作成してください。
「Access Key Id」と「Secret Access Key」を表示してメモっておくか、認証情報をダウンロードしてください。

## ユーザーの権限の設定
最初にユーザーを追加した段階では、全く権限のないユーザーが追加されます。ここに目的のlamda関数の実行権限を付与します。

まずはユーザー一覧から目的のユーザーを選択してください。

「アクセス許可」の項目から、「インラインポリシー」のドロワーを開くと
"表示するインラインポリシーはありません。作成するには、ここをクリックしてください。"
と表示されますので、クリックします。

「許可を設定」の画面で、Policy Generatorを選択します。

![lambda_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/59131/7f8b7086-551f-b843-2937-6867e74c0eba.jpeg)

Policy Generatorの画面で

- サービス：AWS Lambda
- アクション：invokeFunction
- ARN:lambda関数のARN値

を入力し「ステートメントを追加」をクリックします。もし、実行したい関数が複数ある場合は、同様に2個、3個と登録して下さい。

![lambda_4.jpg](https://qiita-image-store.s3.amazonaws.com/0/59131/d5d23534-42c9-61c9-5cd2-7434ce22ed27.jpeg)

必要な関数への権限が付与できたら、「次のステップ」をクリックして下さい。そうすると、ポリシー適用用のJsonが表示されます。
この画面で「ポリシーを適用」ボタンをクリックすると、ユーザーに権限が付与されます。

# JavaScript側の実装
lambda関数とIAMユーザーを作成したら、ブラウザから実行する準備は整いました。

## AWS SDK for JavaScript in the Browser 
[AWS SDK for JavaScript in the Browser](http://aws.amazon.com/jp/sdk-for-browser/)は、ブラウザでAWSにアクセスするための機能を集めたライブラリです。
scriptタグで読み込むだけで利用できます。

```html
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.34.min.js"></script>
```

## Base64ライブラリ
これで基本的には実装可能ですが、Lamda関数にブラウザからパラメーターを渡すためには、SDKの関数にBase64エンコードした値を指定する必要があるので、Base64エンコード用のライブラリ

[js-base64](https://github.com/dankogai/js-base64)

も読み込んでおきます

```html
<script src="base64.min.js"></script>
```

## Script本体

lambdaの関数を実行するソースは以下のとおりです。


```js

    AWS.config.update({accessKeyId: 'akid', secretAccessKey: 'sakey' ,region:"us-west-2"});
    
    var context = Base64.encode(JSON.stringify( {param:"value1"} ));

    var lambda = new AWS.Lambda();    

    var params = {
      FunctionName:"HelloWorld",
      InvocationType:"RequestResponse",
      ClientContext:context
    };

    lambda.invoke( params,function(err,data) {
      if(err) console.log(err,err.stack);
      else console.log(data);
    });

```
### 権限の設定

まずはAWSサービスにアクセスするための権限設定を行います。

```js

AWS.config.update({accessKeyId: 'akid', secretAccessKey: 'sakey' ,region:"us-west-2"});
```

accessKeyIdとsecretAccessKeyには先ほど作成したユーザーの認証情報をいれてください。
regionには実行するlambda関数を登録したリージョンを入力して下さい。lambda関数のARN値
```
arn:aws:lambda:us-east-1:xxxxxx:function:HelloWorld
```
の「arn:aws:lambda:」の後に続く文字列です。

### 関数に渡すパラメーターの設定
関数に渡すパラメータはObjectとして渡すことができます。ただし、Objectをbase64エンコードする必要があるので,ObjectをJSON.stringifyし、Base64エンコードします。

```js
var context = Base64.encode(JSON.stringify( {param:"value1"} ));
```

### lambdaクラスのインスタンス化
lambdaクラスのインスタンス化を行います

```js
var lambda = new AWS.Lambda();
```

### パラメーターの設定
SDKのlambda関数実行用のメソッドに渡すパラメータを指定します。

```js
    var params = {
      FunctionName:"HelloWorld",
      InvocationType:"RequestResponse",
      ClientContext:context
    };
```

- FunctionName:作成したlambda関数の名前を指定します。
- InvocationType:今回は同期的に実行したいので、"RequestResponse"を指定します。
- ClientContext:ここにはBase64エンコーディングしたObjectを渡します。

ClientContextに指定した値は、lambda関数の中で、

```js
context.clientContext
```

としてアクセス可能です。

### lambda関数を実行。実行後callback関数を実行

最後に、AWS.Lambda.invokeメソッドを利用して、lambda関数を実行します。

```js
    lambda.invoke( params,function(err,data) {
      if(err) console.log(err,err.stack);
      else console.log(data);
    });
```

dataの中には、lambda関数の中で実行する、context.doneの第2引数が入ります。
lambda関数のなかで処理したデータをいれれば、同期的に実行し、返り値を受け取ることが可能になります。