Tag: JavaScript


Creating and Deploying a Serverless Web Application with CloudFormation and Ember.js

Serverless computing enables you to build scalable and cost-effective applications that scale up or down automatically without provisioning, scaling, and managing servers. You can use AWS Lambda to execute your back-end application code, Amazon API Gateway for a fully managed service to create, publish, maintain, monitor, and secure your REST API, and Amazon S3 to host and serve your static web files.

Ember.js is a popular, long-standing front-end web application framework for developing rich HTML5 web applications. Ember.js has an intuitive command line interface. You can write dramatically less code by using its integrated Handlebars templates. Ember.js also contains an abstracted data access pattern that enables you to write application adapters that communicate with REST APIs.

In this tutorial, we build a simple Ember.js application that initializes the AWS SDK for JavaScript using native Ember.js initializers. The application communicates with API Gateway, which runs backend Lambda code that reads and writes to Amazon DynamoDB. In addition, we use the Ember.js command line interface to package and deploy the web application to Amazon S3 for hosting and for delivery through Amazon CloudFront. We also use AWS CloudFormation with the AWS Serverless Application Model (AWS SAM) to automate the creation and management of our serverless cloud architecture.

Configuring your local development environment

Requirements:

Clone or fork the aws-serverless-ember repository and install the dependencies. Based on your setup, you might need to use the sudo argument when installing these. If you get an EACCESS error, run these commands with sudo npm install:

npm install -g ember-cli
npm install -g bower
git clone https://github.com/awslabs/aws-serverless-ember

You should now have two folders in the project’s root directory, client and cloud. The cloud folder contains our CloudFormation templates and Lambda function code. The client folder contains the client-side Ember.js web application that deploys to S3. Next, install the dependencies:

cd aws-serverless-ember
cd client
npm install && bower install

When this is complete, navigate to the cloud directory in your project’s root directory:

cd ../cloud

Create and deploy the AWS Cloud environment using CloudFormation

The infrastructure for this application uses API Gateway, Lambda, S3, and DynamoDB.

Note: You will incur charges after running these templates. See the appropriate pricing page for details.

The cloud folder of the repository contains the following files:

  • api.yaml – An AWS SAM CloudFormation template for your serverless backend
  • deploy.sh – A bash helper script for deploying with CloudFormation
  • hosting.yaml – A CloudFormation template for your S3 bucket and website
  • swagger.yaml – The API definition for API Gateway
  • index.js – The Lambda function code
  • swagger.yaml – The OpenAPI definition for your serverless REST API

First, create a website bucket with static website hosting. You also create a bucket for deploying your serverless code.

Note: For this section be sure you’ve installed and configured the AWS CLI with appropriate permissions (your CLI should at least have access to read/write to CloudFormation and read/write to S3) for this tutorial.

Run the following command to create the S3 hosting portion of our back-end, wait for completion, and finally describe stacks once complete:

aws cloudformation create-stack --stack-name ember-serverless-hosting --template-body file://$PWD/hosting.yaml && \
aws cloudformation wait stack-create-complete --stack-name ember-serverless-hosting && \ 
aws cloudformation describe-stacks --stack-name ember-serverless-hosting

This creates a CloudFormation stack named ember-serverless-hosting, waits for the stack to complete, and then display the output results. While you wait, you can monitor the events or view the resource creation in the CloudFormation console, or you run the following command in another terminal:

aws cloudformation describe-stack-events –-stack-name ember-serverless-hosting

When the stack is created, the console returns JSON that includes the stack outputs specified in your template. If the JSON does not output for some reason, re-run the last portion of the command: aws cloudformation describe-stacks --stack-name ember-serverless-hosting. This output includes the bucket name you’ll use to deploy your serverless code. It also includes the bucket URL you’ll use to deploy your ember application. For example:

{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:<aws-region>:<account-id>:stack/ember-serverless-hosting/<unique-id>",
            "Description": "Ember Serverless Hosting",
            "Tags": [],
            "Outputs": [
                {
                    "Description": "The bucket used to deploy Ember serverless code",
                    "OutputKey": "CodeBucketName",
                    "OutputValue": "ember-serverless-codebucket-<unique-id>"
                },
                {
                    "Description": "The bucket name of our website bucket",
                    "OutputKey": "WebsiteBucketName",
                    "OutputValue": "ember-serverless-websitebucket-<unique-id>"
                },
                {
                    "Description": "Name of S3 bucket to hold website content",
                    "OutputKey": "S3BucketSecureURL",
                    "OutputValue": "https://ember-serverless-websitebucket-<unique-id>.s3.amazonaws.com"
                },
                {
                    "Description": "URL for website hosted on S3",
                    "OutputKey": "WebsiteURL",
                    "OutputValue": "http://ember-serverless-websitebucket-<unique-id>.s3-website-<aws-region>.amazonaws.com"
                }
            ],
            "CreationTime": "2017-02-22T14:40:46.797Z",
            "StackName": "ember-serverless",
            "NotificationARNs": [],
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false
        }
    ]
}

