AWS Mobile Blog

React serverless starter application with one-click AWS deployment and hosting

Serverless applications are more popular every day. Many developers want to implement completely serverless hosted websites that are functionally equivalent to traditional infrastructures. However, with serverless websites, it’s often tricky to deal with registration, sign-in, and MFA flows. It can also be difficult to manage API routing, CORS settings, endpoint authorization, and user authentication. Hooking all of these features together with a hosting solution and global CDN takes extra time for features that are standard for business applications today.

We’ve recently been blogging about building applications with React and using them in conjunction with the Hosting and Streaming AWS Mobile Hub features. Today, we are announcing a couple of additions to this solution set.

First, we’ve enhanced the Cloud Logic functionality in a Mobile Hub project so that new projects launched via Import can include a custom AWS Lambda function. The import can also configure more settings such as CORS for Amazon API Gateway or Lambda environment variables.

Second we are releasing a ReactJS starter project on GitHub to demonstrate these capabilities. The sample can be run with a single click, using the new Deploy from GitHub button capabilities of Mobile Hub. After it is deployed, you can run the sample locally with a webpack server. You can also deploy it as an Amazon S3 hosted static site with an Amazon CloudFront origin. The sample is optimized for mobile devices, which enables you to view the app from your phone or desktop browser. You can register users in the system and log user in with SMS-based MFA. After they are signed in, users can insert sample data for “BBQ Restaurants” and view all restaurants in the system. They can then navigate to see everything on the menu and place an order. The sample also demonstrates using forgotten password workflows.

In the sample, the import functionality automatically configures the following:

  • Amazon Cognito User Pools and Federated Identities
  • Amazon API Gateway, AWS Lambda, and Amazon DynamoDB
  • Cross-origin resource sharing (CORS) for the API
  • IAM roles and policy for the Lambda execution role
  • IAM roles and policy for the user roles that access API routes after authentication

You can find the sample demonstrating this functionality here. The repository describes the steps to get the sample running, and describes how to use portions of the sample in your own application and customizations. In this blog post, we dive into a few details.

Prerequisites

To get the sample running quickly you need:

Installation

Clone the GitHub repository and use the Deploy to Mobile Hub button on the page.

After the deployment is complete, click Hosting and Streaming in the Mobile Hub console. At the bottom of the page, download the aws-exports.js file into the ./aws-mobile-react-sample/client/src/configuration folder of your cloned repo.

Use the following commands to run the application:


npm install
npm start

Walkthrough of the application

After the application is running you will see a page with a Login or SignUp Now button. Click SignUp Now to register a new user in the system.

An SMS confirmation code is sent to the phone number you provide. You must provide the phone number to complete the registration process. The confirmation code redirects you to the home screen, where you enter the username and password and then click Login.

You will recieve another confirmation code. This is the MFA code for logging in the user. Enter the code in the screen to complete the login process.

Now that you’re in the application, click Insert Restaurants to load data into the system. Behind the scenes, this invokes Amazon API Gateway, using the valid user credentials from Amazon Cognito. The API is configured to route the request to AWS Lambda, which is running Express using AWS Serverless Express. A route is configured to initialize data, which inserts sample data into Amazon DynamoDB.

Next click List Restaurants. The restaurants that were added into DynamoDB appear

Click any of the restaurants to see a menu. Place an order by clicking the Order button next to an item.

To see the current order, click Orders in the navigation bar. Two records display immediately and two other records display momentarily. This is to demonstrate persisting data in local storage for rendering versus returning a response from a network call.

You can also package and deploy the app by running:

npm run build

The build uses webpack to produce a bundle that can be uploaded to the S3 bucket created by the import. The output will be in ./aws-mobile-react-sample/client/build.

You can use the AWS CLI to upload the contents of this directory to the bucket. This process is described on GitHub. You can also use the Manage Files function in the Hosting and Streaming page of the Mobile Hub console.

After you upload the contents of the build directory, click either View from S3 or View from CloudFront to see your deployed erverless website.

Customization

The GitHub repository covers some advanced scenarios for modifying this sample or using pieces of it in your own React application. Some of these scenarios are as follows:

  • Using the registration and login components with Amazon Cognito for your application.
  • Using the REST client to make signed, authenticated requests to Amazon API Gatway.
  • Using the REST client to make unauthenticated requests to Amazon API Gateway or generic HTTP resources.
  • Modifying the Express routes in AWS Lambda to perform different operations against Amazon DynamoDB, and calling these routes from the client application.

You can also modify the import process to fit your needs and include this in your own GitHub repository with a one-click button. If you open the ./aws-mobile-react-sample/backend/import_mobilehub directory in the repository and unzip react-sample.zip, you will find the following:

  • lambda-archive.zip
  • mobile-hub-project.yml

The lambda-archive.zip is the pre-built Lambda function, which you can use on import. This must follow the Lambda deployment process described in the AWS Lambda Developer Guide. We also include these steps in the Advanced section of the repository.

If you edit mobile-hub-project.yml you’ll notice some other interesting things that are now available for you to configure with project imports.

UPLOADS

The uploads section determines the custom AWS Lambda function that you can provide during an import. In our sample we use lambda-archive.zip, which was created from the files in the ./aws-mobile-react-sample/backend/lambda directory. The YAML section should also specify the target bucket as follows:

uploads:
  - !com.amazonaws.mobilehub.v0.Upload
    fileName: lambda-archive.zip
    targetS3Bucket: deployments

CLOUD LOGIC

In the same YAML file, you’ll notice the cloudlogic section. This contains everything you need to configure a custom AWS Lambda function and related settings as well as setting up your Amazon API Gatway API. You can configure things such as enabling CORS on the API or only allowing authenticated and authorized users access to invoke the API. This sample YAML demonstrates using Amazon Cognito to access the Amazon API Gateway API and configuring environment variables for your custom AWS Lambda function. You’ll also see controls such as runtime for your NodeJS version and handler which is the name of the file entry point for your code.

You can use ___DYNAMIC_PREFIX___-statictext in the enviornment variables configuration. This is beneficial for resources such as Amazon DynamoDB tables, which are generated at the time of import, Mobile Hub performs the appropriate substitutions after resource creation.

The YAML section should look like the following:

features:
  cloudlogic: !com.amazonaws.mobilehub.v0.CloudLogic
    components:
      ReactSample: !com.amazonaws.mobilehub.v0.API
        attributes:
          name: ReactSample
          requires-signin: true
        paths:
          /items: !com.amazonaws.mobilehub.v0.Function
            name: ReactSample
            codeFilename: uploads/lambda-archive.zip
            handler: lambda.handler
            enableCORS: true
            runtime: nodejs6.10
            environment:
              MENU_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_menu_item
              ORDERS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_orders
              RESTAURANTS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_restaurants
          "/items/{proxy+}": !com.amazonaws.mobilehub.v0.Function
            name: ReactSample
            codeFilename: uploads/lambda-archive.zip
            handler: lambda.handler
            enableCORS: true
            runtime: nodejs6.10
            environment:
              MENU_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_menu_item
              ORDERS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_orders
              RESTAURANTS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_restaurants

 

