Diagram of the intended architecture

Full Stack Serverless with AWS SAM

Jörn Kalz
comsystoreply

--

Developing applications with serverless technology facilitates high scalability and allows for significant cost reduction in many use cases. In this article, we will look into setting up a full stack serverless project with AWS Serverless Application Model (AWS SAM).

AWS SAM is a framework for building serverless applications on AWS and it consists of a template specification and a CLI for deploying the application. The template specification is based on CloudFormation templates and provides useful extensions for serverless stacks.

Going through the steps in this article, we will lay the groundwork for a full stack serverless project including CI/CD.

Backend

As a prerequisite, you will need to install and configure AWS SAM. Then create the backend template in the root of your project directory with

sam init --name backend --runtime nodejs14.x \
--dependency-manager npm --app-template hello-world

As the following steps are independent of the runtime you choose for your lambda, you can replace nodejs14.x and npm with any other option; e.g. you can type python3.9 and pip instead.

That’s all we need to do to set up the backend REST API. The initialization creates a CloudFormation templatebackend/template.yaml, which deploys an implicitly defined API Gateway routing to the Lambda handler defined in backend/hello-world/app.js.

Additional AWS Resources

For serving the frontend serverless on AWS, we need to add an S3 bucket in the resource section of backend/template.yaml

Instead of enabling direct website hosting with S3, we will add a CloudFront distribution to be able to support HTTPS, which is a requirement for almost any productive web application.

As you can see, besides the first origin FrontendBucket with the corresponding DefaultCacheBehavior for serving the static website from S3, we also defined a second origin Backend with a corresponding CacheBehavior. The latter proxies our backend REST API at the path /api of the same domain as the static website. This way our backend will not need a CORS configuration and our frontend will not need to know the URL of the API Gateway serving the backend.

To adjust the backend for this solution, we need to change Path: /hello to Path: /api/hello in the predefined HelloWorldFunction resource.

Furthermore, we need to give CloudFront read access to the S3 bucket.

Finally, we provide the domain of the CloudFront distribution in the Outputs section of the template by adding

Frontend

The described solution works with any frontend framework that builds a static website. We will showcase the creation of a React frontend here.

With Node.js installed create the React frontend in the root of your project with

npx create-react-app frontend

To demonstrate the connection to the backend, change the content of frontend/src/App.js to

This will fetch and display a greeting from the generated Lambda.

Manual Deployment

The file structure of the project now looks like this:

├── backend
│ ├── events
│ ├── hello-world
│ │ ├── app.js
│ │ └── ...
│ ├── README.md
│ └── template.yaml
└── frontend
├── public
├── src
│ ├── App.js
│ └── ...
├── package.json
└── README.md

And that’s it. You could deploy the application manually by first running sam build && sam deploy --guided in the folder backend, then npm run build in the folder frontend, and finally copying the content of frontend/build into the S3 bucket. Opening the CloudFront URL in the browser will display the greeting. But here we want to go a step further and set up automated deployment with a CI/CD tool.

CI/CD

For adding CI/CD we will first create the AWS resources required for an automated deployment by running the following command in the backend folder. Replace <R> with an AWS region like us-east-1.

sam pipeline bootstrap --no-interactive --stage dev --region <R>

This will create an IAM user and role for the pipeline, an IAM role for CloudFormation, and an S3 bucket for uploading the artifacts deployed by CloudFormation. You will find the access key id and the secret access key of the created pipeline user in the output of the command.

Next, we need to create a CI/CD pipeline that provides the SAM CLI and the AWS CLI configured with the pipeline user created above. We will demonstrate a solution based on GitHub Actions as an example here. If you want inspiration on how to bootstrap such a pipeline for other CI/CD tools like Jenkins or GitLab, you can generate examples by running sam pipeline init in the backend folder.

To setup GitHub Actions CI/CD commit the project to a newly created GitHub repository and create repository secrets named AWS_SECRET_KEY_ID and AWS_SECRET_ACCESS_KEY with the credentials of the pipeline user.

Now create the actual pipeline file github/workflows/pipeline.yaml

Replace <PIPELINE_EXECUTION_ROLE>, <CLOUDFORMATION_EXECUTION_ROLE> and <ARTIFACTS_BUCKET> with the values you find in backend/.aws-sam/pipeline/pipelineconfig.toml and replace <REGION> with the same region you selected above.

Append the following lines to the pipeline file to check out the repository and to configure the SAM CLI with the pipeline role.

Then we instruct the pipeline to build and deploy the backend.

For deploying the frontend, we first store the generated name of the S3 bucket in an environment variable.

Then we copy the result of building the application into the cleared S3 bucket.

For allowing the pipeline to clear and put objects in S3, we need to adjust the bucket policy in backend/template.yaml by adding a statement to the FrontendBucketPolicy section.

Also add a parameter above the Resources section of backend/template.yaml.

If you commit and push GitHub Actions will deploy our application. In the output of GitHub Actions you will find the URL of the CloudFront distribution. Open this URL in your browser to see the greeting.

Conclusion and Next Steps

In this article, we lay the groundwork for a full stack serverless project including CI/CD with AWS SAM.

The next step could be to set up a custom domain for your application, add a custom error response to your CloudFront distribution to support error handling in single-page applications, or set up forwarding of specific headers and cookies depending on the requirements of your backend.

This blog post is published by Comsysto Reply GmbH

--

--