Next, you create your REST API with CloudFormation and AWS SAM. For this, you need the CodeBucketName output parameter from the previous stack JSON output when running the following command to package the template:

aws cloudformation package --template-file api.yaml --output-template-file api-deploy.yaml --s3-bucket <<CodeBucketName>>

This command creates a packaged template file named api-deploy.yaml. This file contains the S3 URI to your Lambda code, which was uploaded by the previous command. To deploy your serverless REST API, run the following:

aws cloudformation deploy --template-file api-deploy.yaml --stack-name ember-serverless-api --capabilities CAPABILITY_IAM

Next, run the following command to retrieve the outputs:

aws cloudformation describe-stacks --stack-name ember-serverless-api

Note the API Gateway ID OutputValue:

...
"Outputs": [
                {
                    "Description": "URL of your API endpoint", 
                    "OutputKey": "ApiUrl", 
                    "OutputValue": "https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod"
                }, 
                {
                    "Description": "API Gateway ID", 
                    "OutputKey": "Api", 
                    "OutputValue": "xxxxxxxx" //<- This Value is needed in the below command
                }
            ],
...

Now, run the following command to download the JavaScript SDK for your API using the ID noted above:

aws apigateway get-sdk --rest-api-id <<api-id>> --stage-name Prod --sdk-type javascript ./apiGateway-js-sdk.zip

This downloads a .zip file that contains the JavaScript interface generated by API Gateway. You use this interface to interact with API Gateway from your Ember.js application. Extract the contents of the .zip file, which produces a folder named apiGateway-js-sdk , directly into your client/vendor/ folder. You should now have the following client/vendor folder structure:

  • client
    • vendor
      • apiGateway-js-sdk
      • amazon-cognito

The additional files are libraries that the SDK generated by API Gateway uses to properly sign your API Gateway request. For details about how the libraries are used, see the Amazon API Gateway Developer Guide.

To use the SDK in your Ember.js application, you need to ensure Ember loads them properly. We do this by using app.import() statements within the ember-cli-build.js file.

Initialize the AWS SDK for JavaScript with Ember

You’ll set up and initialize the AWS SDK for JavaScript within your application by using ember initializers. Ember initializers allow you to initialize code before your application loads. By using them, you can ensure the AWS SDK and your API SDK are properly initialized before your application is presented to the user.

Open your client/config/environment.js file and add your AWS configuration to the development section. Add the region in which you are running, the Amazon Cognito identity pool ID created in the previous section, the Amazon Cognito user pool ID created in the previous section, and the user pool app client ID created in the previous section.

You can retrieve these values by running:

aws cloudformation describe-stacks --stack-name ember-serverless-api

Use the following values returned in the Output within the client/config/environment.js file:

  • ENV.AWS_POOL_ID -> CognitoIdentityPoolId
  • ENV.AWS_USER_POOL_ID -> CognitoUserPoolsId
  • ENV.AWS_CLIENT_ID -> CognitoUserPoolsClientId
// client/config/environment.js L26
if (environment === 'development') {
    ENV.AWS_REGION = ‘aws-region-1’
    ENV.AWS_POOL_ID = ‘aws-region:unique-hash-id’
    ENV.AWS_USER_POOL_ID = ‘aws-region_unique-id’
    ENV.AWS_CLIENT_ID = ‘unique-user-pool-app-id’
}

Now, run your client and ensure the SDK loads properly. From the client directory, run:

ember s

Then visit http://localhost:4200/ in your web browser, and open the developer tools. (If you’re using Chrome on a macOS machine, press cmd+option+i. Otherwise, press Ctrl+Shift+i.), you should see the following messages:

AWS SDK Initialized, Registering API Gateway Client: 
API Gateway client initialized: 
Object {docsGet: function, docsPost: function, docsDelete: function, docsOptions: function}

