AWS Amplify is a CLI & toolchain for the client that allows developers to quickly create & connect to AWS cloud services directly from the front-end environment. Amplify lowers the barrier to entry for developers looking to build full-stack applications by giving them an easy way to create & connect to managed cloud services.

Expo has a built-in native bridge for the AWS Amplify library.

In this tutorial, we’ll walk through how to create a cross-platform Expo app with features like user sign-in, AWS Lambda functions, an AWS AppSync GraphQL API, analytics, & storage.

Creating the Expo app

If you don’t already have it, you will need to first install the Expo CLI:

npm install expo-cli --global

Next, we’ll scaffold a new Expo project:

expo init expo-amplify cd expo-amplify

Now we’ll install the local dependencies for the AWS Amplify library:

yarn add aws-amplify aws-amplify-react-native # or npm install --save aws-amplify aws-amplify-react-native

To test out the project, we can:

expo start

Installing & configuring the AWS Amplify CLI

Now we’ll install the AWS Amplify CLI:

npm i -g @aws-amplify/cli

With the AWS Amplify CLI installed, we now need to configure it with an IAM User:

amplify configure

For a video walkthrough of how to configure the AWS Amplify CLI, click here.

Initializing the AWS Amplify project

From within the root directory or the newly created Expo app, let’s initialize a new AWS Amplify project:

amplify init

When asked if you’d like to use an AWS profile, choose Yes, using the default profile we created when we configured the CLI earlier.

Enabling our first feature — Authentication

Amplify has an authentication feature that implements Amazon Cognito as an auth provider. This is the first feature we’ll add to the new app.

To add a new feature, we can use the add command: amplify add <featurename> . For authentication, the feature name is auth , so we’ll run the following command to add authentication:

amplify add auth

When asked “Do you want to use default authentication and security configuration?”, choose Yes.

Next, to enable the service in our AWS account, we’ll run the following command:

amplify push

Now, the service is created & we can begin authenticating users!

If you would like to view the new service as well as see new users as they’re created, you can view the Cognito dashboard at https://console.aws.amazon.com/cognito/.

The easiest way to get up and running with authentication is to use the withAuthenticator Higher Order Component (HOC) that comes with the AWS Amplify React Native library we installed earlier. This HOC will protect any route or component with an end to end user authentication scheme including sign up, sign in, MFA, & password reset.

In App.js, let’s update the code to look like this:

In this file, we’ve imported the Amplify library & configured it with the aws-exports.js file that was created by the CLI.

Now, we’ll run the app:

expo start

When we run the app, we should now see the following authentication flow protecting the App component:

Now, you should be able to create an account, login, & log out!

Auth Class

We can also use the Auth class to authenticate users.

import { Auth } from 'aws-amplify' // in your component

Auth.signIn('myusername', 'mYC0MP13xP@55w0r8')

Auth has over 30 methods including signUp , confirmSignUp , signIn , confirmSignIn , & changePassword . You can also do things like change MFA type to TOTP & update user attributes!

When you sign in using Auth.signIn , the session data will be persisted and can be accessed at any time using the Auth.currentauthenticateduser method. Here’s some example code of how user sign in & user sign up could be implemented using the Auth class:

Once you have signed in new users, you can view the configuration at https://console.aws.amazon.com/cognito and click on the cognito user pool that was created. You can get any resource name at any time by typing:

amplify status

GraphQL — AWS AppSync

Next, let’s learn how to add a GraphQL API to the app. For this we’ll use AWS AppSync, a managed GraphQL service that allows you to build serverless GraphQL APIs that scale.

To add the GraphQL API, we’ll run the following command:

amplify add api

This will walk us through the following steps to create the AWS AppSync GraphQL API:

Please select from one of the below mentioned services: GraphQL

Provide API name: myfavoritepetsapp

Choose an authorization type for the API: API_KEY

Do you have an annotated GraphQL schema?: N

Do you want a guided schema creation? Y

What best describes your project: Single object with fields

Do you want to edit the schema now? Y

This should either open up our GraphQL schema file or give you the location of the file. The path to this file should be something like /Users/yourname/amplify-expo/amplify/backend/api/amplifyexpotest/schema.graphql .

In this file, enter the following Schema & save the file:

type Pet @model {

id: ID!

name: String!

description: String

}

Once you’ve updated & saved the file, go back to the command line & click enter.

Now, we have successfully added the AppSync resources locally, we now need to run amplify push to push them for execution in your account:

amplify push

Here, you will be prompted to whether you would like to have GraphQL code generation for mutations, queries, & subscriptions as well as a typed API file for either TypeScript or Flow. We won’t be using these files, but if you’d like to see this in action feel free to choose yes.

