Building a Serverless Web Application With AWS - Act 2
ChigozieCO
Posted on November 22, 2022
So far, in the previous post, we configured and deployed our WebApp on AWS Amplify and used used user pools form AWS Cognito to create a fully-managed user management system that allows us to authenticate our users and manage their user information.
We updated our website to use the user pool, and used it to provide a signin form on the site. We used Git and GitHub and the functionalities of AWS Amplify for continuous integration and continuous deployment (CI/CD).
BUILD A SERVERLESS BACKEND
Here we will use AWS Lambda and Amazon DynamoDB to build a backend process for handling requests for our web application.
To deliver on our deployed web app's promise which is to allow users request a unicorn be sent to a location of their choice the JavaScript running in the browser will need to invoke a service running in the cloud to fulfill those requests.
Implementation
A Lambda function will be invoked each time a user requests a unicorn. The function selects a unicorn from the fleet, records the request in a DynamoDB table, and responds to the front-end application with details about the dispatched unicorn.
The function is invoked from the browser using Amazon API Gateway. We will implement that connection soon. Let's test our function in isolation first.
⚠️ Before going along with this walk through, ensure you have completed all the steps and processes in the ACT 1 of this series. If you have terminated you application, redeploy it before you start to follow along.
Create an Amazon DynamoDB Table
We will create a DynamoDB table and give it a partition.
- a) From AWS Management Console, choose Services at the top left hand side of your screen, click on Database and select DynamoDB from the services on the right.
- b) Choose Create table.
- c) Enter Rides for the Table name. This field is case sensitive.
- d) Enter RideId for the Partition key and select String for the key type. This field is case sensitive.
- e) Check the Use default settings box and choose Create Table (at the bottom of the page).
- f) Click on the name of the table, in the Overview tab, click on 'Additional info' under general information then scroll to the bottom that section of your new table and note the ARN. We will use this in the next configuration.
Create an IAM Role for Your Lambda Function
Every Lambda function has an IAM role associated with it. This role defines what other AWS services the function is allowed to interact with. We will create an IAM role that grants our Lambda function permission to write logs to Amazon CloudWatch Logs and access to write items to your DynamoDB table.
a) From the AWS Management Console, click on Services and then select IAM in the Security, Identity & Compliance section.
b) Select Roles in the left navigation pane and then choose Create Role.
c) Select Lambda for the role type from the AWS service group, then click Next: Permissions.
Note: Selecting a role type automatically creates a trust policy for your role that allows AWS services to assume this role on your behalf. If you were creating this role using the CLI, AWS CloudFormation or another mechanism, you would specify a trust policy directly.
d) Begin typing AWSLambdaBasicExecutionRole in the Filter text box and check the box next to that role.
e) Choose Next Step.
f) Enter WildRydesLambda for the Role Name. Keep other parameters as default.
g) Choose Create Role at the bottom of the page.
h) Type WildRydesLambda into the filter box on the Roles page and choose the role you just created.
- i) On the Permissions tab, on the left under Add permissions, choose Create Inline Policy.
j) Select Choose a service.
k) Begin typing DynamoDB into the search box labeled Find a service and select DynamoDB when it appears..
l) Choose Select actions.
m) Begin typing PutItem into the search box labeled Filter actions and check the box next to PutItem when it appears.
n) Select the Resources section.
o) With the Specific option selected, choose the Add ARN link in the table section.
p) Paste the ARN of the table you created in the previous section in the Specify ARN for table field, and choose Add.
q) Choose Review Policy.
- r) Enter DynamoDBWriteAccess for the policy name and choose Create policy.
Create a Lambda Function for Handling Requests
AWS Lambda will run our code in response to events such as an HTTP request. In this step we'll build the core function that will process API requests from the web application to dispatch a unicorn.
a) Choose Services then select Lambda in the Compute section.
b) Click Create function.
c) Keep the default Author from scratch card selected.
d) Enter RequestUnicorn in the Name field.
e) Select Node.js 16.x for the Runtime.
f) Ensure 'Use an existing' role is selected from the Role dropdown.
g) Select WildRydesLambda from the Existing Role dropdown.
h) Click on Create function.
i) Scroll down to the Function code section and replace the existing code in the index.js code editor with the contents of requestUnicorn.js.
j) Choose Deploy.
Implementation Validation
Let's test the function that we just built using the AWS Lambda console.
- a) From the main edit screen for your function, select Test and choose Configure test event from the dropdown.
- b) Keep Create new event selected.
- c) Enter TestRequestEvent in the Event name field
- d) Copy and paste the following test event into the editor:
{
"path": "/ride",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Authorization": "eyJraWQiOiJLTzRVMWZs",
"content-type": "application/json; charset=UTF-8"
},
"queryStringParameters": null,
"pathParameters": null,
"requestContext": {
"authorizer": {
"claims": {
"cognito:username": "the_username"
}
}
},
"body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
}
- e) Choose save.
- f) On the main function edit screen click Test with TestRequestEvent selected in the dropdown.
- g) Scroll to the top of the page and expand the Details section of the Execution result section.
- h) Verify that the execution succeeded and that the function result looks like the following:
Deploy a RESTful API
It's all beginning to come together now, In these next couple of steps, we will use API Gateway to expose the Lambda function we just built as a RESTful API.
This API will be accessible on the public Internet. It will be secured using the Amazon Cognito user pool we created in the under User Management. Using this configuration we will then turn our statically hosted website into a dynamic web application by adding client-side JavaScript that makes AJAX calls to the exposed APIs.
Create a New REST API
We will use the Amazon API Gateway console to create a new API named WildRydes.
- a) In the AWS Management Console, click Services then select API Gateway under Networking and Content Delivery.
- b) Select Build under REST API.
- c) Choose 'New API' under Create API and enter WildRydes for the API Name.
- d) Choose Edge optimized in the Endpoint Type dropdown. Note: Edge optimized are best for public services being accessed from the Internet. Regional endpoints are typically used for APIs that are accessed primarily from within the same AWS Region.
- e) Choose Create API
Create a Cognito User Pools Authorizer
Amazon API Gateway can use the JWT tokens returned by Cognito User Pools to authenticate API calls. And so in this step we'll configure an authorizer for our API to use the user pool we created earlier.
a) Under your newly created API, choose Authorizers.
b) Chose Create New Authorizer.
c) Enter WildRydes for the Authorizer name.
d) Select Cognito for the type.
e) Enter WildRydes (or the name you gave your user pool) in the Cognito User Pool input.
f) Enter Authorization for the Token Source.
g) Choose Create.
Let's verify our authorizer configuration
h) Open a new browser tab and visit /ride.html under your website's domain.
i) If you are redirected to the sign-in page, sign in with the user you created in the last module. You will be redirected back to /ride.html.
j) Copy the auth token from the notification on the /ride.html,
k) Go back to previous tab where you have just finished creating the Authorizer
l) Click Test at the bottom of the card for the authorizer.
m) Paste the auth token into the Authorization Token field in the popup dialog.
n) Click Test button and verify that the response code is 200 and that you see the claims for your user displayed.
Create a new resource and method
We will create a new resource called /ride within our API. Then create a POST method for the resource and configure it to use a Lambda proxy integration backed by the RequestUnicorn function we created previously.
a) Still in the API we just created, by the left nav, click on Resources.
b) From the Actions dropdown select Create Resource.
c) Enter ride as the Resource Name.
d) Ensure the Resource Path is set to ride.
e) Select Enable API Gateway CORS for the resource.
f) Click Create Resource.
g) With the newly created /ride resource selected, from the Action dropdown select Create Method.
h) Select POST from the new dropdown that appears, then click the checkmark.
i) Select Lambda Function for the integration type.
j) Check the box for 'Use Lambda Proxy integration'.
k) Select the Region you are using for Lambda Region.
l) Enter the name of the function you created in the previous module, RequestUnicorn, for Lambda Function.
m) Choose Save.
⚠️ Please note, if you get an error that you function does not exist, check that the region you selected matches the one you used in the previous module.
n) When prompted to give Amazon API Gateway permission to invoke your function, choose OK.
o) Select the Method Request card.
p) Click the pencil icon next to Authorization.
q) Select the WildRydes Cognito user pool authorizer from the drop-down list, and click the checkmark icon.
Deploy Your API
- a) From the Amazon API Gateway console, choose the Actions drop-down list select Deploy API.
- b) Select [New Stage] in the Deployment stage drop-down list.
- c) Enter prod for the Stage Name.
- d) Choose Deploy.
- e) Note the Invoke URL. We will use it in the next configuration.
Update the Website Config
Update the /js/config.js file in your website deployment to include the invoke URL of the stage we just created. You should copy the invoke URL directly from the top of the stage editor page on the Amazon API Gateway console and paste it into the _config.api.invokeUrl key of your sites /js/config.js file.
Make sure when you update the config file it still contains the updates you made in the previous module for your Cognito user pool.
- a) Open the config.js file in a text editor.
- b) Update the invokeUrl setting under the api key in the config.js file. Set the value to the Invoke URL for the deployment stage your created in the previous section.
An example of a complete config.js file is included below.
⚠️ Note, the actual values in your file will be different.
- c) Save the modified file and push it to your Git repository to have it automatically deploy to Amplify Console.
git add .
git commit -m 'RESTful API configuration update'
git push
Validate your Implementation
- a) Visit /ride.html under your website domain.
- b) If you are redirected to the ArcGIS sign-in page, sign in with the user credentials you created previously in the Introduction section as a prerequisite of this tutorial.
- c) After the map has loaded, click anywhere on the map to set a pickup location.
- d) Choose Request Unicorn. You should see a notification in the right sidebar that a unicorn is on its way and then see a unicorn icon fly to your pickup location.
⭐☆★ Congratulations, you have completed the Wild Rydes Web Application Workshop! Now we Clean up.
The Final Act in this series will show you how to terminate all the resources used for this project.
Posted on November 22, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.