Before deploying a new website, it’s useful to show beta versions to clients. In this post, I’m going to explain how I created a web application using a backend app and a frontend app and deploying it in a serverless way using three key Amazon Web Services: Lambda, API Gateway, and S3 storage. After deployment, you can send an API endpoint link to clients so they can view the work-in-progress.
Step 1: Prep backend code for uploading into AWS Lambda Function
For my backend web application I used NodeJS. So to prepare the code to upload into Lambda, I installed the npm serverless-http module from https://www.npmjs.com/package/serverless-http. This module wraps your API for serverless use. In the terminal run the command:
npm i serverless-http
In the index.js, comment out the line that states the port, since we don’t need it:
app.set("port", process.env.PORT || 3001)
At the top of your index.js file, add the require() function, which will add the serverless-http module to your backend:
const serverless = require("serverless-http")
Instead of using app.listen() function,
app.listen(app.get("port"), () => {console.log(`Example app listening at https://localhost:${app.get("port")}`);
});
we will use a handler that invokes the serverless function:
module.exports.handler = serverless(app)
Once you’re done, create a zip file of all your backend code, and move on to Step 2.
Step 2: Create New Lambda Function and Upload Code
Go to Amazon Web Services, and search for Lambda. Once on the main page for Lambda, click on the button that says “Create Function”. Give your function a name, and specify language for your function (Mine is Node.js 14x). Click on “Create Function” again.
Click on “Actions” and “Upload a Zip File”. After the zip file is uploaded, click on “Test”. Here you can see if your Lambda function returns headers and a body successfully.
Congrats! You’re done uploading the backend code. Now let’s create a REST API using the API Gateway.
Step 3: Set up a REST API using AWS API Gateway
Go to the AWS API Gateway page, and click “Create API”. Scroll down through the options until you find REST API. Click on “Build”. Give your API a name, and click on “Create API”. Now you can start setting up requests. Go to the “Actions” button, and click so that you see the drop-down menu. Click on “Create Resource”, and name your resource so that it matches the name of your route. Make sure to tick the box labeled “Enable API Gateway CORS”, because we need to enable CORS policies. CORS stands for Cross-Origin Resource Sharing. In this project we are enabling CORS to allow for requests and responses to take place between our backend and frontend applications.
For example, my first resource looks like this:
Go to “Actions” again, and click on “Create Method”.
Now choose “GET” from the drop down menu, and click on the arrow that appears beside it.
You will now choose an “integration point” for your method, which will be your Lambda Function. Click on “Lambda Proxy Integration”, and type in the name of your Lambda Function. The Lambda Proxy Integration is used so that the API will be responsible for checking for requests' headers and responses' headers.
Click on “Save”, and then “OK” when it asks for permission to use your Lambda Function.
*Be sure not to skip this step; you will get an error message when you try to deploy the API if integration points are not chosen for all methods.
At this point you will want to test the route. Click on the “Test” icon, and then click “Test” again at the bottom of the page. When I click “Test”, the response shows an object filled with the author’s works information.
As you can see, it’s good I tested this route, because my images came through as “undefined”. At this point, I had to backtrack, upload images into AWS S3, retrieve their URLs from the storage Bucket (more on this later!), and for test purposes, hardcoded the URLs into the backend code, upload the code again into a Lambda Function and test the route again. When I tested it again, you can see how the images came through:
Create Resources and Methods for each of your routes, and test each route to make sure it is invoking data from the Lambda function correctly.
For one route that requests a work by ID, it was necessary to create an additional “child” resource using the “Configure as proxy resource” option at the top. For example,
my route is:
/shops/work/:id
I created a “shops” resource, and then under “shops”, I created a “work” resource, and then on the “work” resource, I created the “child” resource that requests the work by ID. Under this /{proxy+} resource, I deleted the wildcard “ANY” method, and created another “GET” method since this is the method I wanted to use.
Test the method to make sure it fetches the correct item by ID.
Once you are finished creating your API endpoints (for example, /card, /shops, etc. that I have above), and have tested each one to make sure the data is being fetched correctly from your Lambda function, create one final GET method under your main / route, at the very top.
Go to the “Actions” button once again, and click “Enable CORS”. You will click on “Enable CORS and replace existing CORS headers”, and then hit “Yes.” on the pop-up window.
Now it’s time to deploy the API. Go to “Actions”, and hit “Deploy API”. Choose [New Stage] and give your Stage a name. Then click on “Deploy”.
After you’ve deployed it, click on your Test API, so that you can see all the routes again, and click on each “GET” method. Make sure “Inherit from Stage” is clicked under Settings, and hit “Save”.
Now go through each method and check the Invoke URL on a new browser to make sure the JSON data is being fetched correctly.
Once you’ve finished, you can move on to Step 4!
Step 4 Prepare your Frontend Code and upload it into S3
Now take this new URL created by your API (for example, mine is: https://uuuqydy5el.execute-api.us-east-2.amazonaws.com/beta) and go to your frontend code.
We will need to insert this URL into the fetch functions in the frontend code, while keeping our routes intact. (Note that inserting URLS into fetch functions is tedious and not a best practice; however for a small project like this one it is OK).
Once you finish updating the fetch functions with your AWS URL, run this command in the terminal of your project:
npm run build
This will create a build folder (for React projects), which can be uploaded to a S3 bucket. The build folder contains the frontend application.
Once this step is finished, you will see a “build” folder added to your project with all the files of your frontend application.
Now it’s time to go back to AWS, and navigate to the S3 page. Click on “Create Bucket”, and name the bucket. Scroll down, and uncheck the option “Block all public access”--and tick the box to agree to the terms. Scroll down again and click “Create Bucket”.
Click on your newly created bucket, and click on the “Upload” option. Now upload all the files from the build folder (upload files as a group; do not upload the folder itself). Before clicking “Upload”, click “Additional Upload Options”, scroll down to Access Control List, and click both boxes for “Everyone (Public Access)”. Agree to terms for this change, and then hit “Upload”. Check to make sure all your files have uploaded, and then go back to the Bucket list.
Click on your bucket, and go to Properties. Scroll all the way down, and click on “Edit” for the Static Website Hosting property. Click on “Enable Static Website Hosting”. Next, specify your index document. In my case, it is “index.html”. Once you’ve entered the name, hit “Save”. This is necessary because we will be using this S3 bucket for a static frontend web application.
Next, go to Permissions. Scroll down to Bucket Policy, and click “Edit”. Here you can specify permissions for your bucket. Bucket policies offer access permissions. I used the following script which allows public access to the bucket objects. You should research what type of policy you need to use for your bucket. (read more here: https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html). If you use the following script, you will want to replace the bold section below with your own Bucket ARN, which is listed at the top of the text space where you paste in the policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::writerwebsite3/"
}
]
}
Next, scroll down to CORS permissions, and click “Edit”. Here you will also save a script that allows resources to be shared between applications. You can use the following:
[
{
"AllowedHeaders": [
""
],
"AllowedMethods": [
"PUT",
"GET",
"POST",
"DELETE"
],
"AllowedOrigins": [
""
],
"ExposeHeaders": []
}
]
After you’ve finished updating your Permissions, go back to Properties, scroll to the bottom, and open up your new Bucket website endpoint! Send this link to your clients so they can check out your progress and give feedback.
Disclaimer: This is a POC to walk you through the process of creating an API endpoint using AWS. Every project varies regarding requirements; therefore, please review the security configuration before deploying your code.
Resources:
https://www.npmjs.com/package/serverless-http
https://docs.aws.amazon.com/lambda/latest/dg/welcome.html
https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html
https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Top comments (0)