This confirms your generated SDK and the AWS SDK are properly loaded and ready for use.

Now try the following:

1. Log in with any user/credentials, and observe the error. (onFailure: Error: User does not exist.)
2. Register with a weak password, and observe the error. (Password did not conform with policy. Password not long enough.)
3. Register a new user, and use an email address you have access to so you receive a confirmation code.
4. Try re-sending the confirmation code.
5. Enter the confirmation code.
6. Log in with your newly created user.

The JWT access token is retrieved from Amazon Cognito user pools, it is decoded and displayed for reference after logging into the client application. The section entitled “Dynamo Items” within the application creates and deletes items within your DynamoDB table (that was previously created with CloudFormation) via API Gateway and Lambda, and authenticated with Cognito User Pools.

Deploying the web application to Amazon S3

In this command, you use the S3 WebsiteBucketName output from the ember-serverless-hosting CloudFormation stack as the sync target.

Note: you can retrieve the output values again by running:
aws cloudformation describe-stacks --stack-name ember-serverless-hosting

cd client
ember build
aws s3 sync dist/ s3://WebsiteBucketName/ --acl public-read

Your website should now be available at the WebsiteURL output value from the ember-serverless-hostingCloudFormation stack’s outputs.

Questions or comments? Reach out to us on the AWS Development Forum.

Source code and issues on GitHub: https://github.com/awslabs/aws-serverless-ember.

React Native Support in the AWS SDK for JavaScript

We’re excited to announce React Native support in the AWS SDK for JavaScript.

You can now access all services that are currently supported in the AWS SDK for JavaScript from within a React Native application. You can configure Amazon Cognito Identity as the authentication provider by using the same Amazon Cognito Identity credentials you might already be familiar with from the browser SDK.

Getting Started with the SDK in React Native

Save the AWS SDK for JavaScript as a project dependency by running the following:

npm install --save aws-sdk

Within your project, import the SDK with the following example:

import AWS from 'aws-sdk/dist/aws-sdk-react-native';

Once imported, you can use the SDK the same way you use it in the browser. For example, the following shows how to get a list of folders from an S3 bucket, given a prefix:

import AWS from 'aws-sdk/dist/aws-sdk-react-native';

const s3 = new AWS.S3({
  region: 'REGION',
  credentials: {/* */}
});

export async function getFoldersByPrefix(bucket, prefix) {
  let nextMarker = null;
  let isTruncated = false;
  const folders = [];

  // Returns all objects in current 'directory'
  do {
    const s3Objects = await s3.listObjects({
      Bucket: bucket,
      Prefix: prefix || '',
      Delimiter: '/',
      Marker: nextMarker
    }).promise();
    // Store the folder paths
    const prefixes = s3Objects.CommonPrefixes.map(common => common.Prefix);
    folders.push.apply(folders, prefixes)
    // Check if there are more objects in this directory
    isTruncated = s3Objects.IsTruncated;
    nextMarker = isTruncated ? s3Objects.NextMarker : null;
  } while (isTruncated);
  
  return folders;
}

Take a look at the AWS SDK for JavaScript SDK Developer Guide for examples of how to make service calls with the SDK.

Give It a Try!

We look forward to hearing what you think of this new support for React Native in the AWS SDK for JavaScript! Try it out and leave your feedback in the comments or on GitHub!

Using webpack and the AWS SDK for JavaScript to Create and Bundle an Application – Part 2

In the previous post in this series, we introduced how to use webpack and the AWS SDK for JavaScript to create and bundle an application.

In this post, we’re going to dig a little bit into other features, such as creating bundles with only the AWS services you need, and generating bundles that will also run in Node.js.

Importing Individual Services

One of the benefits of using webpack is that it can parse your dependencies and include only the code your application needs. You might have noticed that in our previous project, webpack generated a bundle that was 2.38 MB. That’s because webpack is currently importing the entire AWS SDK for JavaScript based on the following statement in s3.js.

var AWS = require('aws-sdk');

We can help webpack include only the Amazon S3 service if we update our require statement to the following:

var S3 = require('aws-sdk/clients/s3');

All the AWS SDK configuration options that are available using AWS.config can also be set when instantiating a service. We can still access the AWS namespace to set global configuration across all services with the following:

var AWS = require('aws-sdk/global');

Here’s an example of what our s3.js file would look like with these changes.

s3.js

// Import the Amazon S3 service client
var S3 = require('aws-sdk/clients/s3');