Once this command has finished executing, we can start using the API.

You should also see the API URL logged out to you in the console. To view the API URL & information at any time, you can run amplify status to view enabled Amplify features & information. To view all AppSync APIs in your account, you can visit the AppSync dashboard at https://console.aws.amazon.com/appsync/home.

If you’d like to update the API, you can change your local schema file at any time & run amplify push again, this will create, update, or delete the resources in your AWS AppSync API.

To interact with the API, we will use the API category & graphqlOperation helper from aws-amplify:

import API, { graphqlOperation } from '@aws-amplify/api'

To perform a mutation, we need to define the mutation then we can use the API.graphql function to execute it:

// define mutation

const createPet = `

mutation($name: String!, $description: String) {

createPet(input: {

name: $name

description: $description

}) {

id

name

description

}

}` // execute a mutation

state = { name: '' }

onChangeText = value => {

this.setState({ name: value })

}

createPet = async () => {

const pet = this.state

await API.graphql(graphqlOperation(createPet, pet))

}

To perform a query, we can do something similar, define the query then execute it:

// define query

const listPets = `

query {

listPets {

items {

id

name

description

}

}

}

` // execute query

getPets = () => {

const data = await API.graphql(graphqlOperation(listPets))

// do something with data

}

For a full demo, check out this gist:

Lambda Functions

AWS Lambda & services like it allow you to outsource your infrastructure management to cloud providers like AWS. With Lambda functions, we don’t need to worry about setting up, maintaining & deploying our servers. This allows developers to reduce both operational complexity & cost.

AWS Amplify allows us to quickly spin up both Lambda functions as well as APIs that are built using Lambda functions by using the api category. Let’s create a Lambda function that works as an API for our app. This Lambda function will be running an Express app with different endpoints that we can access.

To create the API & Lambda function, we’ll run the following command:

amplify add api

This will walk us through the following steps to create the API:

Please select from one of the below mentioned services: REST

Provide a friendly name for your resource to be used as a label for this category in the project: mylambdaapi

Provide a path (e.g., /items) /pets

Choose a Lambda source: Create a new Lambda function

Provide a friendly name for your resource to be used as a label for this category in the project: mylambdaapifunction

Provide the AWS Lambda function name: mylambdaapifunction

Choose the function template that you want to use: Serverless express function (Integration with Amazon API Gateway)

Do you want to edit the local lambda function now? Y

Next, in amplify-expo/amplify/backend/function/mylambdaapifunction/src/app.js , update app.get(/pets) to the following:

app.get('/pets', function(req, res) {

const pets = ['zeus', 'apollo', 'bella', 'cocoa', 'charlie']

res.json({

pets

})

})

Next, go back to the command line & click Enter.

Restrict API access: N

Do you want to add another path? N

Now with everything configured locally, we can push to create the resources in our AWS account:

amplify push

Now, we have a new REST API with the name mylambdaapi, & we can immediately start working with it.

If you would like to view your Lambda function at any time in your account, visit https://console.aws.amazon.com/lambda/ and click on the new function that was just created.

To fetch data, we can call API.get(apiname, apipath) like so:

const restData = await API.get('mylambdaapi', '/pets')

Updating the Lambda Function / REST API

If we would like to update our endpoint at any time, we can do so by:

Running amplify configure api & adding / updating configuration Changing the code in amplify-expo/amplify/backend/function/mylambdaapifunction . Running amplify push

Let’s add a new endpoint, /people , & allow it to fetch data remotely from an http endpoint (the Star Wars API).

First, we’ll run amplify configure api and go through the prompted questions:

amplify configure api

Please select from one of the below mentioned services REST

Please select the REST API you would want to update mylambdaapi

What would you like to do Add another path

Provide a path (e.g., /items) /people

Choose a Lambda source Use a Lambda function already added in the current Amplify project

Choose the Lambda function to invoke by this path mylambdaapifunction

Restrict API access N

Do you want to add another path? N

Next, we’ll need to install the axios library in amplify-expo/amplify/backend/function/mylambdaapifunction . To do so, navigate to the directory and run:

yarn add axios # or npm install —-save axios

Next, we’ll update the code in amplify-expo/amplify/backend/function/mylambdaapifunction/src/app.js to add the new endpoint:

// below the last import

const axios = require('axios');