The Mobile Hub import process also prepopulates some Environment Variables in the Lambda configuration:

  • MOBILE_HUB_DYNAMIC_PREFIX
  • MOBILE_HUB_PROJECT_ID
  • MOBILE_HUB_PROJECT_NAME
  • MOBILE_HUB_PROJECT_REGION

As a usage example, you could re-write the Lambda code in the starter application to reference these like so:


const MENU_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_menu_item`;
const ORDERS_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_orders`;
const RESTAURANTS_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_restaurants `;

You could also use these prepopulated variables for other utility purposes.

Wrapping up

We’re excited to bring you these capabilities. We hope that they accelerate your next serverless website or React project using AWS. Let us know in the GitHub issues section of the repository if you have any feedback or requests.

Deploying an EmberJS mobile web application with Mobile Hub

by Dennis Hills | on | Permalink | Comments |  Share

This post was authored by Michael Labieniec, AWS Sr. Solutions Architect.

AWS Serverless Architecture

Ember.js is a popular open source JavaScript framework for developing rich, dynamic web applications. It supports dependancy injection model and has been a is a stable contender in the JavaScript community. Ember.js also ships with its own CLI which supports building, testing, and deploying your applications. The Ember CLI supports installing plugins and the bundling of those plugins within your application, it has a built in web server to serve your application locally.

AWS Mobile Hub is an AWS service that guides you through feature selection and configuration, it automatically provisions the AWS services required. Mobile Hub generates working code that helps you integrate the AWS SDK for JavaScript with your application in minutes. When using Mobile Hub to develop JavaScript-based applications, JavaScript configuration files as well as a sample web application are generated for you, and placed in your Amazon S3 bucket. These configuration files can then be copied directly to your application environment for use. The files can be continuously updated when your AWS environment changes via Mobile Hub. This is useful for developing JavaScript web applications because your AWS configuration can be dynamically updated by Mobile Hub and your application can immediately realize and support those updates when hosted in Amazon S3.

Mobile Hub will copy a new aws-config.js and aws-exports.js to the Amazon S3 bucket associated with your application after you update your configuration. In order to utilize these in your local development environment, you need to download them from your S3 bucket. The files will be copied to the root of the S3 bucket, which may require you to copy them elsewhere for your application to properly include them.

Amazon Cognito lets you add user sign-up and sign-in to your mobile and web applications. This sample application uses Cognito User Pools for user management and storage, and Amazon Cognito Federated Identities for authentication the user pool. The application then uses Amazon DynamoDB directly through the AWS SDK for JavaScript. The sample application uses a custom Ember.js Adapter to abstract the API logic and allow utilization of Ember.js Models.

First, clone the repository and install the dependencies:

git clone https://github.com/awslabs/aws-mobilehub-ember
cd aws-mobilehub-ember && npm install

Then, click the following button to import the MobileHub.zip file and create the AWS back-end:

Alternatively you can download the .zip file from the GitHub repository and from the Mobile Hub console click Import your project and drag and drop the .zip file to create a new project.

After the import is complete the AWS environment is ready. Click Hosting and Streaming, and then click Download aws-config.js file. Copy the aws-config.js file to the ./vendor/aws-config.js directory of your application.

You can also download the file with the AWS CLI. You first need to know the Amazon S3 hosting bucket. You can see the bucket name by going to Resources from within you Mobile Hub project. Then from within the root directory of your application project run:

aws s3 cp s3://your-hosting-bucket/aws-config.js ./vendor/aws-config.js

If you don’t already have the Ember CLI installed run the following:

npm install -g ember-cli

Now that the aws-config.js file is copied to your vendor directory, run the following:

ember serve

Your application should now be available at localhost:4200. If you ever change your AWS Mobile Hub configuration, simply cp the configuration file again and deploy.

To retrieve the generated S3 bucket name for the cli commands, navigate to your project in the Mobile Hub console, click Hosting and Streaming, and then click Manage Files. Note the bucket name at the top of the screen.

To deploy your web application to Amazon S3, run the following:

ember build 
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Your web application is now available at the web hosting URL of the Amazon S3 bucket that Mobile Hub generated. To view your application:

  1. Goto Mobile Hub and click Hosting and Streaming
  2. Click View from S3

After about a minute, the file changes you pushed propagate to the CloudFront distribution. You can click View from CloudFront and browse the site from a CDN for faster performance. You can force this refresh to happen immediately from the Hosting and Streaming page:

  1. Click Edit your CDN distribution
  2. Click the Invalidations tab
  3. Select Create Invalidation and enter an asterisk (*) to refresh all the content

After the process completes, click View from CloudFront in the Hosting and Streaming section of Mobile Hub.

Making changes

We detail the application architecture at the end of this blog post. You can change parts of the application to meet your needs. Each time you deploy the application you must build and copy to Amazon S3, as follows:

ember build
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Then either wait for a CloudFront distribution refresh or force one with an invalidation.

Walking through the sample

The Ember sample is a TODO or “notes” application. It walks through functionality for registering user accounts into your application (including email confirmation), login and logout functionality, session information and saving notes to a database. To demonstrate, first select Create User to register a new user account in the system. Enter the following:

  1. Unique username
  2. Complex password
  3. Valid email address

This process registers a user in the system with Amazon Cognito User Pools. A registration confirmation code is sent to the email address. Type that code in the page and select Confirm Registration at the bottom. The workflow for this sample allows you to immediately press Login with the previously entered credentials to access the application.

In the main page create a new note by clicking the plus sign (+) in the lower right corner. Type a title for the note and some content. Click Save Note, your data is written to Amazon DynamoDB. These notes are secured where only the users who create them can read or edit them after logging in.

Select the user’s name in the upper right corner of the page. Here you see information about the user session, such as JWT token details from Amazon Cognito User Pools. This is a great place to store user-specific attributes that can be read-only or editable by the user. Click User Attributes on the left side to view your email address.

Application Anatomy

Now that the sample application is up and running we dive a little deeper and explain the structure of an Ember application. You can incorporate pieces of the sample into your own projects.

There are two types of initializers in Ember: application initializers and application instance initializers.

Application initializers while your application boots and have no access to internal services. The application initializer performs a dependency injection process to ensure that everything your application needs is setup before loading UI or user state. This is also great for security control and separation of concerns in your application architecture.

Application instance initializers run while the application instance itself loads. This provides a way to configure the initial state of the application and inject values into application services. For example you can customize the UI based on a theme for users and control state.

Application Initializers

This application uses both types of initializers. The initializers allow us to initialize the AWS SDK for JavaScript before the application instance loads. The instance initializer allows us to inject values into services. We also use the deferReadiness and advanceReadiness in the application initializer to defer loading of the application until we have temporary credentials for making AWS API calls. The main application initializer is located in the app/initializers directory, as follows:

app/initializers/aws.js

To generate an initilizer runember g initializer myInitializer. This creates a new initializer .js file named app/initializers/myInitializer.js. It also create a unit test in tests/unit/initializers/myInitializer.js.

The AWS initializer instantiates the AWS SDK using the variables that are instantiated in the configuration file that Mobile Hub generated. This file was copied from your Amazon S3 bucket. Then, the initializer checks if there is a current session with Amazon Cognito User Pools. It retrieves temporary SDK credentials. The initializer uses these credentials to make AWS API calls with the SDK. The initializer then registers values for the application to use, and finally advanceReadiness to continue loading the application instance.

The initializer determines if there is a logged in user with the Amazon Cognito Identity SDK (included in ./vendor/amazon-cognito). If a session exists, register the session credentials and JWT tokens on the application instance. These are injected by the instance initializer.

Application Instance Initializers

The instance initializer is located in the instance-initializers directory, as shown next:

app/instance-initializers/auth.js

When the instance initializer runs, it has access to application services, as well as access to any values we previously registered within the application initializer.

You can generate instance-initializers with the ember-cli using ember g instance-initializer myInstanceInitializer. This generates a myInstanceInitializer.js in the instance-initializers folder. It also generates a unit test in test/unit/instance-initializers.

The auth instance initializer first retrieves the values registered in the application initializer, as well as the service we have created (app/services/cognito.js). Ember services are referenced using the prefix “service:”. The application-registered values that we registered in the initializer are completely custom (for example “auth:session”). It then injects those dependencies into the applicable service within our instantiated application instance: in this case, our custom cognito service.

Application Components

Within this application we use a service, model, adapter, and serializer to abstract the AWS logic away from the presentation level logic. This allows us to work with data using ember models, while the application adapter and serializer hold AWS-specific back-end logic. This architecture allows us to potentially swap adapters that communicate with different back-ends, or to even load and serialize different types of data (for example JSON vs. XML responses). The serializer takes whatever is retrieved via the adapter and serializes it to a uniform format (based on the extended ember class) for our routes and components to use.

Models, Adapters, and Serializers

The note adapter in this application is specifically tied to the note model, and note serializer. Ember uses this file-level naming convention to determine which components work together. For example, the note model utilizes the note adapter and serializer if the similarly named .js files are found in app/serializers or app/adapters. You can also define an “application” adapter and serializer which serves as a catch-all for any model actions.

You can generate a model by running ember g model myModel, which does not generate an adapter or serializer. You can generate these with ember g serializer|adapter. As long as you name them appropriately, they will are used. Otherwise, the model uses an application adapter or serializer if you generated one.

Data is initially requested via the note route. This route provides the result from the adapters call, serialized, to the Ember component, which in this case is directly used within the view. This model.notes dataset is then sent into the ui-note-list component for use within the view component.

Components and Controllers

Components are custom elements that align with the W3C Custom Elements spec and contain de-coupled view logic.

Components can reference and call methods on the higher level component or controller that instantiated the component. This abstracts away the model or data level logic, making the component more dynamic and re-usable. Components should never work with models or data. They should work with specific view logic and the data that is provided to them, allowing the components to be more de-coupled and re-usable. Components can also work with services directly.

Components can be generated via the ember-cli ember g component myComponent. This creates an app/components/my-component.js logic file, and an app/templates/components/my-component.hbs view template. Since Ember components adhere to the W3C Custom Elements spec, they require a “-” in their name.

To learn more about developing with Ember, see Guides and Tutorials on the Ember website.

Wrapping up

Using the Hosting and Streaming features of Mobile Hub is a great way to quickly provision a fully functioning back-end for your mobile web application. The application includes end-to-end functionality, including user life-cycle and application state. Using the provided sample should help you get started with building an Ember application. You can make changes to this application and get your site running quickly. You can also use the sample and the Deploy from GitHub Button, like this repository shows, to fork this application and create your own version. Others can use your version to quickly spin up a fully functioning back-ends.

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

Source Code and Issues on GitHub
github.com/awslabs/aws-mobilehub-ember

Take Your Chatbot Mobile!

With Amazon Lex, any developer can quickly and easily create a chatbot. With AWS Mobile Hub, the same developer can just as easily integrate the bot into a mobile app.

Want to take your bot mobile? Use the Mobile Hub conversational bots feature to create your own mobile bot or import an existing bot into your mobile app. You can build, test, and publish your mobile bot in minutes. No deep learning expertise needed.

How does integration work? Integrate your bot into a fully native mobile app by using a sample bot template or by importing an existing Amazon Lex chatbot into Mobile Hub. Mobile Hub generates a fully functional mobile iOS or Android app, integrated with your bot. The sample mobile app provides the option to interact with your bot with voice or text, and includes built-in authentication provided by Amazon Cognito.

How do I do it?
Here’s how simple it is:

  1. Use Amazon Lex to build a bot or choose from one of the sample bots in Mobile Hub.
  2. Import your bot into Mobile Hub using the conversational bots feature.
  3. Download the generated iOS/Android project code.
  4. Launch your mobile app and start a conversation!

Want to see how others have done it?

The Kelley Blue Book team created their voice-enabled mobile application using Amazon Lex and Mobile Hub. Their bot allows users to interact with their vehicle API using natural spoken language. A simple inquiry like, “Kelley Blue Book, can you tell me the trade-in value for my 2012 Honda Civic?” gets expert car advice from an industry-leading automotive company.

To learn more about The Kelley Blue Book Bot and building your own mobile chatbot, see the post on the AWS AI blog.

We can’t wait to see what you can build with AWS Mobile Hub and Amazon Lex!

Testing Mobile Apps: A Primer

Why should you test your mobile app?  A recent study showed that almost a quarter of users only use a mobile app once, and a shocking 95% abandon an app within the first month.  Some of the reasons that users abandon an app are due to content and engagement.  The biggest non-content reasons for abandonment are application crashes and security concerns.  No one can prevent all application crashes.  The mobile ecosystem is too broad and unpredictable to provide a 100% guarantee.  However, testing ensures that your mobile app has been stressed on as many devices as possible , which enables you to identify and fix bugs early.

Types of mobile testing

There are seven types of scenarios that you should consider when testing a client-server application such as a mobile app:

  • Unit testing
  • UI testing
  • Fuzz testing
  • Performance testing
  • End-to-end testing
  • Pre-production testing
  • Canary (post-production) testing

Tests are organized into test suites – sets of tests that together test the entire functionality of your app.  Let’s look at each of these types.

Unit testing

Unit testing tests individual parts of your code for correctness, usually using an automated test suite.  A good unit test assures you that the functionality that you are expecting out of the unit (your code; usually a single method) is correct.  A good unit test is:

  • Repeatable – you can run it several times and it produces the same result.
  • Fast – you don’t want it to interrupt the flow of your work.
  • Readable – you can understand what the test is doing.
  • Independent – you can run a single test from a suite.
  • Comprehensive – you have enough tests to test all the main cases and corner cases of inputs and cover all code paths.

A good unit test suite augments the developer documentation for your app. This helps new developers come up to speed by describing the functionality of specific methods.  When coupled with good code coverage, a unit test acts as a safeguard against regressions.  Unit tests are important for anything that does not produce a UI.  For example, consider a Notes app that has a set of notes stored in a SQLite database on a mobile device. For this app, there is a class that accesses the notes and a set of classes that implement the UI.  The class that accesses the notes has unit tests.

Each platform has its own unit testing framework:

Each of these frameworks supports all of the features you need to start testing, including support for async functionality (a common pattern in mobile apps).   Each testing framework has its own appearance, but in essence all testing frameworks operate the same.  You specify some inputs, call the method to test, and then verify that the output is what you expect it to be.

UI testing

UI testing takes a flow that the user might follow and ensures it produces the right output.  It can be done on real devices or on emulators and simulators.  Given the same state (including backing stores and starting point), the UI test always produces the same output.  A UI test can be considered similar to a unit test. The input to the test is the user clicks and the output of the test is the screen.  UI testing is more closely associated with the device than with the platform language.  There is a preferred testing framework and each framework has a test recorder. This enables you to record a UI flow on one device and then replay the test on many other devices.  The test recorder allows you to get productive quickly:

In addition, there are cross-platform UI test frameworks to consider, primarily Appium and Calabash.  With Appium, you can choose a language. This is useful if you are writing Ionic or React Native apps because you can use JavaScript as the testing language.  Calabash requires that the tests are written in Ruby.  Neither of these frameworks provide a recorder to aid in writing tests.  Both frameworks are open source projects.

Finally, AWS Device Farm has a feature called Explorer for Android apps.  This feature investigates your UI and finds things to interact with.  When it finds a control, it interacts with the control.  This feature works with login screens, allowing you to validate authenticated sessions as well.

Ionic and React Native perform UI testing against compiled code, so your UI tests should not include Ionic or React Native code.  Instead, you are testing how the app acts on a device.

Fuzz testing

Unit tests and UI tests are used to ensure that the expected output happens when the expected input is used.  However, apps are used by humans and humans don’t always do the expected thing.  For that case, you can introduce a random stream of events into your app and see what happens.  This is known as monkey testing or fuzz testing. It’s a stress test that simulates what happens when the user randomly presses the screen, for example.  This is similar to a UI test.  However, you don’t need to write any tests since random events are created.

It is also interesting to record a fuzz test run.  It can be replayed later to reproduce any issue found, verify that the issue was fixed, and to scale testing across more devices.  Fuzz testing takes off when you take testing to the cloud with AWS Device Farm, allowing you to test on many more devices than you may have access to.

Performance testing

Gather performance metrics while running the UI and fuzz tests to ensure that your application does not take up significant resources on the device.  Such performance metrics include:

  • Battery drain and energy usage.
  • Appropriate usage of the GPS and other features that drain battery.
  • Network bandwidth usage.
  • Memory usage.

This data can be gathered during development using a profiling tool such as the Android Monitor (built into Android Studio) or Instruments (built into XCode).  During this process, you can also use network shaping, which simulates lower bandwidth network connections (for example, 3G connections) or spotty Wi-Fi connections.  This enables you to experience adverse network conditions as your users would and ensure an appropriate user experience.  If you are developing a mobile game, you can also measure the FPS (frames per second) for your mobile game when the device is stressed (low memory or restricted network capabilities).

For performance testing during the test phase (and beyond), use application performance monitoring (APM) tools such as New Relic Mobile or Splunk MINT.

Integration (end-to-end) testing

After you test your mobile app in isolation, you test it with a mobile backend. This is generally known as integration testing or end-to-end testing.  Take the same UI and fuzz testing that we already described, and then recompile your code with the live cloud backend.  Many organizations produce a separate test environment for this purpose.

If you are upgrading the mobile app (rather than releasing a new app) and the upgrade involves an upgrade to the backend resources – the database schema or API responses – then you also should test the upgrade scenarios during integration testing.  Users do not upgrade their mobile apps immediately, so multiple versions of your app will use the same cloud backend resources (even if only the database is affected).

If you are using a third-party cloud service (for example, a Weather API), then make sure you check their rules for throttling.  Test failures can result if the third-party cloud service detects you are making too many API calls.

Pre-launch or pre-submission testing

You are just about to launch your app to the public.  You’ve done all the appropriate testing on the latest devices and OS versions.  Run the UI and fuzz tests on as wide a pool of devices as you possibly can.  There is one final test before submitting your app to the app store.  You want to test your app on as large a community of devices and OS combinations as you possibly can.

An enterprise usually has the luxury of dictating a support matrix of devices. If you are producing a mobile app for the general public, then the situation is a little more complex.  OpenSignal estimates that there are over 24,000 distinct Android devices in the world. Over 18,000 of these were used in the last year.  The statistics from Google indicate that API level 19 (which is a few years old at this point) has only reached 73% of consumers. The iOS device types are a little more limited – there are only a handful of models, and iOS devices tend to be kept up to date.  That’s still numerous device / OS combinations.

One option is to maintain a device farm of your own, buying one of each device.  However, that is expensive to buy and maintain. A better option is to rent the devices you need for the pre-production run and let someone else worry about maintaining the latest device and OS versions. AWS Device Farm helps with this problem as well, running your UI and fuzz tests across a wide variety of devices and charging only for what you use.

Canary (post-production) testing

After your app is in production, use a canary test to ensure that the mobile app and the backend are running harmoniously. A canary test is a set of UI tests that run using the same mobile app that you distributed to your users and using the same (production) services on the backend.

You can generate a (different, smaller) test suite for an individual (canary) user and run this test suite on AWS Device Farm on a schedule to implement canary testing.

Best practices in testing

You don’t need to run all tests all the time.  The following are some best practices:

  • Architect your application so that the mobile application and backend can be tested independently.  Compile your app with “stub” methods that simulate the cloud services.  Also, try mock cloud services with frameworks like Mockito (Android) or Cuckoo (Swift).
  • All changes to the code base of your mobile app or backend should include appropriate unit tests or UI tests to check the new functionality.
  • Run unit tests with every build and UI tests on an emulator or simulator before checking in your code change.
  • Run a complete set of UI and fuzz tests on a pre-defined set of the most popular devices for your users on a regular basis. It is ideal to do this as part of a continuous integration pipeline (for example, using Jenkins). At minimum, you should run these tests on a nightly basis.  Monitor for application crashes and test failures.
  • Run your UI tests on as many devices as possible at intervals throughout the development process. At minimum, run a full set of tests on as many devices as possible before release.  Any test failures or application crashes should generate bugs to be fixed by the engineers.
  • Include enough information in your bugs to reproduce the failure. Include the test case, device and OS combination, whether the test was against the cloud services or the stubs, and video or screen captures of the test failure.
  • Analyze the test results.  A single test failure is useful.  Knowing that the same error or crash occurred on a set of devices with a common characteristic is more useful to the developers who need to diagnose the problem.

AWS Device Farm is a mobile app testing service that lets you test and interact with your Android, iOS, and web apps on many devices at once. It enables you to capture video, screenshots, logs, and performance data to pinpoint and fix issues before shipping your app.  You can use it to automate a large portion of the suggested mobile app testing capabilities described in this article.

With these best practices, you are on your way to producing a quality product that can be enjoyed by the maximum number of users.

Integrate the AWS SDK for JavaScript into a React App

In our last blog post, I showed how to create a React app using the create-react-app tool provided by Facebook, and then deploy the app to a content delivery network driven by AWS Mobile Hub, Amazon S3, and Amazon CloudFront. This enables you to produce dynamic single page applications (SPAs) and serve them to a global audience.

Very few web apps are static web sites.  Ideally, you also deploy a serverless backend that includes identity, database, storage, and custom APIs that provide the dynamic data for your SPA. AWS provides this kind of serverless backend. You can compose this backend by using the AWS Mobile Hub console. You still need to integrate the AWS SDK for JavaScript into your SPA. In this post, we walk through that integration.

Add the AWS SDK for JavaScript to your project

The SDK is distributed via the npm package manager. To install the SDK into your project, use the following command:

npm install –save aws-sdk

This downloads the SDK and adds an entry into the package.json file so that the SDK is downloaded automatically when it is needed. In addition, any dependencies for the SDK are downloaded and included in your project.

Download the AWS configuration for your project

In the last article, we showed you how to create an AWS Mobile Hub project and turn on the Hosting and Streaming service. This also generates two files in the Amazon S3 bucket that is created:

  • aws-config.js is used by browser sessions to configure the SDK.
  • aws-exports.js is used by SPA applications that are packed (by Webpack, Browserify, or similar tools) to configure the SDK.

You need the aws-exports.js file for the React app. You can download this file from the Amazon S3 bucket using either the AWS Mobile Hub console or the AWS CLI. To download via the CLI, use the following:

aws s3 cp s3://bucket/aws-exports.js ./src/aws-exports.js

From the AWS Mobile Hub console:

  1. Sign in to the AWS Mobile Hub console.
  2. Choose your project.
  3. Choose Hosting and Streaming.
  4. Click Download aws-exports.js file.

You can (and should) do this before every build. I have included the following in my package.json:

{
	"scripts": {
		"prebuild": "aws s3 cp s3://${S3BUCKET}/aws-exports.js ./src/aws-exports.js",
		"build": "react-scripts build",
		"deploy": "aws s3 cp ./build s3://${S3BUCKET}/ --recursive",
		"start": "react-scripts start",
		"test": "react-scripts test –env=jsdom",
		"eject": "react-scripts eject"
	},
	…
}

Set the S3BUCKET environment variable and build the React app as follows:

# For MacOS or Linux
export S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows cmd
# set S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows PowerShell
# $env:S3BUCKET="reacttestapp-hosting-mobilehub-1234567890"

# Now run the build
npm run build

Integrate the SDK into your app

In each SPA, there is an entry point. The entry point for all apps created by create-react-app is the src/App.js file. The create-react-app tool uses ES2015 modules.  This means we can use the import keyword to bring in the aws-exports.js file:

/*
 * Import the SDK and Project Configuration
 */
import AWS from 'aws-sdk';
import awsmobile from './aws-exports';

/*
 * Configure the SDK to use anonymous identity 
 */
AWS.config.update({
  region: awsmobile.aws_cognito_region,
  credentials: new AWS.CognitoIdentityCredentials({
    IdentityPoolId: awsmobile.aws_cognito_identity_pool_id
  })
});

In this snippet, we import both the SDK and the configuration of the backend, and then automatically create identity credentials for Amazon Cognito based on the configuration. We can also use this to instantiate an Amazon DynamoDB connection or call an Amazon API Gateway REST endpoint using the SDK.

What’s in the aws-exports.js

The aws-exports.js file is a standard JavaScript file that is maintained by AWS Mobile Hub on your behalf. It changes when you add, remove, or edit features within AWS Mobile Hub. An example from one of my apps is below:

// WARNING: DO NOT EDIT. This file is Auto-Generated by AWS Mobile Hub. It will be overwritten.

// Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved.
// Code generated by AWS Mobile Hub. Amazon gives unlimited permission to
// copy, distribute and modify it.

// AWS Mobile Hub Project Constants
const awsmobile = {
aws_app_analytics : 'enable',
aws_cognito_identity_pool_id : 'us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
aws_cognito_region : 'us-east-1',
aws_content_delivery : 'enable',
aws_content_delivery_bucket : 'XXXXXX-hosting-mobilehub-1234567890',
aws_content_delivery_bucket_region : 'us-east-1',
aws_content_delivery_cloudfront : 'enable',
aws_content_delivery_cloudfront_domain : 'XXXXXXXXXXX.cloudfront.net',
aws_mobile_analytics_app_id : 'XXXXXXXXXXXXXXXXXXXXXXX',
aws_project_id : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ',
aws_project_name : 'XXXXXX’,
aws_project_region : 'us-east-1',
aws_resource_name_prefix : 'XXXXXX-mobilehub-1234567890’,
}

export default awsmobile;
var AWS = require('aws-sdk');
AWS.config.region = awsmobile.aws_project_region;
AWS.config.update({customUserAgent: 'MobileHub v0.1'});

This project has the following enabled:

  • Analytics (from the Messaging and Analytics feature)
  • Hosting and Streaming

You can see the appropriate IDs are available through constants that are then exported as a module. You should never edit this file directly. Instead, change the features within your AWS Mobile Hub project and then copy the file to your source code control again.

Best Practices

We consider the following best practices for integrating the SDK:

  1. Always use the latest version of the SDK.
  2. Add the src/aws-exports.js file to your .gitignore (or similar) file. Do not check this file into your source code repository.
  3. Copy the aws-exports.js file from your AWS Mobile Hub project during the build phase of your app.

Now that you know how to integrate the SDK into your app, you can start using the AWS SDK for JavaScript to access your AWS services. In future articles, we will explore adding AWS service access to your React app. Until then, please see the AWS SDK for JavaScript Developer Guide for more details.

Automated Device Testing with AWS Device Farm and Jenkins

A strong indicator of quality of an app is its ability to run on multiple devices of different make, model, and manufacturer consistently and predictably. Incremental development models are at the core of every mobile app development team. Often a seemingly benign feature can be disruptive to the overall user experience and functioning of the app if not thoroughly tested. How do you ensure that every code check-in triggers tests for your mobile app against numerous devices and provides detailed analysis of the results?

Continuous integration (CI) systems have been around for a long time and are now at the core of all DevOps workflows. They integrate build, test, and distribution into one workflow. Many systems to implement CI exist, including cloud solutions like AWS CodePipeline and on-premises solutions like Jenkins. Jenkins is an open source CI solution that is easy to install and portable across all major platforms. It has more than 1000 plugins that integrate with build, test, and distribution components.  This makes Jenkins a popular choice among teams looking for a CI tool for a new project.

AWS Device Farm is an app testing service. You can use it to test and interact with your Android, iOS, and web apps on physical phones and tablets that are hosted by AWS. You can use Device Farm for automated testing with a variety of available testing frameworks. You can also use it for manual testing through a remote session.

Today, AWS Device Farm announced the availability of a Jenkins plugin for AWS Device Farm.  The Jenkins plugin enables you to integrate device testing into your CI workflow.

Prepare your AWS account so that Jenkins can access Device Farm resources:

  1. Sign in to the IAM console.
  2. Create or modify an IAM policy so that your Jenkins instance has access to AWS Device Farm.
  3. Create a user for your Jenkins master (with programmatic access) and assign the user to the IAM policy you just created.
  4. Note the access key ID and secret access key. You need them later.

Add the Jenkins plugin to your Jenkins master:

  1. Sign in to your Jenkins web UI.
  2. Click Manage Jenkins > Manage Plugins on the left side of the screen.
  3. Click the Available tab.
  4. Type aws-device-farm in the search box.
  5. Click Install without restart.
  6. After the installation is complete, click Manage Jenkins > Configure System.
  7. Scroll to the AWS Device Farm header.
  8. Paste the access key ID and secret access key into the appropriate boxes.
  9. Click Save.

You can also use the Jenkins CLI to manage plugins.  Now that the Jenkins plugin for AWS Device Farm is available on your Jenkins master, you can use it in a workflow:

  1. Select the project for which you want to set up the plugin.
  2. Add a post-build step: Run Tests on AWS Device Farm.
  3. Configure any options you want for the run. At minimum, select the UI tests that you want to run and the devices you want to run those tests on.
  4. Save the changes for the project.

AWS Device Farm supports major testing frameworks such as Espresso, XCTest UI, Appium, and Calabash.

After a build and test flow is complete, you can see the results of the tests:

Integrating AWS Device Farm into your automated build pipeline enables you to test your mobile applications on more devices, producing a better quality mobile app.  As always, we want to hear from you.  If you have suggestions or issues, let us know on the AWS Forums.

Deploy a React App to S3 and CloudFront with AWS Mobile Hub

Single page applications (SPAs) are now ubiquitous. Every web developer needs to understand how to build them and how to deploy them to a web hosting facility of their choice. In this article, I am going to look at what it takes to create and build a basic React app and deploy it globally to the AWS Cloud.

Before you start, you need to create a suitable cloud environment for your app. This is shown in the following architectural diagram.

All users of your app will load the single page application resources (which are all static resources) from Amazon CloudFront, which provides a global set of edge caching services. CloudFront is a caching facility –the resources it caches are from an Amazon S3 bucket. This ensures that the application is provided securely and efficiently across the globe. Amazon Route 53 provides DNS services so your service has the right name.

Prepare your development workstation

To create and deploy React applications to AWS, you need the following:

After you install and configure the AWS CLI, make sure that you have access to your AWS account via the CLI before continuing.

Create the cloud backend

Use AWS Mobile Hub to create this architecture.

  1. Sign in to the AWS Mobile Hub console.
  2. Create a project.
  3. Click Hosting and Streaming.
  4. Check the box to acknowledge the security implications, and then click Enable.

Ensure you read about the security implications of the Hosting and Streaming feature. The service creates an Amazon S3 bucket and an Amazon CloudFront distribution for you. Make a note of the Amazon S3 bucket; you need this later.

(Optional) Create a domain name for your app

The default name for your app is a little cryptic. In the picture above, you can see the URL in the CloudFront section. Amazon Route 53 can be used to give your application a more friendly URL. For details on how to accomplish this, see the Amazon Route 53 Developer Guide.

Create a React application

There are many ways to create a React application. You can integrate the components yourself, use a Yeoman generator, or use one of the many templates available. My favorite mechanism is to use create-react-app. To install create-react-app, type the following at the command line:

npm install -g create-react-app

After you install the tool, run create-react-app on the command line. Change directory to a working directory and type the following:

create-react-app test-app
cd test-app
npm install
npm start

This starts the application on your local machine. A browser starts and your application loads. Changes to the source code are then reflected in the browser. For more information on writing a React app, see the React tutorial and documentation. This is just the starting point and a great place to begin your exploration of React.

Deploy the React application to your AWS project

Deploying to your AWS project is a two-step process. First, build the deployable artifacts for your project by running the following command:

npm run build

Next, copy the deployable artifacts to your S3 bucket by running the following command:

aws s3 cp build s3://<your-s3-bucket-name> --recursive

Replace <your-s3-bucket-name> with the name of your S3 bucket.  You can add this command to the scripts section of the package.json file.  For example, the scripts section for my package.json looks like this:

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "predeploy": "react-scripts build",
    "deploy": "aws cp build s3://my-s3-bucket --recursive",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }

Only users who have access to the S3 bucket can run this script.  The AWS CLI credentials are separate from your application code.  However, you can place the S3 bucket name in an environment variable and use the environment variable instead of the specific name in your package.json file.  This ensures that your package.json file does not contain specific references to your AWS resources and that the project can be shared between multiple developers.

After the process is complete, you can browse to your S3 bucket to see your app deployed.   By default, your files are available on the CloudFront edge cache servers within an hour.  If you have a production app, you can also invalidate the contents of the CloudFront edge cache servers.   The URL of the CloudFront edge cache servers is displayed on the Hosting and Streaming feature page in AWS Mobile Hub.

The CloudFront CLI is currently in preview. You can enable it by running the following command:

aws configure set preview.cloudfront true

After you configure the preview feature, list the distributions.  On macOS, you can run the following:

aws cloudfront list-distributions | grep d21o

Replace d21o with enough of the URL for your CloudFront distribution to uniquely identify it.  I don’t have that many CloudFront distributions, so using the first few characters is enough to limit the output to just 1 line:

The highlighted text is the distribution ID associated with the URL.  I can create an invalidation as follows:

aws cloudfront create-invalidation --distribution-id <distribution-id> --paths /\*

I need to quote the wildcard character.  If I do not properly quote the *, the shell expands it to all the files in the directory.  This is definitely not what you want.  You can monitor the invalidation by running the following command:

aws cloudfront list-invalidations --distribution-id <distribution-id>

Best Practices

When working with any architecture, there are inevitably some best practices to discuss.  Content delivery networks are no different.  The best practice that you should definitely follow is to ensure you version each file.  The easiest way to do this is to use a task runner automation tool (broccoli, grunt, or gulp) for the distribution.  Use the version from the package.json file as part of the directory so that your build directory is copied to a new directory each time it is built.  When you deploy, you can adjust the version that is distributed to your end users by running the following command:

aws cloudfront update-distribution --id <distribution-id> --default-root-object 0.0.2/index.html

For example, if you are using gulp and have a Gulpfile.js, you can include the following task:

const gulp = require('gulp');
const exec = require('child_process').exec;
const version = require('./package.json').version;

// Make sure you assign your distribution ID here
const distributionid = '<your-distribution-id>'
gulp.task('update-cloudfront', (cb) => {
    const cmd = 'aws cloudfront update-distribution';
    exec(`${cmd} --id ${distributionid} --default-root-object ${version}/index.html`, cb);
});

Call the update-cloudfront task as the last task in the deployment pipeline to do the adjustment.  You can get the distribution ID programatically from a file.

There are many plugins for the task runners to handle AWS resources.  These can be used as an aid to produce an automated workflow for deploying from your web development workflow.

Wrap up

Now that you have a React app running within the AWS Cloud, you can use AWS Cloud features within your app.  In future blog posts, I’ll describe how to use AWS Cloud features in your React application.

Using Amazon DynamoDB Document API with the AWS Mobile SDK for Android – Part 2

In the first part of this blog, we introduced you to the Amazon DynamoDB Document API. This API is a mechanism for accessing data in DynamoDB that doesn’t require you to map models to the data. Instead, you access the data through standard accessor methods on a standard Document object. In this blog post, we show how to integrate this functionality into a real application. The application for this demonstration is an Android memo app. The mobile backend architecture for the app is shown in the following diagram.

The services used are:

This infrastructure can be easily set up using AWS Mobile Hub.  Either click the Deploy to AWS Mobile Hub button in our GitHub repository or follow these instructions:

  1. Click Create a new Project in the AWS Mobile Hub console.  Provide a name for your project.
  2. Click NoSQL Database.
  3. Click Enable NoSQL.
  4. Click Add a new table.
  5. Click Start with an example schema.
  6. Select Notes as the example schema.
  7. Select Public for the permissions (we won’t add sign-in code to this app).
  8. Click Create Table, and then click Create Table in the dialog box.

Even though the table you created has a userID, the data is stored unauthenticated in this example. If you were to use this app in production, use Amazon Cognito to sign the user in to your app, and then use the userID to store the authenticated data.

In the left navigation pane, click Resources. AWS Mobile Hub created an Amazon Cognito identity pool, an IAM role, and a DynamoDB database for your project. Mobile Hub also linked the three resources according to the permissions you selected when you created the table. For this demo, you need the following information:

  • The Amazon Cognito identity pool ID (for example, us-east-1:f9d582af-51f9-4db3-8e36-7bdf25f4ee07)
  • The name of the Notes table (for example, androidmemoapp-mobilehub-1932532734-Notes)

These are stored in the application code and used when connecting to the database.

Now that you have a mobile app backend, it’s time to look at the frontend. We have a memo app that you can download from GitHub. First, add the required libraries to the dependencies section of the application build.gradle file:

compile 'com.amazonaws:aws-android-sdk-core:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb-document:2.4.4'

Add the INTERNET, ACCESS_NETWORK_STATE, and ACCESS_WIFI_STATE permissions to AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Set up the connection to the Amazon DynamoDB table by creating an Amazon Cognito credentials provider (for appropriate access permissions), and then creating a DynamoDbClient object. Finally, create a table reference:

// Create a new credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
        context, COGNITO_POOL_ID, COGNITO_REGION);

// Create a connection to DynamoDB
dbClient = new AmazonDynamoDBClient(credentialsProvider);

// Create a table reference
dbTable = Table.loadTable(dbClient, DYNAMODB_TABLE);

You can now perform CRUD (Create, Read, Update, Delete) operations on the table:

/**
 * create a new memo in the database
 * @param memo the memo to create
 */
public void create(Document memo) {
    if (!memo.containsKey("userId")) {
        memo.put("userId", credentialsProvider.getCachedIdentityId());
    }
    if (!memo.containsKey("noteId")) {
        memo.put("noteId", UUID.randomUUID().toString());
    }
    if (!memo.containsKey("creationDate")) {
        memo.put("creationDate", System.currentTimeMillis());
    }
    dbTable.putItem(memo);
}

/**
 * Update an existing memo in the database
 * @param memo the memo to save
 */
public void update(Document memo) {
    Document document = dbTable.updateItem(memo, new UpdateItemOperationConfig().withReturnValues(ReturnValue.ALL_NEW));
}

/**
 * Delete an existing memo in the database
 * @param memo the memo to delete
 */
public void delete(Document memo) {
    dbTable.deleteItem(
        memo.get("userId").asPrimitive(),   // The Partition Key
        memo.get("noteId").asPrimitive());  // The Hash Key
}

/**
 * Retrieve a memo by noteId from the database
 * @param noteId the ID of the note
 * @return the related document
 */
public Document getMemoById(String noteId) {
    return dbTable.getItem(new Primitive(credentialsProvider.getCachedIdentityId()), new Primitive(noteId));
}

/**
 * Retrieve all the memos from the database
 * @return the list of memos
 */
public List<Document> getAllMemos() {
    return dbTable.query(new Primitive(credentialsProvider.getCachedIdentityId())).getAllResults();
}

There are two mechanisms for searching the dataset: scan and query. The query() method uses indexed fields within the DynamoDB table to rapidly retrieve the appropriate information. The scan() method is more flexible. It allows you to search on every field, but it can run into performance issues when searching large amounts of data. This results in a worse experience for your users because data retrieval will be slower. For the best experience, index fields that you intend to search often and use the query() method.

The Notes schema in DynamoDB usually segments data on a per-user basis. The app works with both authenticated and unauthenticated users by using the .getCachedIdentityId() method. This method stores the current user identity with every new note that is created.

Android does not allow you to perform network requests on the main UI thread. You must wrap each operation in an AsyncTask. For example:

/**
 * Async Task to create a new memo into the DynamoDB table
 */
private class CreateItemAsyncTask extends AsyncTask<Document, Void, Void> {
    @Override
    protected Void doInBackground(Document... documents) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(EditActivity.this);
        databaseAccess.create(documents[0]);
        return null;
    }
}

You can initiate a save operation by instantiating the appropriate AsyncTask and then calling .execute():

/**
 * Event Handler called when the Save button is clicked
 * @param view the initiating view
 */
public void onSaveClicked(View view) {
    if (memo == null) {
        Document newMemo = new Document();
        newMemo.put("content", etText.getText().toString());
        CreateItemAsyncTask task = new CreateItemAsyncTask();
        task.execute(newMemo);
    } else {
        memo.put("content", etText.getText().toString());
        UpdateItemAsyncTask task = new UpdateItemAsyncTask();
        task.execute(memo);
    }
    // Finish this activity and return to the prior activity
    this.finish();
}

Similarly, you can retrieve a list of memos on an AsyncTask and pass the memos back to a method in the MainActivity to populate the UI:

/**
 * Async Task for handling the network retrieval of all the memos in DynamoDB
 */
private class GetAllItemsAsyncTask extends AsyncTask<Void, Void, List<Document>> {
    @Override
    protected List<Document> doInBackground(Void... params) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(MainActivity.this);
        return databaseAccess.getAllMemos();
    }

    @Override
    protected void onPostExecute(List<Document> documents) {
        if (documents != null) {
            populateMemoList(documents);
        }
    }
}

You can find this sample in our GitHub repository. To run the sample:

  1. Open the project in Android Studio.
  2. Open the DatabaseAccess.java file.
  3. Replace the temporary string for COGNITO_POOL_ID with your Amazon Cognito Identity Pool ID.
  4. Replace the temporary string for DYNAMODB_TABLE with your Amazon DynamoDB table name.
  5. If necessary, replace the COGNITO_REGION with the region for your Amazon Cognito identity pool ID.
  6. Run the app on a real device or the Android emulator.

If you are successful, the app looks like the following:

The Document API is currently in beta. We would like to hear about the use cases you want us to support. You can leave your feedback and issues on our forums and GitHub.

Deploy to AWS Mobile Hub from your GitHub repository

by Bharath Kumar | on | Permalink | Comments |  Share

AWS Mobile Hub now helps you share your Mobile Hub project configuration template with other developers. With one click, you can import the project configuration from a GitHub repository into the AWS Mobile Hub console and deploy an identical mobile backend. In addition to one-click import, you can export your project configuration, commit to GitHub, and provide your project configuration as a one-click from your GitHub repository.

Importing a shared project configuration from a GitHub repository

Importing a shared project configuration from a GitHub repository

  1. Click the Deploy to AWS Mobile Hub button in the AWS Mobile community discussion GitHub repository. This button imports the shared project configuration to the AWS Mobile Hub console.
  2. You are prompted to sign in if you have not already done so.

Importing a shared project configuration from a GitHub repository

  1. After you sign in, you are prompted to name your imported project. You can accept the default or create your own name.
  2. Click Import project to deploy the backend configuration specified in the imported project configuration file.

Importing a shared project configuration from a GitHub repository

  1. After importing the project, click integrate with my app for the integration instructions. Either download the sample app, which demonstrates each feature, or integrate the AWS Mobile SDK into your own app.

Create a project configuration that can be shared from a GitHub repository

Create a project configuration that can be shared from a GitHub repository

  1. In the AWS Mobile Hub console, hover over the dots in the upper right of the card for the project you want to share.
  2. Select Export(file).
  3. Download the .zip file to your local computer. The .zip file contains a YAML file that has the backend configuration of your exported project.
  4. Check in the .zip file or the YAML file to your GitHub repository.
  5. Add a button to your GitHub repository’s README file with the following information:
<p>
<a target="_blank" href="https://console.aws.amazon.com/mobilehub/home?#/?config=<GITHUB_URL_TO_ZIP_OR_YAML_FILE>">
<span>
    <img height="100%" src="https://s3.amazonaws.com/deploytomh/button-deploy-aws-mh.png"/>
</span>
</a>
</p>
  1. Replace GITHUB_URL_TO_ZIP_OR_YAML_FILE with the actual GitHub URL to the checked-in .zip or YAML file.

Now any developer can import the backend configuration of your exported project from your GitHub repository into the AWS Mobile Hub console and build a mobile application.

For more information, see Cloning, Exporting, and Importing AWS Mobile Hub Projects in the AWS Mobile Hub Developer Guide. As always, feel free to contact us on the AWS Forums if you have questions or issues.

Using Amazon DynamoDB Document API with AWS Mobile SDK for Android – Part 1

The AWS Mobile SDK for Android helps developers write mobile apps by providing simplified APIs for using AWS services, such as Amazon Cognito and Amazon DynamoDB. In the past, to access data, you needed to use the DynamoDB Object Mapper (or use the service APIs). You then had to define a model within your mobile code that mirrors the model defined in the table for DynamoDB. This meant more code to write and test. With v2.4.4 of the SDK, we are introducing a new feature, which we call the Document API. With the Document API, you no longer need to use the DynamoDB Object Mapper; instead, you access individual fields within data objects directly.

What is the difference between the Object Mapper and the Document API?

The Document API provides a simplified interface to access the NoSQL data that is returned by DynamoDB. You no longer need to update schema or map the table properties to class members. The Document API provides new data types to assist in the serialization and deserialization process. The DynamoDB Object Mapper maps client-side model classes to DynamoDB tables.

Both APIs provide methods to perform create / update / delete (CRUD) operations and execute queries against the DynamoDB tables. The difference between the two APIs is in how the data is represented as you manipulate it within your mobile app.  This enables you to select the API that you feel is better for your situation. You can even mix and match. For example, you can use the Object Mapper for data in one table, and use the Document API for data in another table.

Working with the Document Object

When working with the Document API, you primarily work with a Document. A Document is the container for the data returned from or pushed to the Amazon DynamoDB database.

You can convert between JSON and Document objects. However, you will lose fidelity when converting from a Document object to JSON. This is because not all data types that can be stored in DynamoDB can be represented in JSON. Use Document.fromJson() and Document.toJson() to perform the conversion. For example:

Document myDocumentObject = Document.fromJson(myJsonString);
String myJsonString = Document.toJson(myDocumentObject);

The Document object accepts standard JSON types, like string, number, or Boolean:

Document doc = new Document();
doc.put(“stringField”, “value”);
doc.put(“numberField”, 2.0F);
doc.put(“booleanField”, true);

The Document object also accepts JSON arrays (represented as a set of items) and JSON maps (represented as another Document):

// An unordered list
Set<String> coll = new HashSet<String>();
coll.add(“string1”);
coll.add(“string2”);
doc.put(“arrayField”, coll);

// A key-value map
Document name = new Document();
name.put(“first”, “Adrian”);
name.put(“last”, “Hall”);
doc.put(“name”, name);

The Document object also accepts Amazon DynamoDB types, such as binary data, null, and ordered lists:

//null field
doc.put(“nullField”, DynamoDbNull.NULL);

// Binary Data
ByteBuffer buffer = new ByteBuffer();

// Populate the buffer with binary data
doc.put(“binaryField”, new Primitive(buffer));

// An Ordered List
DynamoDbList ddl = new DynamoDbList();
ddl.add(“string1”);
ddl.add(“string2”);
doc.put(“orderedList”, ddl);

You can access data within a Document object using the document path. For example:

String stringField = doc.get(“stringField”);
String firstName = doc.get(“name.first”);

If you do not know which data type is being returned, use the DynamoDbEntry type, and then compare it against the known types:

DynamoDBEntry entry = doc.get(“orderedList”);
If (entry instanceof DynamoDBList) {
    dynamoDBList list = entry.asDynamoDBList();
    for (Iterator I = list.iterator(); i.hasNext(); ) {
        DynamoDBEntry listEntry = (DynamoDBEntry)i.next();
    }
}

You can also use entry.asString(), entry.asNumber(), etc. to convert to more primitive types.

Handling Data with the Document API

Document objects are used as the unit of transfer between your mobile app and Amazon DynamoDB. Each of the CRUD operations within the Document API either accepts or returns a Document object. First, create an Amazon DynamoDB client, then get a reference to the DynamoDB table:

DynamoDBClient client = new DynamoDBClient(awsCredentialProvider, config);
Table myTable = Table.loadTable(client, “MyTable”);

Once you have a reference to the table, you can use putItem(), getItem(), updateItem() or deleteItem() to perform CRUD (create, read, update, delete) operations. For example, if you know the key of the item that you want to retrieve, you can use this key to retrieve the document, obtain the text content, and assign it to an Android control:

Document retrievedDoc = myTable.getItem(new Primitive(“key”));
myTextView.setText(retrievedDoc.get(“stringField”).asString());

If the user has changed the text, you can update the document as follows:

retrievedDoc.set(“stringField”, myTextView.getText());
Document updatedDoc = myTable.updateItem(retrievedDoc);

You can also query for data using the Document API. For example, to find all Document objects where the Age field is greater than 5:

final Expression expression = new Expression();
expression.setExpressionStatement("Age > :age");
expression.withExpressionAttibuteValues(":age", new Primitive(5));
Search searchResult = table.scan(expression);
List<Document> documents = searchResult.getAllResults();

The table.scan() method performs a query across all fields in the table, which is probably not the most optimal method for querying the table. If you have a partition key called userId (which contains the user’s ID), then you can run queries across a single partition using the table.query() method:

final Expression expression = new Expression();
expression.setExpressionStatement("Tag = :tag");
expression.withExpressionAttibuteValues(":tag", new Primitive(“sports”));

Search searchResult = table.query(new Primitive(“myUser”), expression);
List<Document> documents = searchResult.getAllResults();

This method will have better performance because DynamoDB is scanning fewer records.

Document API limitations

The DynamoDB Document API does not currently support:

  1. Data types such as S3Link, Date, Calendar, etc.
  2. Batch operations.
  3. Conditional expressions.

The Document API is currently in beta and we would like to hear about the use cases you would like us to support. You can leave your feedback and issues on our forums and GitHub.

In the second part of this blog, we will describe how to integrate the Document API into a real Android app and provide a sample app that shows the Document API in action.