// Set credentials and region
var s3 = new S3({
    apiVersion: '2006-03-01',
    region: 'REGION', 
    credentials: {/* */}
  });

/**
 * This function retrieves a list of objects
 * in a bucket, then triggers the supplied callback
 * with the received error or data
 */
function listObjects(bucket, callback) {
  s3.listObjects({
    Bucket: bucket
  }, callback);
}

// Export the handler function
module.exports = listObjects;

Now when we run npm run build, webpack reports the following:

    Version: webpack 1.13.2
    Time: 720ms
      Asset    Size  Chunks             Chunk Names
    bundle.js  797 kB     0  [emitted]  main
      [0] multi main 28 bytes {0} [built]
      [1] ./browser.js 653 bytes {0} [built]
      [2] ./s3.js 803 bytes {0} [built]
       + 155 hidden modules

Now, our generated bundle has dropped from 2.38 MB to 797 KB.

You can configure webpack to minify the generated code to reduce the final size even more!

Generating Node.js Bundles

You can use webpack to generate bundles that run in Node.js by specifying target: 'node' in the configuration. This can be useful when you’re running a Node.js application in an environment where your disk space is limited.

Let’s update our project to build a Node.js bundle by creating a file called node.js. This file will be nearly identical to browser.js, however, instead of listing S3 objects in the DOM, it will output them to the console.

node.js

// Import the listObjects function
var listObjects = require('./s3');
var bucket = 'BUCKET';
// Call listObjects on the specified bucket
listObjects(bucket, function(err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log('S3 Objects in ' + bucket + ':');
    // Print the Key for each returned Object
    data.Contents.forEach(function(metadata) {
      console.log('Key: ' + metadata.Key);
    });
  }
});

Next, we’ll update our webpack.config.js to use node.js as the entry point, and add a new field, target: "node" to let webpack know it should generate a Node.js bundle.

webpack.config.js

// Import path for resolving file paths
var path = require('path');
module.exports = {
  // Specify the entry point for our app
  entry: [
    path.join(__dirname, 'node.js')
  ],
  // Specify the output file containing our bundled code
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
  // Let webpack know to generate a Node.js bundle
  target: "node",
  module: {
    /**
      * Tell webpack how to load JSON files
      * By default, webpack only knows how to handle
      * JavaScript files
      * When webpack encounters a 'require()' statement
      * where a JSON file is being imported, it will use
      * the json-loader
      */
    loaders: [
      {
        test: /.json$/, 
        loaders: ['json']
      }
    ]
  }
}

Run npm run build to generate the new bundle. You can test this code on the command line by running node bundle.js. This should output a list of S3 objects in the console!

Give It a Try!

We look forward to hearing what you think of this new support for webpack in the AWS SDK for JavaScript v2.6.1! Try it out and leave your feedback in the comments or on GitHub!

Using webpack and the AWS SDK for JavaScript to Create and Bundle an Application – Part 1

We introduced support for webpack in version 2.6.1 of the AWS SDK for JavaScript. Using tools such as webpack with the SDK give you a way to bundle your JavaScript modules so that you can write modularized code for the browser.

This post will walk through how to create and bundle a simple application that displays a list of Amazon S3 objects from a bucket by using webpack and the AWS SDK for JavaScript.

Why Use webpack?

Tools such as webpack parse your application code, searching for import or require statements to create bundles that contain all the assets your application needs.

Although webpack only knows how to handle JavaScript files by default, can also configure it to handle other types, such as JSON, CSS, and even image files! This makes it great at packaging up your application’s assets so that they can be easily served through a webpage.

Using webpack, you can create bundles with only the services you need, and generate bundles that will also run in Node.js!

Prerequisites

To follow along with this post, you’ll need to have node.js and npm installed (npm comes bundled with node.js). When you have these tools, create a new directory and download the dependencies we’ll need for this project by running npm install x, where x is the following:

  • aws-sdk: the AWS SDK
  • webpack: the webpack CLI and JavaScript module
  • json-loader: a webpack plugin that tells webpack how to load JSON files

Setting Up the Application

Start by creating a directory to store the project. We’ll name our project aws-webpack.

Our application will contain three files that do the following:

  • s3.js exports a function that accepts a bucket as a string, and a callback function, and returns a list of objects to the callback function.
  • browser.js imports the s3.js module, calls the listObjects function, and displays the results.
  • index.html references the JavaScript bundle that webpack creates.

