Multiple frontends with Amplify Console
Tags: aws, amplify, react, devops
Published: 2020-05-30 11:55:36

>  If you have an Amplify Console app with a cloud backend and need to connect a second app to it, this is the tutorial for you. 

AWS Amplify is a fantastic solution for building secure, scalable full stack applications. The concept is that as you build out your frontend app, you also scaffold out your backend in the cloud using the Amplify CLI, storing the resulting config in a single Git repository. Amplify Console then provides a Git-based workflow for deploying and hosting your fullstack serverless app.

The Amplify documentation covers this scenario in detail. What if you want to connect more than one app to your backend though? The schema for all of your cloud backend is in the first repo. How do you connect to say an iOS app, Android app or as in my case another React app to the cloud backend? 

The Amplify team have provided the basic commands to enable you to achieve this but the documentation and use cases are lagging, leaving you to search out the specifics yourself.  

## Connecting a second app

I'll assume you've already created your full-stack app in Amplify Console with a frontend web app and a cloud backend app. Now you want to get cracking on that second app and get it talking to your single backend.

> If you haven't you best start with the Getting Started Amplify Docs https://docs.amplify.aws/start/q/integration/js

### Scaffold out your app

In my case I'm creating a Gatsby app so I ran the command `gatsby new gatsby-site`.

### Pull down the backend

Next you need to pull down the backend from Amplify. In Amplify Console select your app, select the `Backend environements` tab and click the `Edit backend` link. This will reveal the command you need to run in order to pull down the backend. In my case `amplify pull --appId dt9kkffvqgojy --envName dev`.

![](https://dev-to-uploads.s3.amazonaws.com/i/exmw5f5gizg6cjpjc602.png)

Run this command and follow the prompts as normal but for the final question "Do you plan on modifying this backend?" answer no. This ensures the `amplify` folder is not copied to your second app. Whilst the docs say things will work if you have the amplify folder in your second app, it can lead to conflicts when pushing code. 

```bash
? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use Default
Amplify AppID found: dt9kkffvqgojy. Amplify App name is: test-app
Backend environment dev found in Amplify Console app: test-app
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path:  src
? Distribution Directory Path: build
? Build Command:  npm run-script build
? Start Command: npm run-script start

? Do you plan on modifying this backend? No

```

### Download backend schema

Most likely you'll also have a schema for your backend that you need to work with in your second app e.g if you've created an API. You'll need to also download that. 

Jump back into the Amplify Console and click on your backend environment name, in my case it is `Dev` and click on the `API` tab. I have a GraphQL API so I clicked the `View in AppSync` button which opens the AppSync console. Click the `Schema` navigation link and then the `Export schema` button. Select the `schema.json` option and save it in the root of your second app. 

You will now be able to run `amplify codegen add` to configure your second project with your API to generate the GraphQL mutations, queries and subscriptions so your second app can talk to your amplify backend.

> For more information on codgen see the docs https://docs.amplify.aws/cli/graphql-transformer/codegen

At this point you have everything you need to develop locally on your second app. If you need to work with a different environment, simply run the `amplify pull`command, update `schema.json`  and run the `amplify codegen` command again. 

## Configuring C.I builds

Working in development locally is only part of the solution. As you move closer towards deployment you'll notice some issues. Specifically: 

* You can't use your AWS Profile in continuous integration like you do on your local machine
* The interactive prompts from the `amplify pull` command need to be automatically answered somehow

The solution to these problems is that you need to run the commands in headless mode https://docs.amplify.aws/cli/usage/headless.

### Update @amplify/cli in C.I

Amplify pull is a relatively new command, so older versions of the Amplify CLI have no clue what to do when you run the command. So step 1 before you do anything else and to help you avoid losing many an hour to this quirk as I did, update the Amplify CLI in C.I. 

For some reason the default version of the Amplify CLI running in C.I of the Amplify Console is `1.12.0`, the latest version being `4.21.0`. To fix this go into the `Build settings` section of the Amplify console for your project (available in the sidebar menu). Scroll to the bottom and edit the `Build image settings`, then choose to `Add package version override`. Select Amplify CLI and set the version to `canary`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gtxzx7aji75qdmqo2ef0.png)

This will update `@amplify/cli` during the `Cloning repository` stage of your build to the latest version.

```bash
2020-05-28T12:51:32.924Z [INFO]: # Ensuring NPM package '@aws-amplify/cli' is version: 'canary'
2020-05-28T12:51:40.174Z [INFO]: # Patching NPM package '@aws-amplify/cli' from 1.12.0 to canary...
2020-05-28T12:52:45.411Z [INFO]: # Done patching NPM package '@aws-amplify/cli'
```

