Until now, I had only developed in the Heroku environment, but when developing a custom Shopify app, I decided to try building a serverless environment on AWS.
This time, I tried to create an SPA + Serverless configuration on AWS, referring to the blog below.
Personally, I have only had experience with S3 when it comes to AWS, so I am a complete beginner when it comes to building this.
Generally, we check and verify the operation, but if you find any mistakes in the explanation, please let us know in the comments!
Development Environment
front end
React.js
Amplify Hosting
└S3
└Cloudfront
Backend
Node.js/aws-serverless-express
Serverless Framework
└API Gateway
└Lambda
└DynamoDB
References
Overall structure
https://www.nri-digital.jp/tech/20200526-2059/
Sample code
https://github.com/t-kurasawa/shopify_dev_template
・Install Serverless Framework
https://www.serverless.com/framework/docs/getting-started/
・About JWT
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
https://github.com/serverless/examples/blob/master/aws-node-auth0-cognito-custom-authorizers-api/auth.js
https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.ts
・AWS Amplify
https://docs.amplify.aws/start/q/integration/react
・Amazon DynamoDB
https://aws.amazon.com/jp/dynamodb/getting-started/
Git Clone
This time, we will set up the environment based on the sample code provided by Mr. Kurazawa.
This code is a custom app that displays a list of products registered on the Shopify admin screen and also allows you to register new products.
First, clone the app.
$ git clone git@github.com:t-kurasawa/shopify_dev_template.git
$ cd shopify_dev_template
The directory structure is as follows:
shopify_dev_template
└ app
└ api-serverless (サーバー側)
└ react-amplified (フロント側)
└ shopify-app-cli
└ themekit
└ README .md
Basically, api-serverless in the app directory is the server-side code, and react-amplified is the front-end code.
First, we will build the server-side api-serverless.
Building a backend API with Serverless Framework
The backend will be built using AWS' Serverless Framework.
Apparently they won't use Amplify's api/function because it has poor scalability.
First, install the Serverless Framework.
$ curl -o- -L https: / /slss.io/install | bash
*References: https://www.serverless.com/framework/docs/getting-started/
Next, let's build it.
$ cd app/api-serverless
$ yarn install
By the way, yarn install is a command that installs the contents of package.json, but I did my own research to find out what it installs.
Skipping this section will not affect your environment setup, so if you don't need it, you can move on to the next step.
The contents installed by yarn install are as follows:
I have researched and written this information, but if you have any misunderstandings, please leave a comment!
@babel/core, bable-loader : A JavaScript compiler that unifies various versions of JS.
aws-sdk : The AWS SDK itself.
aws-serverless-express: Written in Express, a Node.js web application framework, it runs on API Gateway + Lambda.
axios: A Promise-based HTTP client that runs on browsers and node.js. It can be easily implemented when you want to perform asynchronous HTTP communication.
cors: A mechanism that uses additional HTTP headers to instruct a browser to grant a web application running at one origin (URL) access to selected resources at a different origin.
jsonwebtoken: JWT (JSON Web Token) is a specification for a token expressed in a JSON data structure.
jwk-to-pem : A library for converting a JSON Web Key to a public key.
{
"name" : "api-serverless" ,
"version" : "1.0.0" ,
"main" : "index.js" ,
"license" : "MIT" ,
"dependencies" : {
"@babel/core" : "^7.9.6" ,
"aws-sdk" : "^2.673.0" ,
"aws-serverless-express" : "^3.3.8" ,
"axios" : "^0.19.2" ,
"babel-loader" : "^8.1.0" ,
"body-parser" : "^1.19.0" ,
"cors" : "^2.8.5" ,
"crypto" : "^1.0.1" ,
"express" : "^4.17.1" ,
"jsonwebtoken" : "^8.5.1" ,
"jwk-to-pem" : "^2.0.3" ,
"moment" : "^2.26.0" ,
"request" : "^2.88.2" ,
"serverless-dotenv-plugin" : "^2.4.2" ,
"serverless-webpack" : "^5.3.1" ,
"shopify-api-node" : "^3.3.1" ,
"webpack" : "^4.43.0"
}
}
Building a front-end environment with Amplify
Next, let's use Amplify to build the front-end environment.
In this sample code, the front-end language used is React.js.
First, install Amplify.
$ cd ../react-amplified
$ curl -sL https://aws-amplify.github.io/amplify-cli/install | bash && $SHELL
Once the installation is complete, let's configure Amplify.
$ amplify configure
https: / /console.aws.amazon.com/
Press Enter to continue
=>You will be asked to log in to your AWS account, so please log in. After logging in, press enter.
You will then be asked a number of questions which I will answer one by one.
Specify the AWS Region
? region: ( Use arrow keys )
us-east -1
us-east -2
us-west -2
eu-west -1
eu-west -2
eu-central -1
❯ ap-northeast -1
( Move up and down to reveal more choices)
Set it to ap-northeast-1 in Tokyo.
Specify the username of the new IAM user:
? user name: (amplify-xxxxx)
I registered my real name in Roman letters.
Then, a browser will open automatically, so create an IAM.
I've reproduced the gif from the tutorial because it was easy to understand the settings.
Don't forget to copy your access key and chiclet key now.
Once that's done, hit enter in the terminal to move on.
Enter the access key of the newly created user:
? accessKeyId: ***** ***** ***** *****
? secretAccessKey: ***** ***** ***** ***** ***** ***** ***** *****
Enter your access key and secret key and set your AWS profile name.
Next, create a local AWS profile.
This would update / create the AWS Profile in your local machine
? Profile Name :
That's it, Amplify setup is complete!
Next, let's build it. Move to the app/react-amplified directory.
$ yarn install
(app/react-amplifiedで実行してください)
Once the front-end build is complete, let's use amplify to authenticate users.
$ amplify init
(基本的に、ひたすらEnterで問題ありません)
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project ( reactamplified )
? Enter a name for the environment ( dev )
? Choose your default editor: ( Use arrow keys )
❯ Visual Studio Code
Atom Editor
Sublime Text
IntelliJ IDEA
Vim ( via Terminal, Mac OS only )
Emacs ( via Terminal, Mac OS only )
None
? Choose the type of app that you're building ( Use arrow keys )
android
flutter
ios
❯ JavaScript
? What javascript framework are you using ( Use arrow keys )
angular
ember
ionic
❯ react
react-native
vue
none
? Source Directory Path: ( src )
? Distribution Directory Path: ( build )
? Build Command: ( npm run-script build )
? Start Command: ( npm run-script start )
Using default provider awscloudformation
For more information on AWS Profiles, see:
https: //docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
? Do you want to use an AWS profile? ( Y/n )
=> Y
? Please choose the profile you want to use ( Use arrow keys )
❯ default
This completes the S3 and CloudFormation configuration.
Next, let's use the hosting feature to expose the front end of our web app on CloudFront + S3.
First, set up your hosting.
$ amplify add hosting
? Select the plugin module to execute
Hosting with Amplify Console ( Managed hosting with custom domains, Continuous deployment)
❯ Amazon CloudFront and S3
This time, we are setting up the environment for study purposes only, so continuous deployment is not necessary.
Therefore, we choose Amazon CloudFront and S3.
? Select the environment setup: ( Use arrow keys )
DEV (S3 only with HTTP )
❯ PROD (S3 with CloudFront using HTTPS)
Since HTTPS is required to connect to Shopify, select the production environment (PROD) instead of the development environment (DEV) so that you can use https.
? hosting bucket name (reactamplified-xxxxxxxxxx-hostingbucket)
The S3 bucket name can be anything you like, so just enter it and hit enter.
Configuring the authentication function Cognito
Next, let's configure Amazon Cognito using amplify.
Cognito is a service that allows you to register, authenticate, update, and delete users.
$ amplify add auth
Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? ( Use arrow keys )
❯ Default configuration
Default configuration with Social Provider (Federation)
Manual configuration
I want to learn more.
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in ?
Username
❯ Email
Phone Number
Email or Phone Number
I want to learn more.
Do you want to configure advanced settings ? ( Use arrow keys )
> No , I am done.
Yes, I want to make some additional changes.
Publishing with Amplify and setting environment variables
Once you've completed the setup, publish the information you've provided so far.
$ amplify publish
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | --------------- | -------- | ----------------- |
| Hosting | S3AndCloudFront | Create | awscloudformation |
? Are you sure you want to continue? (Y/n)
=> Y
As of December 2020, a warning is displayed that caniuse-lite is out of date.
It asks you to enter the following command, so just follow the instructions and enter it.
$ npx browserslist --update-db
Now, the cloudfront URL has been issued. The URL is shown in the figure below.
Once the CloudFront URL has been issued, set the URL on your custom Shopify app.
Setting up a custom Shopify app
Now, create a custom app from your Shopify Partner Dashboard.
Use the CloudFront URL issued earlier for the app URL and redirect URL.
- App URL: https://cloudfront URL/auth
- Redirect URL: https://cloudfront URL/callback
Let's also set the URL in REACT_APP_APPLICATION_URL in app/react-amplified/.env.
Once created, make a note of the API key and API secret key.
Copy app/api-serverless/.env.example and create a .env file in the same directory.
Enter the API key and API secret key you copied earlier into SHOPIFY_API_KEY and SHOPIFY_API_SECRET.
Next, we will take measures to deal with the CORS error that seems to occur in CloudFront.
First, log in to the AWS CloudFront console.
Click on the ID to edit it.
- Click the "Behaviors" tab, check the checkbox and click "Edit"
・Change "Cache Based on Selected Request Headers" to "White List"
・Add "Origin" to "Whitelist Headers"
Click "Yes, Edit" at the bottom of the page to save your changes.
Next, set the user pool ID, client ID, and Identity_pool ID in the environment variables.
First, copy app/react-amplified/.env.example and create a .env file in the same directory.
*I didn't know how to check from the terminal, so I checked from the URL below.
If you have any other ways to check, please let me know in the comments.
Sign in to Amazon Cognito. Select Tokyo as the region, as shown below.
Select the created identity and click "Edit Identity Pool" in the upper right.
You can check it here,
- Set "Identity Pool ID" to REACT_APP_COGNITO_IDENTITYPOOLID in app/react-amplified/.env
- Set "User Pool ID" to REACT_APP_COGNITO_USERPOOLID in app/react-amplified/.env and COGNITO_USER_POOL_ID in app/api-serverless/.env
- Set "App Client ID" to REACT_APP_COGNITO_CLIENTID in app/react-amplified/.env and COGNITO_CLIENTID in app/api-serverless/.env
- Set "ap-northeast-1" to REACT_APP_COGNITO_REGION in app/react-amplified/.env and REGION in app/api-serverless/.env.
I will.
While you're there, enter the API key of your custom Shopify app in REACT_APP_SHOPIFY_API_KEY and read_products, write_products, read_product_listings in REACT_APP_SCOPES.
The actual member registration is performed around line 88 of app/react-amplified/src/Top.js.
However, this sample code does not create a membership registration screen, and it appears that registration is forced through the code.
To register as a member, uncomment line 90 of app/react-amplified/src/Top.js and change “your-email@mail.com” to your own email address.
async componentDidMount() {
// TODO: Create a login screen (temporarily replacing signup -> confirmation -> login)
const res = await cognito.signUp( 'xxxxxxxxxx@gmail.com' , 'P@ssw0rd1234567890' )
// const res = await cognito.confirmation('xxxxxxxxxx@gmail.com',"123456")
// const res = await cognito.login('xxxxxxxxxx@gmail.com', 'P@ssw0rd1234567890')
Deploy
First, let's deploy it on the server side.
Since we have already installed the Serverless Framework, all we need to do is enter the command below.
*Please make sure that the environment variables are entered in .env.
*Please run the application in the app/api-serverless directory.
$ cd ../api-serverless
$ serverless deploy
Once the deployment is complete, the API endpoint will be issued, so copy it.
Set these to REACT_APP_PUBLIC_API_URL and REACT_APP_PRIVATE_API_URL in app/react-amplified/.env respectively.
Now that we have modified the environment variables, let’s publish them with Amplify.
$ cd ../react-amplified
$ amplify publish
It may take a few hours for the published information to appear.
If you want the changes to be reflected immediately, follow the steps below to clear your cache.
・Log in to the CloudFront console screen
・Select the target Distribution
・Click the "Invalidations" tab.
- Click "Create Invalidation", enter "/*" and click "Invalidate"
Once In Progress becomes Completed, the update is complete.
Once the deployment is complete, install it on your Shopify online store.
If the installation is successful, you will see the following screen.
When you access the site, a new member registration will be performed in Cognito.
Check your email address and copy the verification code.
Go back to app/react-amplified/src/Top.js and this time uncomment the configuration line.
Replace it with the verification code you copied earlier.
async componentDidMount() {
// TODO: ログイン画面の作成(signup -> confirmation -> login を一旦代替)
// const res = await cognito.signUp('xxxxxxxxxx@gmail.com', 'P@ssw0rd1234567890')
const res = await cognito.confirmation( 'xxxxxxxxxx@gmail.com' , "Please paste the verification code" )
// const res = await cognito.login('xxxxxxxxxx@gmail.com', 'P@ssw0rd1234567890')
Deploy again.
$ amplify publish
Let's clear the cloudfront cache again.
Once you have cleared your cache, return to the Shopify app screen.
This will complete your user registration.
Finally, go back to app/react-amplified/src/Top.js and this time uncomment the login line.
async componentDidMount() {
// TODO: ログイン画面の作成(signup -> confirmation -> login を一旦代替)
// const res = await cognito.signUp('xxxxxxxxxx@gmail.com', 'P@ssw0rd1234567890')
// const res = await cognito.confirmation('xxxxxxxxxx@gmail.com',"verification codeを貼ってください")
const res = await cognito.login('xxxxxxxxxx@gmail.com', 'P@ssw0rd1234567890')
Once you have made your changes, deploy them and clear the cache as before.
If you access the Shopify app screen again, you should see a list of products and be able to register them.
This completes the creation of a serverless custom Shopify app environment!
Thank you for your hard work! m(_ _)m