Create these files in the project’s root directory, as follows:

s3.js

Important: We’ve left configuring the credentials to you.

// Import the AWS SDK
var AWS = require('aws-sdk');

// Set credentials and region,
// which can also go directly on the service client
AWS.config.update({region: 'REGION', credentials: {/* */}});

var s3 = new AWS.S3({apiVersion: '2006-03-01'});

/**
 * This function retrieves a list of objects
 * in a bucket, then triggers the supplied callback
 * with the received error or data
 */
function listObjects(bucket, callback) {
  s3.listObjects({
    Bucket: bucket
  }, callback);
}

// Export the handler function
module.exports = listObjects;

browser.js

// Import the listObjects function
var listObjects = require('./s3');
var bucket = 'BUCKET';
// Call listObjects on the specified bucket
listObjects(bucket, function(err, data) {
  if (err) {
    alert(err);
  } else {
    var listElement = document.getElementById('list');
    var content = 'S3 Objects in ' + bucket + ':n';
    // Print the Key for each returned Object
    content +=  data.Contents.map(function(metadata) {
      return 'Key: ' + metadata.Key;
    }).join('n');
    listElement.innerText = content;
  }
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>AWS SDK with webpack</title>
    </head> 
    <body>
        <div id="list"></div>
        <script src="bundle.js"></script>
    </body>
</html>

At this point, we have one JavaScript file that handles making requests to Amazon S3, one JavaScript file that appends a list of S3 object keys to our webpage, and an HTML file that contains a single div tag and script tag. In this last step before our webpage will display data, we’ll use webpack to generate the bundle.js file that the script tag references.

Configuring webpack

You specify configuration options in webpack by using a plain JavaScript file. By default, webpack looks for a file named webpack.config.js in your project’s root directory. Let’s create our webpack.config.js.

webpack.config.js

// Import path for resolving file paths
var path = require('path');
module.exports = {
  // Specify the entry point for our app.
  entry: [
    path.join(__dirname, 'browser.js')
  ],
  // Specify the output file containing our bundled code
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
  module: {
    /**
      * Tell webpack how to load 'json' files because
      * by default, webpack only knows how to handle
      * JavaScript files.
      * When webpack encounters a 'require()' statement
      * where a 'json'' file is being imported, it will use
      * the json-loader.  
      */
    loaders: [
      {
        test: /.json$/, 
        loaders: ['json']
      }
    ]
  }
}

We specified our entry point as browser.js in webpack.config.js. The entry point is the file webpack uses to start searching for imported modules. We also defined the output as bundle.js. This bundle will contain all the JavaScript our application needs to run. We don’t’ have to specify s3.js as an entry point because webpack already knows to include it because it’s imported by browser.js. Also, webpack knows to include the aws-sdk because it was imported by s3.js!

Notice that we specified a loader to tell webpack how to handle importing JSON files, in this case by using the json-loader we installed earlier. By default, webpack only supports JavaScript, but uses loaders to add support for importing other file types as well. The AWS SDK makes heavy use of JSON files, so without this extra configuration, webpack will throw an error when generating the bundle.

Running webpack

We’re almost ready to build our application! In package.json, add "build": "webpack" to the scripts object.

{
  "name": "aws-webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.6.1"
  },
  "devDependencies": {
    "json-loader": "^0.5.4",
    "webpack": "^1.13.2"
  }
}

Now run npm run build from the command line and webpack will generate a bundle.js file in your project’s root directory. The results webpack reports should look something like this:

    Version: webpack 1.13.2
    Time: 1442ms
      Asset     Size  Chunks             Chunk Names
    bundle.js  2.38 MB     0  [emitted]  main
      [0] multi main 28 bytes {0} [built]
      [1] ./browser.js 653 bytes {0} [built]
      [2] ./s3.js 760 bytes {0} [built]
       + 343 hidden modules    

 

At this point, you can open index.html in a browser and see output like that in our example.

Give It a Try!

In an upcoming post, we’ll explore some other features of using webpack with the AWS SDK for JavaScript.

We look forward to hearing what you think of this new support for webpack in the AWS SDK for JavaScript v2.6.1! Try it out and leave your feedback in the comments or on GitHub!

AWS Lambda Support for Node.js 4.3.2 Runtime

We are pleased to announce that in conjunction with the availability of Node.js 4.3.2 in AWS Lambda, Version 2.3.2 of the AWS SDK for JavaScript (in both Node.js and in the browser) supports the passing in of "nodejs4.3" as a value for the Runtime parameter for the createFunction and updateFunctionConfiguration operations. Now that the Node.js 4.3.2 runtime is available in Lambda, you will be able to take advantage of ES6 features in your Lambda functions, such as native Promise support, destructuring assignment, block-scope variables, and more. For more information about using Node.js 4.3.2 in Lambda, see the AWS Compute Blog.

Since Version 2.3.0, the AWS SDK for JavaScript supports a Promise interface on all requests. Lambda will soon update its default version of the SDK to include this feature, but you can leverage the SDK’s Promise support in Lambda now by bundling the latest version of the SDK in your Lambda functions. For more information about the SDK’s Promise support, see our blog post.

We are excited for Lambda support for Node.js 4.3 and the possibilities for our customers. We would love to hear your feedback. You can leave comments here on our blog, open up an issue on Github, or tweet @AWSforJS!

Support for Promises in the SDK

Today’s release of the AWS SDK for JavaScript (v2.3.0) introduces support for promises when calling service operations. Promises provide an alternative to the use of a callback function to manage asynchronous flow. They allow treating asynchronous calls as a variable, simplifying error handling and providing greater control over handling results from asynchronous calls.

For more information about promises, check out out this entry on MDN!

This post describes how to use promises within the context of the SDK to handle completing asynchronous tasks.

Setting a Promise Library

By default, the AWS SDK for JavaScript will check for a globally defined Promise function. If found, it adds the promise() method on AWS.Request objects. Some environments, such as Internet Explorer or earlier versions of Node.js, don’t support promises natively. You can use the AWS.config.setPromisesDependency() method to supply a Promise constructor. After this method is called, promise() will exist on all AWS.Request objects. The following example shows how you can set a custom promise implementation for the AWS SDK to use.

Node.js Example

// Use bluebird implementation of Promise
AWS.config.setPromisesDependency(require('bluebird'));
// Use Q implementation of Promise
AWS.config.setPromisesDependency(require('Q').Promise);
// Use 'rsvp' implementation of Promise
AWS.config.setPromisesDependency(require('rsvp').Promise);
// Revert back to using native or globally available Promise
AWS.config.setPromisesDependency(null);

Browser Example

In the browser, a library that implements promises and provides a global Promise namespace, (bluebird) should be loaded before the AWS SDK is loaded. The AWS SDK will then find the namespace and use it internally. If the AWS SDK is loaded before the library, or the library uses a namespace other than Promise, then the namespace can be provided by calling AWS.config.setPromisesDependency():

// AWS SDK was loaded after bluebird, set promise dependency
AWS.config.setPromisesDependency(Promise);

Making Requests by Using Promises

Instead of using callbacks, the AWS.Request.promise() method provides a way to call a service operation and return a promise to manage asynchronous flow instead of callbacks. In node.js and the browser, an AWS.Request is returned when a service operation is called without a callback function. You could call send() on the request to make the service call. The promise() method immediately starts the service call and returns a promise.

The following examples provide a comparison between the use of a simplified callback method and promises to make a simple request.

Simplified Callback Method

In the following example, a callback method that accepts error and data objects is supplied. The logic to handle errors or successful requests is contained in the callback method.

var s3 = new AWS.S3({apiVersion: '2006-03-01', region: 'us-west-2'});
var params = {
  Bucket: 'bucket',
  Key: 'example1.txt',
  Body: 'Uploaded text using the simplified callback method!'
};
s3.putObject(params, function(err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log('Success');
  }
});