### Headless Amplify pull

Now that Amplify Console can understand the `amplify pull` command we can run it in headless mode by passing the `--yes` flag at the end. This means we don't get any of the question prompts and instead need to provide all of the parameters to the command. 

At the bottom of the documentation on headless CLI usage there is a section on `amplify pull` that provides an example bash script. We'll use that as the basis for our C.I build. 

In the root of your project create a bash file named `amplify-pull.sh` (can be named whatever you want). Then set execute permissions by running  `chmod u+x amplify-pull.sh`. 

### YAML configuration

Next we need to make a few amends to the build config in Amplify Console to call our bash script. 

In the build settings edit the `amplify.yml` file (you can also download it and put it in the root of your project if you prefer). In the frontend phase of the build we need to tell Amplify Console to run our bash script in the preBuild stage, e.g

```yaml
version: 0.1
frontend:
  phases:
    preBuild:
      commands:
		- ./amplify-pull.sh "${ACCESS_KEY_ID}" "${SECRET_ACCESS_KEY}" "${AWS_BRANCH}"
        - npm ci
```

In the code above we specify that we want to run the command `./amplify-pull.sh` which will pass everything over to our bash script. The bash script requires a number of environment variables which you'll note we also pass in via the YAML file. They are:

* ACCESS_KEY_ID
* SECRET_ACCESS_KEY
* AWS_BRANCH (not strictly required but handy)

You'll need to set up these environment variable values within the Amplify Console. You'll find the values in your `.aws/credentials` file on your local machine. These are the credentials you may have set up when running `amplify configure`. 

> See docs on setting environment variables in Amplify Console https://docs.aws.amazon.com/amplify/latest/userguide/environment-variables.html

### The bash file

Finally back to the empty bash file we created. The exact config of your bash file will depend on your specific needs. In my case I'm building a Gatsby site so the `DistributionDir` is set to `public` as that is where Gatsby likes to place the files when building for production. On the whole though the bash files should be fairly similar. 

It's important to know that environment variables are read in a bash script based on the order they are passed in. So:

* ACCESS_KEY_ID was passed in first so is available as $1

* SECRET_ACCESS_KEY as $2
* AWS_BRANCH as $3

The first part of the code checks $3 to check the current Git branch. This enables deploying different backends depending on which branch you are on with the value simply passed on as the $AWSENV variable to the Amplify object. Also note that `projectName` and `appId` are the values of the Amplify app in the other project that is fully connected to Amplify.

The rest of the code is essentially the same as the example in the documentation but note that `accessKeyId` and `secretAccessKey` take their values from the environment variables we passed in.

One additional step added is the `amplify codegen` command, not stricly necessary as we did that locally but it does ensure the correct code is deployed. 

```bash
#!/bin/bash
set -e
IFS='|'

# Use AWS_BRANCH var to check which backend to pull
if [ "$3" = "master" ]; then
    AWSENV="prod" 
else
    AWSENV="qa"
fi

REACTCONFIG="{\
\"SourceDir\":\"src\",\
\"DistributionDir\":\"public\",\
\"BuildCommand\":\"npm run-script build\",\
\"StartCommand\":\"npm run-script start\"\
}"

AWSCLOUDFORMATIONCONFIG="{\
\"configLevel\":\"project\",\
\"useProfile\":false,\
\"profileName\":\"default\",\
\"accessKeyId\":\"$1\",\
\"secretAccessKey\":\"$2\",\
\"region\":\"eu-west-2\"\
}"

AMPLIFY="{\
\"projectName\":\"admin-app\",\
\"appId\":\"dt9kkffvqgojy\",\
\"envName\":\"$AWSENV\",\
\"defaultEditor\":\"code\"\
}"

FRONTEND="{\
\"frontend\":\"javascript\",\
\"framework\":\"react\",\
\"config\":$REACTCONFIG\
}"

PROVIDERS="{\
\"awscloudformation\":$AWSCLOUDFORMATIONCONFIG\
}"

amplify pull --amplify $AMPLIFY --frontend $FRONTEND --providers $PROVIDERS --yes
amplify codegen

```

That's it! You should now be able to develop and publish your second app via continuous integration connected to the amplify cloud backend from your main app codebase. 

In truth it isn't that hard to set up, it is just that none of this is fully documented as yet and pitfalls like the outdated Amplify CLI in Amplify Console may prevent you knowing this is even possible at all.