ブラウザでAWS SDK for JavaScript v3を扱う

ブラウザでAWS SDK for JavaScript v3を扱う

ブラウザでAWS SDK for JavaScript v3を扱う

AWSを使用してWebアプリを開発する場合、AWS SDK for JavaScriptの使用がベストプラクティスとなります。
同SDKには2つのバージョンがあります。v2とv3です。
今回はAWS SDK for JavaScript v3を使用して、Webアプリを開発する方法を確認します。

構築する環境

Diagram of using AWS SDK for JavaScript v3 in browser.

S3バケットを作成し、静的ウェブサイトホスティング機能を有効にします。内部にHTMLファイルを設置して、コンテンツを用意します。
Cognito IDプールで、ブラウザスクリプトからAWSリソースへアクセスするためのクリデンシャルを取得します。今回はLambdaを実行する権限を付与します。
Lambda関数で実行するコードですが、Python3.8を選択し、現在の日付を返すものとします。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLに、CloudFormationテンプレートに加え、ブラウザスクリプト等を配置してます。

https://github.com/awstut-an-r/awstut-fa/tree/main/034

ブラウザスクリプトの作成手順

以下のAWS公式ページを参考にして作成します。

https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/welcome.html

https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/webpack.html

npmのインストール・初期化

AWS SDK for JavaScript v3を使用してWebアプリを開発する場合、npmのインストールが必要となります。
インストール手順は、以下のページをご確認ください。

https://docs.npmjs.com/downloading-and-installing-node-js-and-npm

インストール完了後、初期化処理を実行します。

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
...

Press ^C at any time to quit.
package name: (034)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
<meta charset="utf-8">About to write to /path/to/your/directory/package.json:

{
  "name": "034",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes)
Code language: Bash (bash)

これでpackage.jsonが作成されました。

Webpackインストール・設定

ブラウザスクリプトからAWS SDK for JavaScript v3を使用する場合、Webpackが必要です。
npmから、2つのパッケージをインストールします。

$ npm install --save-dev webpack
...
+ webpack@5.70.0
...


$ npm install --save-dev path-browserify
...
+ path-browserify@1.0.1
...
Code language: Bash (bash)

webpack.config.jsファイルを作成して、Webpackの設定を行います。
以下がwebpack.config.jsの中身です。

var path = require("path");
module.exports = {
  entry: [path.join(__dirname, "browser.js")],
  output: {
    path: __dirname,
    filename: 'main.js'
  },
   resolve:{
  fallback: { path: require.resolve("path-browserify")}
  }
};
Code language: JavaScript (javascript)

package.jsonファイルの修正も行います。

{
  "name": "034",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "path-browserify": "^1.0.1",
    "webpack": "^5.70.0"
  }
}
Code language: JSON / JSON with Comments (json)

Webpackでビルドするように設定します。

SDK for JavaScriptのインストール

v3の場合、SDKは複数のパッケージに分割されており、必要なものだけをnpmでインストールすることになります。
今回はCognito、Lambdaを扱いますので、合計4パッケージをインストールします。

$ npm install @aws-sdk/client-cognito-identity
...
+ @aws-sdk/client-cognito-identity@3.56.0
...


$ npm install @aws-sdk/credential-provider-cognito-identity
...
+ @aws-sdk/credential-provider-cognito-identity@3.56.0
...


$ npm install @aws-sdk/client-lambda
...
+ @aws-sdk/client-lambda@3.56.0
...


$ npm install @aws-sdk/util-utf8-browser
...
+ @aws-sdk/util-utf8-browser@3.55.0
...
Code language: Bash (bash)

ブラウザスクリプト作成

webpack.config.jsで指定した通り、browser.jsにコードを記載します。

import {
  CognitoIdentityClient
} from "@aws-sdk/client-cognito-identity";

import {
  fromCognitoIdentityPool
} from "@aws-sdk/credential-provider-cognito-identity";

import {
  LambdaClient,
  InvokeCommand
} from "@aws-sdk/client-lambda";

import {
  toUtf8
} from "@aws-sdk/util-utf8-browser";


const REGION = "ap-northeast-1";
const IDENTITY_POOL_ID = "[ID of Cognito ID Pool]";
const FUNCTION_NAME = "[Lambda Function Name]";

const lambdaClient = new LambdaClient({
  region: REGION,
  credentials: fromCognitoIdentityPool({
    client: new CognitoIdentityClient({ region: REGION }),
    identityPoolId: IDENTITY_POOL_ID
  }),
});

const showLambdaResult = async () => {
  try {
    const response = await lambdaClient.send(
      new InvokeCommand({ FunctionName: FUNCTION_NAME })
    );
    document.getElementById("viewer").innerHTML = `<p>${toUtf8(response.Payload)}</p>`
  } catch (err) {
    console.log(err);
  }
};

window.showLambdaResult = showLambdaResult;
Code language: JavaScript (javascript)

今回は開発方法の概要を確認することを目的としていますので、コードの詳細な解説は割愛します。
importでインストール済みのパッケージから、必要なクラスや関数を読み込みます。
Cognito IDプールとLambda用のクライアントオブジェクトを作成します。それらを使用してLambda関数を実行し、取得した文字列をHTMLに埋め込むように関数(showLambdaResult)を定義し、windowsオブジェクトに登録しておきます。

