Using AWS SDK for JavaScript v3 in Browser

TOC

Using AWS SDK for JavaScript v3 in Browser

When developing Web applications using AWS, the best practice is to use the AWS SDK for JavaScript.
The SDK is available in two versions: v2 and v3.
In this article, we will review how to develop a web app using AWS SDK for JavaScript v3.

Environment

Diagram of using AWS SDK for JavaScript v3 in browser.

Create an S3 bucket and enable the static website hosting feature. Prepare content by placing HTML files inside.
Obtain credentials to access AWS resources from a browser script in the Cognito ID Pool. This time, grant permission to invoke Lambda.
The code to be executed by the Lambda function, but we will choose Python 3.8 and assume it returns the current date.

CloudFormation template files

The above configuration is built with CloudFormation.
The following URL contains the CloudFormation template, browser scripts, etc.

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

Browser Script Creation Procedure

Refer to the following official AWS page for creation.

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

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

Installation and initialization of npm

To develop web applications using AWS SDK for JavaScript v3, npm must be installed.

Please refer to the following page for the installation procedure.

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

After installation is complete, initialization process is executed.

$ 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)
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 is now created.

Webpack installation and configuration

Webpack is required to use AWS SDK for JavaScript v3 from a browser script.
Install the two packages from npm.

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


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

Create the webpack.config.js file to configure Webpack.
The following is the content of 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)

Also modify the package.json file.

{
  "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)

Installing SDK for JavaScript

In v3, the SDK is divided into multiple packages, and only the necessary ones are installed using npm.
In this case, we will deal with Cognito and Lambda, so we will install a total of 4 packages.

$ 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)

Browser Script Creation

Write code in browser.js as specified in webpack.config.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)

The purpose of this article is to provide an overview of the development method, so a detailed explanation of the code is omitted.
Load the necessary classes and functions from the packages already installed with import.
Create a Cognito ID pool and a client object for Lambda. Execute a Lambda function using them, define a function (showLambdaResult) to embed the retrieved string in HTML, and register it in the windows object.

Once the file is complete, build it.

$ 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)

If the build completes successfully, main.js is created. This is also as configured in webpack.config.js.

HTML file creation

Finally, we also create the HTML files that users will access.

<!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)

A simple HTML file.
Execute the function we defined earlier (showLambdaResult).

(Reference) CloudFormation template files

The purpose of this article is to provide an overview of the development method, so a detailed explanation of the template file is omitted.

S3 static website hosting capabilities

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)

The key point is the static website hosting feature.
Please see the following page for details.

あわせて読みたい
Publish your site with S3 static website hosting 【Configure the S3 static website hosting to publish your site】 Find out how to use the S3 static website hosting to publish a website. If your website cons...

Inline definition of code to be executed by Lambda functions

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)

The ZipFile property allows the code to be defined inline. This time, the current date is returned.
See the following page for more details.

あわせて読みたい
3 parterns to create Lambda with CloudFormation (S3/Inline/Container) 【Creating Lambda with CloudFormation】 When creating a Lambda with CloudFormation, there are three main patterns as follows. Uploading the code to an S3 buc...

Creating credentials in 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 can be used to generate credentials to access AWS resources.
For more information, please see the following page.

あわせて読みたい
Authorization by Cognito ID Pool after Authentication by User Pool – Implicit Grant Ver 【Authorization by Cognito ID Pool after Authentication by User Pool - Implicit Grant Ver】 Use the Cognito user pool and identity pool to grant signed-in us...

Architecting

Use CloudFormation to build this environment and check its actual behavior.

Create CloudFormation stacks and check resources in stacks

Create a CloudFormation stacks.
For information on how to create stacks and check each stack, please refer to the following pages.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

After checking the resources in each stack, information on the main resources created in this case is as follows.

  • Bucket name: fa-034
  • Cognito ID pool: ap-northeast-1:f78ed244-a960-481d-b20d-54649660f668
  • Lambda function name: fa-034-function

Place HTML file/script in S3 bucket

Place 2 files from AWS CLI.

$ 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)

Verification of Operation

Now that you are ready, access the HTML file.
For this configuration, the URL is as follows

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

Successfully executed Lambda using SDK.

The current date was returned.
From the above, we were able to execute Lambda using the AWS SDK for JavaScript v3.

Summary

We have reviewed how to develop a web application using AWS SDK for JavaScript v3.

TOC