Promise-Based Method

In the following example, a promise is returned that is fulfilled with a data object, or rejected with an error object. Using promises, a single callback isn’t responsible for detecting errors. Instead, the correct callback will be called based on the success or failure of a request.

var s3 = new AWS.S3({apiVersion: '2006-03-01', region: 'us-west-2'});
var params = {
  Bucket: 'bucket',
  Key: 'example2.txt',
  Body: 'Uploaded text using the promise-based method!'
};
var putObjectPromise = s3.putObject(params).promise();
putObjectPromise.then(function(data) {
  console.log('Success');
}).catch(function(err) {
  console.log(err);
});

The following example demonstrates how to write a simple script that uploads a directory of files to an Amazon S3 bucket, and then sends an email after the upload is complete.

Promises Example

// Check if environment supports native promises
if (typeof Promise === 'undefined') {
  AWS.config.setPromisesDependency(require('bluebird'));
}

var s3 = new AWS.S3({apiVersion: '2006-03-01', region: 'us-west-2'});
var ses = new AWS.SES({apiVersion: '2010-12-01', region: 'us-west-2'});

// Take a list of objects containing file data and send an email
var sendEmail = function sendEmail(files) {
  var keys = files.map(function(file) {
    return file.key;
  });
  var body = keys.join('n') + 'nnobjects were successfully uploaded.';
  var params = {
    Source: 'from@email.com',
    Destination: {
      ToAddresses: ['to@email.com']
    },
    Message: {
      Subject: {
        Data: 'Batch PutObject job completed'
      },
      Body: {
        Text: {
          Data: body
        }
      }
    }
  };
  return ses.sendEmail(params).promise();
};