ファイルが完成したら、ビルドします。

$ npm run build

> 034@1.0.0 build /path/to/your/directory
> webpack

asset main.js 180 KiB [emitted] [minimized] (name: main) 1 related asset
...
Code language: Bash (bash)

ビルドが正常に完了すると、main.jsが作成されます。こちらもwebpack.config.jsで設定した通りです。

HTMLファイル作成

最後にユーザーがアクセスするHTMLファイルも作成します。

<!DOCTYPE html>
<html>
    <head>
        <title>fa-034</title>
    </head>
    <body>
        <div id="viewer"></div>
        <script type="text/javascript" src="./main.js"></script>
        <script>
          showLambdaResult();
        </script>
    </body>
</html>
Code language: HTML, XML (xml)

シンプルなHTMLファイルです。
先ほど定義した関数(showLambdaResult)を実行します。

(参考)CloudFormationテンプレートファイル

今回は開発方法の概要を確認することを目的としていますので、テンプレートファイルの詳細な解説は割愛します。

S3の静的ウェブサイトホスティング機能

Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref Prefix
      PublicAccessBlockConfiguration:
        BlockPublicAcls: false
        BlockPublicPolicy: false
        IgnorePublicAcls: false
        RestrictPublicBuckets: false
      WebsiteConfiguration:
        IndexDocument: index.html

  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Prefix
      PolicyDocument:
        Statement:
          Action:
            - s3:GetObject
          Effect: Allow
          Resource:
            - !Sub "arn:aws:s3:::${Bucket}/*"
          Principal: "*"
Code language: YAML (yaml)

ポイントは静的ウェブサイトホスティング機能です。
詳細は以下のページをご確認ください。

あわせて読みたい
S3静的ウェブサイトホスティング機能でサイトを公開する 【S3静的ウェブサイトホスティング機能でサイトを公開する構成】 S3の静的ウェブサイトホスティング機能を使って、ウェブサイトを公開する方法を確認します。 ウェブサ...

Lambda関数で実行するコードをインラインで定義

Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${Prefix}-function"
      Runtime: python3.8
      Role: !GetAtt FunctionRole.Arn
      Handler: index.lambda_handler
      Code:
        ZipFile: |
          import datetime

          def lambda_handler(event, context):
            return str(datetime.date.today())
Code language: YAML (yaml)

ZipFileプロパティを使用することで、コードをインラインで定義することができます。今回は現在の日付を返します。
詳細は以下のページでご確認ください。

あわせて読みたい
CloudFormationでLambdaを作成する3パータン(S3/インライン/コンテナ) 【CloudFormationでLambdaを作成する】 CloudFormationでLambdaを作成する場合、大別すると以下の3パターンあります。 S3バケットにコードをアップロードする インライ...

Cognitoでクリデンシャル作成

Resources:
  IdentityPool:
    Type: AWS::Cognito::IdentityPool
    Properties:
      AllowUnauthenticatedIdentities: true
      IdentityPoolName: !Sub "${Prefix}-IdentityPool"

  IdentityPoolRoleAttachment:
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties:
      IdentityPoolId: !Ref IdentityPool
      Roles:
        unauthenticated: !GetAtt IdentityPoolAuthenticatedRole.Arn

  IdentityPoolAuthenticatedRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: cognito-identity.amazonaws.com
            Condition:
              StringEquals:
                cognito-identity.amazonaws.com:aud: !Ref IdentityPool
              ForAnyValue:StringLike:
                cognito-identity.amazonaws.com:amr: unauthenticated
      Policies:
        - PolicyName: IdentityPoolUnauthenticatedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - lambda:InvokeFunction
                Resource:
                  - !Ref FunctionArn
Code language: YAML (yaml)

Cognitoを使用することで、AWSリソースにアクセスするためのクリデンシャルを生成することができます。
詳細は以下のページをご確認ください。

あわせて読みたい
Cognitoユーザープールの認証後にIDプールで権限を与える(Implicit Grant編) 【Cognitoユーザープールの認証後にIDプールで権限を与える】 CognitoユーザープールとIDプールを使用して、サインインユーザーにAWSリソースにアクセスするための権限...

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • バケット名:fa-034
  • Cognito IDプール:ap-northeast-1:f78ed244-a960-481d-b20d-54649660f668
  • Lambda関数名:fa-034-function

S3バケットにHTMLファイル・スクリプトを配置する

AWS CLIから2ファイルを配置します。

$ aws s3 cp index.html s3://fa-034
upload: ./index.html to s3://fa-034/index.html

$ aws s3 cp main.js s3://fa-034
upload: ./main.js to s3://fa-034/main.js
Code language: Bash (bash)

動作検証

準備が整いましたので、HTMLファイルにアクセスします。
今回の構成ですと、以下のURLとなります。

http://fa-034.s3-website-ap-northeast-1.amazonaws.com/

Successfully executed Lambda using SDK.

現在の日付が返ってきました。
以上のことから、AWS SDK for JavaScript v3を使用して、Lambdaを実行することができました。

まとめ

AWS SDK for JavaScript v3を使用して、Webアプリを開発する方法を確認しました。