Last updated on November 30, 2023
Plenty of full-stack web applications are scattered across the internet nowadays, with varying tech stacks and services utilized to serve their varying purposes. Like with other technologies, as popularity increases, so does the surrounding ecosystem, which manifests in significant improvements in the development cycle. In this article, we will discuss how to build a simple but purposeful, full-stack web application using multiple features of Amazon Web Services. We will focus on the orchestration of the many various services used, with an emphasis on making a streamlined process.
Application Use Case
This application is intended for anyone monitoring reviews, feedback messages, or any form of writing found in digital images. In this example, we will consider messages in screenshots, pictures, or, in future iterations, possibly videos. The base use case of the application is detecting a sentiment from an image, and if the negative sentiment is stronger than the positive sentiment, it will be flagged, and the application can notify certain people.
Overview of the Stack
Whenever we talk about full-stack applications, the key components include the frontend and backend. The backend service can expose (in our case) a RESTful API to facilitate communication between them. To avoid issues during development, it is also helpful to consider where the parts (mentioned above) will be running on (or hosted) so that we can develop with the intent of making easier connections between our moving parts. Lucky for us, plenty of tools are available for this purpose.
Prerequisites
This article will utilize the Serverless framework, which requires locally saved IAM credentials. The credentials should be accessible through the development environment and must come from an account with attached IAM policies to access the above services. One method is to set up an account in the root account using IAM, then get the keys through the `Security Credentials`, then save them in the environment by installing the AWS CLI and running `aws configure`.Â
We will also use Vercel, which can be authenticated using a GitHub account.
Backend
Development
As the title suggests, this application’s core is a serverless function that powers the backend using AWS Lambda. Inside the Lambda function will be the logic behind our application, of which the main goal is to extract text from an image, analyze the sentiment within it, and return this analysis to the front end. To do such, we will also utilize the AWS SDK for Python (boto3) to initialize clients for Amazon Textract for text extraction and Amazon Comprehend for sentiment analysis, all within the Lambda function. Here’s a snippet of the code of the deployed Lambda function.
import json import base64 import boto3 from botocore.exceptions import ClientError import logging # Initialize logging logger = logging.getLogger() logger.setLevel(logging.INFO) # Initialize AWS clients textract = boto3.client(service_name='textract') comprehend = boto3.client(service_name='comprehend') def lambda_handler(event, context): # Log the start of the process logger.info("Processing started") logger.info(f"Event : {event}") logger.info(f"Context : {context}") logger.info(f"Event type : {type(event)}")
AWS Lambda also automatically sends any log entries made in a Lambda function to Amazon CloudWatch. In CloudWatch Logs, the function has its own log group and log stream, which can be used to view any logs made during the function’s runtime.Â
Deployment
There are many ways of deploying the Lambda function for it to be callable as an API, as shown in the Lambda Console, as well as connecting it to a trigger in API Gateway. However, there is an alternative with a more streamlined method of building and deploying Lambda functions through the Serverless framework.Â
The Serverless framework allows a codified approach to build, test, and deploy serverless functions in one place. It uses the details provided through `aws configure` in the CLI to identify the AWS account and perform actions on it.
Critical parts of the Serverless framework include:
- The `handler.py` file, which serves as the code that the serverless function will run
- The `requirements.txt` file, to include all custom libraries in the file
- The `serverless.yml` file, contains the configurations for the lambda function, its IAM Role, and plugins for `requirements.txt`, among others.Â
Serverless then translates the `serverless.yml` file’s syntax into an AWS CloudFormation template, which can then perform the actions configured in the files listed above. The CloudFormation template’s tasks include the packaging and deployment of the Lambda function and provisioning of the role it needs, dependency management, connecting the function to an AWS API Gateway trigger, rollback on failure, and others included in the `serverless.yml` file.Â
Once the Lambda function is built and the configuration files are ready, we can run `serverless deploy` in the directory of the backend of the app, and the steps above will run.
API
Upon running `serverless deploy` in the terminal in the Serverless directory, it returns the API Endpoint provided in AWS API Gateway, which we can then connect to our app.
This API endpoint can now be integrated into our React app, called through whichever functionality (either automated or on click), by sending a Post request containing the data of the image.
const sendImageToLambda = () => { // If the image exists if (imageBase64) { // Make an API call to your Lambda function axios.post( 'https://<some-link>.lambda-url.us-east-1.on.aws/', { imageBase64 } ) .then(response => { // Handle the Lambda response data here console.log('Lambda Response:', response.data); // Extract data from the Lambda response setData(response.data.Data); }) .catch(error => { // Handle errors here console.error('Error calling Lambda function:', error); }); } };
Frontend
Development
There are many ways to do frontend development, following whichever frameworks best suit the app’s needs. In our case, we will use the React library using Typescript, with the build tool Vite, for an even more optimized build process. Building the React app is outside the scope of this article, but documentation links will be provided to get started.
The most important components of the frontend application would be:
- An image uploader and serializer (base64 encoded)
- Sending the picture through an API call (utilizing the `axios` library)
- Parsing and displaying the response of the API call
At this point, it would also be ideal to integrate testing features of the web app, such as logging and testing the API Calls, to ensure that the different parts work together well. If the locally-hosted web app passes all testing and is performing as intended, the app can then be deployed to the cloud to be hosted for other users to access.
React might also prompt you to install React DevTools, an extension that can help in debugging, optimizing performance, understanding the app’s structure, and others.
Deployment
There are also many ways to deploy a React application, but a simple and free option would be to use Vercel. There is also the Vercel CLI that can make deploying any application even faster.
Once Vercel CLI has been installed, all we have to do is to run `vercel` on the terminal in the directory of our React app, login (if we haven’t), and provide the directory. It will automatically detect and deploy our app, which we can inspect and review in our Vercel dashboard.Â
Maintenance and Updates
In the development cycle, it is customary to do CI/CD in case of logical errors in the application or future features we wish to implement. In any case, deploying these future updates is also relatively simple, using both the Serverless framework to deploy to the backend and the Vercel CLI for the frontend.Â
- For any updates to the Lambda function, the configuration file, or other files from the Serverless directory:
-
- Running `serverless deploy` could take some time, depending on how complicated the application and the resources are. To quicken the process, Serverless allows `–config` when deploying and enables the update of select files only.
-
- For any updates to the React app:
-
- Running `vercel` updates the deployed version of the application in Vercel and the dashboard.
-
We can also view the Lambda function and the API in the AWS Console by navigating to the said services.
Final Remarks
Full-stack applications have been a mainstay in the tech world, starting as a beginner project that can grow and scale to a massive user base. As the ease of use in deploying such applications has been rising, this allows us to have lesser overhead and struggle with menial problems in development and deployment. These improvements finally allow us to worry less about how to build the application and to think more about improving the application.
Note that this is only one of the many ways you can go about developing your full-stack web app. Popularity is not the sole consideration when choosing your tech stack. For persistent, compute-heavy applications, attaching an EC2 instance with S3 access could prove to be better. Maybe hosting the web app somewhere else could introduce more features. Decisions like these are important to be considered at the early stages of development to prevent running into issues later on.Â
This article is also a beginner-level application, and many more features, services, and intricacies can be integrated with other applications you may consider building. We encourage you to look deeper into the everyday problems people face, think of what a solution can be, and then think of how to implement the solution.
Lastly, it should be brought into consideration that although AWS offers powerful and effective services, it is important to keep an eye out for any costs that may be incurred. Be sure to activate your AWS Cost Explorer, read through the pricing plans, and utilize the pricing calculator.Â
Thank you, and happy building!
Resources:
https://aws.amazon.com/sdk-for-python/
https://aws.amazon.com/textract/