// Upload a list of files to an S3 bucket
var putBatch = function putBatch(bucket, files) {
  // Make all the putObject calls immediately
  // Will return rejected promise if any requests fail
  return Promise.all(files.map(function(file) {
    var params = {
      Bucket: bucket,
      Key: file.key,
      Body: file.stream
    };
    return s3.putObject(params).promise();
  }));
};

// Create streams for files
var fileNames = fs.readdirSync('/path/to/dir/');
var files = fileNames.map(function(fileName) {
  return {
    key: fileName,
    stream: fs.createReadStream('/path/to/dir/' + fileName)
  };
});

//Upload directory of files to S3 bucket and send an email on success
putBatch('myBucket', files)
  .then(sendEmail.bind(null, files))
  .catch(console.error.bind(console));

You’ll notice we aren’t checking for errors inside our callback functions to determine the action to take. Instead, we can attach a single catch callback to our promise chain that will handle any errors thrown by our functions. Our code also reads as a series of steps to take (putBatch then sendEmail) instead of having to nest callbacks inside callbacks.

When a promise is fulfilled, the registered callback will have access to the data object as the first argument. We could have also provided a second callback that would be executed if the promise was rejected, but used a single catch statement instead. Rejected promises will pass an error object as the first argument to a callback.

Give It a Try!

We would love to hear what you think of this new feature. Give the AWS SDK for JavaScript v2.3.0 a try and leave your feedback in the comments or on GitHub!

Announcing the Amazon DynamoDB Document Client in the AWS SDK for JavaScript

Version 2.2.0 of the AWS SDK for JavaScript introduces support for the document client abstraction in the AWS.DynamoDB namespace. The document client abstraction makes it easier to read and write data to Amazon DynamoDB with the AWS SDK for JavaScript. Now you can use native JavaScript objects without annotating them as AttributeValue types.

This article describes how to use the document client abstraction to make requests to Amazon DynamoDB.

Making Requests with the Document Client

The following example shows a PutItem request to Amazon DynamoDB with the document client. Note that you can use native JavaScript objects without annotating them as AttributeValue types. The document client annotates the JavaScript object that you provide as input with AttributeValue types before making a request to DynamoDB.

For a list of supported API operations, you can check out the API documentation.

Example

var docClient = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});

var params = {
    Item: {
        hashkey: 'key',
        boolAttr: true,
        listAttr: [1, 'baz', true]
        mapAttr: {
            foo: 'bar'
        }
    },
    TableName: 'table'
};

docClient.put(params, function(err, data){
    if (err) console.log(err);
    else console.log(data);
});

Support for Sets

The AWS.DynamoDB.DocumentClient.createSet() is a convenience method for creating a set. This method accepts a JavaScript array and a map of options. The type of set is inferred from the type of the first element in the list. Amazon DynamoDB currently supports three types of sets: string sets, number sets, and binary sets.

Example

var docClient = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});

var params = {
    Item: {
        hashkey: 'key',
        stringSet: docClient.createSet(['a', 'b']);
        numberSet: docClient.createSet([1, 2]);
        binarySet: docClient.createSet([new Buffer(5), new Uint8Array(5)]);
    },
    TableName: 'table'
};

docClient.put(params, function(err, data){
    if (err) console.log(err);
    else console.log(data);
});

You can also validate the uniformity of the supplied list by setting validate: true in the options passed in to the createSet() method.

// This is a valid string set
var validSet = docClient.createSet(['a', 'b'], {validate: true});

// This is an invalid number set
var invalidSet = docClient.createSet([1, 'b'], {validate: true});

Using Response Data from the Document Client

