Create an AWS Lambda function
The first step in adding a serverless backend to your Angular application is to create an AWS Lambda function. Lambda is a serverless compute service that allows you to run code without provisioning or managing servers.
resource "aws_lambda_function" "function_name" {
function_name = "your-function-name"
runtime = "nodejs12.x"
handler = "index.handler"
role = aws_iam_role.iam_role.arn
environment {
variables = {
your_env_variable = "your-value"
}
}
code {
zip_file = file("path/to/your-lambda-function.zip")
}
}
And inside this zip file we might want to hold some code to run...
exports.handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({
message: 'Hello World',
}),
};
};
This function simply returns an object containing a statusCode of 200 and a message body containing a JSON string of the message "Hello World" but it would be SO much more!
Create an IAM Role
In order to execute the Lambda function, an IAM role with the necessary permissions must be created. This role can be created using Terraform.
resource "aws_iam_role" "iam_role" {
name = "your-role-name"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "iam_role_policy" {
name = "your-role-policy"
role = aws_iam_role.iam_role.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": "*"
}
]
}
EOF
}
Create a Lambda API Gateway
Once the Lambda function is created, it needs to be exposed through an API Gateway. The API Gateway will handle the incoming requests and invoke the Lambda function.
resource "aws_api_gateway_method" "method_name" {
rest_api_id = aws_api_gateway_rest_api.api_name.id
resource_id = aws_api_gateway_resource.resource_name.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "integration_name" {
rest_api_id = aws_api_gateway_rest_api.api_name.id
resource_id = aws_api_gateway_resource.resource_name.id
http_method = aws_api_gateway_method.method_name.http_method
type = "AWS"
uri = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${aws_lambda_function.function_name.arn}/invocations"
integration_http_method = "POST"
}
resource "aws_api_gateway_deployment" "deployment_name" {
rest_api_id = aws_api_gateway_rest_api.api_name.id
stage_name = "prod"
}
Deploy the Terraform Configuration
After updating the Angular application, the Terraform configuration can be deployed to create and configure the necessary resources on AWS.
terraform init
terraform apply
Verify the Deployment
As always we should verify what we deploy, to make sure that the serverless backend has been set up correctly, you can test the API Gateway endpoint using a tool like Postman, and check the logs of the Lambda function to ensure that it is being invoked correctly.
Updating the Angular Application
Now that the Lambda function and API Gateway have been created, the Angular application needs to be updated to call the API Gateway endpoint. This can be done by adding an HTTP service in the Angular application, and making a GET request to the API Gateway endpoint.
In order to consume this data in your Angular application, you will need to create an Angular module that makes an HTTP request to the API Gateway endpoint and handle the response data. You can use the HttpClient module from @angular/common/http to make the request.
Here's an example of an Angular service that makes a GET request to the API Gateway endpoint and returns the data:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class HelloWorldService {
constructor(private http: HttpClient) { }
getHelloWorld() {
return this.http.get<any>('https://your-api-gateway-endpoint.execute-api.us-east-1.amazonaws.com/prod/your-resource-path');
}
}
You can then import this service in your component class and call the getHelloWorld() method to retrieve the data like in the following example:
import { Component, OnInit } from '@angular/core';
import { HelloWorldService } from './hello-world.service';
@Component({
selector: 'app-root',
template: '<p> {{ message }} </p>'
})
export class AppComponent implements OnInit {
message: string;
constructor(private helloWorldService: HelloWorldService) {}
ngOnInit() {
this.helloWorldService.getHelloWorld().subscribe((data) => {
this.message = data.message;
});
}
}
This component will now display the message "Hello World" on the webpage when implemented.
It's important to notice that you should replace the url of the API Gateway on the service file with the url of your API Gateway after you deploy it with terraform, also you will need to import HttpClientModule in the root module of your Angular application and import the service in the components that you want to consume the data.
Wrap Up!
As you can see, integrating a serverless backend using AWS Lambda and API Gateway is a great way to add dynamic functionality to your Angular application while also taking advantage of the scalability and cost-efficiency of serverless compute.
By using Terraform, we can automate the process of creating and configuring the necessary resources, making the deployment process faster and more efficient. Remember to verify the backend and the frontend are correctly deployed, and test the API Gateway endpoint to check the Lambda function is being invoked correctly.