axios.get('

.then(response => {

res.json({

data: response.data.results,

err: null

})

})

.catch(err => {

res.json({

err: err

})

})

}) app.get('/people', function(req, res) {axios.get(' https://swapi.co/api/people/' .then(response => {res.json({data: response.data.results,err: null})}).catch(err => {res.json({err: err})})})

Now, we’ll push our updates to our AWS account:

amplify push

Now, we can call:

const restData = await API.get('mylambdaapi', '/people')

From our Expo app and we’ll see the Star Wars data returned from our new API endpoint!

Analytics

Every application needs analytics! You want to know what is working & what isn’t working. You also may want to keep up with important metris about usage & track what your users are liking / not liking about your app.

With AWS Amplify, we can easily add Analytics to our app using the analytics category which implements Amazon Pinpoint under the hood.

From the Amazon Pinpoint docs: You can capture vital information about how your customers use your apps. Amazon Pinpoint includes usage dashboards that track the number of sessions per day, the number of purchases per day, the days and times when customers use your app, and more.

Let’s add Pinpoint & start tracking some custom events!

To add analytics, we’ll run the following command:

amplify add analytics

Provide your pinpoint resource name: amplifyexpoanalytics

Apps need authorization to send analytics events. Do you want to allow guests and unauthenticated users to send ana

lytics events? (we recommend you allow this when getting started): Y

Next, we’ll push the new configuration to our account:

amplify push

We can now start recording events! To do so, we’ll import Analytics and call Analytics.record . Analytics.record takes three arguments:

Analytics.record({ name: String!, attributes: Object, metrics: Object })

Let’s create a button & wire it up to send events when it is pressed:

// import the Button component

import {

// existing imports from react native

Button

} from 'react-native' // import the Analytics category

import Analytics from '@aws-amplify/analytics' // create an event handler

onPress = () => {

Analytics.record({ name: "Button Clicked!" })

} // add button to rendered UI

<Button onPress={this.onPress} title='Record Event' />

To view you Analytics Pinpoint events, go to the Amazon Pinpoint dashboard, click on your project, & click events in the left menu.

We can also add attributes or metrics to the events. A convenient attribute might be to see the username of the user that is currently logged in! If we add back back the withAuthenticator component & log in as the user we created previously, this is pretty easy to do:

// set some initial state

state = { user: {} } // store user info in the state

async componentDidMount() {

const user = await Auth.currentAuthenticatedUser()

this.setState({ user })

} // register event with attributes containing user's username

onPress = () => {

Analytics.record({

name: "Button Clicked",

attributes: { username: this.state.user.username }

})

}

Storage

We can add storage to our app using the Amazon S3 by taking advantage of the Amplify storage category.

To do this, we’ll run the amplify add storage command:

amplify add storage

Please select from one of the below mentioned services Content (Images, audio, video, etc.)

? Please provide a friendly name for your resource that will be used to label this category in the project: amplifyexpos3bucket

? Please provide bucket name: YOURUNIQUEBUCKETNAME

? Who should have access: Auth and guest users

? What kind of access do you want for Authenticated users read/write

? What kind of access do you want for Guest users read

Now, we can begin uploading images, text, or whatever we would like to our S3 bucket!

The API basically looks like this:

import Storage from '@aws-amplify/storage' // to store an item

await Storage.put('test.txt', 'Hello World!') // retrieve an item

const image = await Storage.get('welcome.png')

For a deep dive of the Storage API, click here to see the docs.

Let’s take a look at how we can upload an image to S3.

First, we’ll need to install a couple of libraries:

yarn add mime-types path

Now, we’ll use ImagePicker & Permissions from Expo to get an image from the user’s camera roll & upload it to our S3 bucket:

// add additional imports

import { ImagePicker, Permissions } from 'expo';

import mime from 'mime-types'; // event handler to pull up camera roll

_pickImage = async () => {

const {

status: cameraRollPerm

} = await Permissions.askAsync(Permissions.CAMERA_ROLL); if (cameraRollPerm === 'granted') {

let pickerResult = await ImagePicker.launchImageLibraryAsync({

allowsEditing: true,

aspect: [4, 3],

});

this._handleImagePicked(pickerResult);

}

}; // this handles the image upload to S3

_handleImagePicked = async (pickerResult) => {

const imageName = pickerResult.uri.replace(/^.*[\\\/]/, '');

const fileType = mime.lookup(pickerResult.uri);

const access = { level: "public", contentType: 'image/jpeg' };

const imageData = await fetch(pickerResult.uri)

const blobData = await imageData.blob()



try {

await Storage.put(imageName, blobData, access)

} catch (err) {

console.log('error: ', err)

}

}

If you have issues running the code & are getting an error that says “Expected params.Body to be a string, Buffer, Stream, Blob, or typed array object”, check out the fix here as the AWS SDK that Amplify uses may not yet have been updated.

Next Steps

With AWS Amplify, you can also implement PubSub, Interactions (chatbots), Push Notifications, Internationalization & more. To learn more, check out the AWS Amplify documentation.

If you have any questions about AWS Amplify, feel free to reach out to me on Twitter!