The document client also unmarshalls response data annotated with AttributeValue types from DynamoDB to native JavaScript objects that can be easily used with other JavaScript code.

Example

var docClient = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});

var params = {
    Key: {
        hashkey: 'key',
    },
    TableName: 'table'
};

docClient.get(params, function(err, data){
    if (err) console.log(err);
    else console.log(data); 
    /**
     *  { 
     *      Item: { 
     *          hashkey: 'key'
     *          boolAttr: true,
     *          listAttr: [1, 'baz', true]
     *          mapAttr: {
     *              foo: 'bar'
     *          }
     *      }
     *  }
     **/
});

For more information about the document client and its supported operations, see the API documentation.

We hope this simplifies the development of applications with the AWS SDK for JavaScript and Amazon DynamoDB. We’d love to hear what you think about the document client abstraction, so leave us a comment here, or on GitHub, or tweet about it @awsforjs.

Introducing the SDK Builder for the AWS SDK for JavaScript in the Browser

We are pleased to introduce the SDK builder for the AWS SDK for JavaScript in the Browser.

The SDK builder allows you to customize and download the AWS SDK for JavaScript in the Browser. You can now include support for just the service clients you are using, which reduces the size of the browser distributable of the AWS SDK for JavaScript and improves the efficiency of your web applications.

You’ll find the SDK builder here: https://sdk.amazonaws.com/builder/js.

This article gives you an overview of the SDK builder, and shows you how to build a custom version of the SDK.

Step 1: Select an SDK Version

First, select the SDK version you want to customize. We recommend selecting the latest version.

Select a core version

 

Step 2: Select Services

You can then choose which service clients you want to include in your customized build. There are two preconfigured selections available:

  • Default services: This includes service clients for services that support the CORS standard.
  • All services: If you are using the AWS SDK for JavaScript in an environment that doesn’t enforce the CORS standard (for example, Google Chrome extensions and Windows Store Applications), then you can include support for all AWS services.

Select services

The globe icon next to the name of the service client indicates that the service supports CORS.

Services that support CORS

You can also customize the API version of the service clients you select. We recommend selecting the latest API version.

Select API versions

 

Step 3: Select a Bundle Type and Build

You are now ready to build your custom version of the SDK. Verify your build configuration, select a bundle type, and then click Build!

Supported Browsers

The SDK builder can be used on all modern browsers.

Browser Version
Google Chrome 31.0+
Microsoft Internet Explorer 10.0+
Mozilla Firefox 31.0+
Apple Safari 7.0+
Opera 29.0+

Wrapping Up

We hope the SDK builder makes it easier for you to optimize your application’s JavaScript footprint. We’re eager to hear what you think. Leave us a comment, tweet about it @awsforjs, or report an issue at github.com/aws/aws-sdk-js/issues.

AWS SDK for JavaScript Office Hour

The AWS SDKs and Tools team invites you to the first-ever online office hour hosted by the maintainers of the AWS SDK for JavaScript. It will be held via Google Hangouts at 10:00-11:00am PDT (UTC -7:00) on Tuesday 6/30. If you don’t have one already, you will need to create an account with Google to join the video chat.
 
This first office hour will be driven by customer questions. We expect to focus on questions about the SDK, but any questions related to JavaScript development on AWS are welcome. We’re excited to meet you and help you be successful in developing JavaScript applications on AWS!
 
Please register for the event, add it to your calendar, and join the office hour next Tuesday.

 

Announcing CORS Support for Amazon EC2

We are pleased to announce that Amazon EC2 now supports CORS requests, which means you can now use the AWS SDK for JavaScript in the Browser to access your Amazon EC2 resources.

The following example code snippet shows how to make requests to Amazon EC2:

In your HTML file:

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

In your JavaScript file:

var ec2 = new AWS.EC2({region: 'us-west-2'});

ec2.describeInstances(function(err, data) {
  if (err) {
    console.log(err);
  } else {
    data.Reservations.forEach(function(reservation) {
      reservation.Instances.forEach(function(instance) {
        console.log(instance.InstanceId);
      });
    });
  }
});

With Amazon EC2 support for CORS requests, you can now build rich two-tier web applications to manage your instances, VPCs, and more using the AWS SDK for JavaScript in the Browser. Check out our API documentation for details about how to use the API.

We hope you are excited to use use the Amazon EC2 API directly from the browser. We’re eager to know what you think, so leave us a comment or tweet about it @awsforjs.