Developing Two-Tier Web Apps with React and AWS

Harness the power of cloud platforms for accelerated application development

Pavindu Lakshan
Bits and Pieces

--

The two-tier and three-tier models are the widely adopted software architectures in designing full-stack web applications. The three-tier architecture has been popular for a long time due to its benefits, such as better security and scalability.

However, the tables have started turning around with the adoption of cloud platforms. Cloud (serverless) computing makes application development fast and easy while compromising the benefits of implementing the three-tier architecture.

This article will discuss how to use the cloud platforms, specifically AWS, to build better web applications efficiently with the two-tier architecture.

What is Two-Tier architecture?

The two-tier architecture is a client-server architecture where the clients directly access the data layer. Unlike the three-tier architecture, there is no intermediary business logic layer between the presentation and data access layers.

Since the two-tier architecture doesn’t require an intermediary layer, it helps you make web app development rapid and easy. However, due to the simplicity of the architecture, single-tenant apps are preferred to be developed using the two-tier architecture.

Nonetheless, two-tier web apps start to suffer in the face of high scalabilities, such as sudden request hypes. Also, it poses a considerable security threat since the front end is directly connected to the data store. As two-tier architecture is very straightforward, it is usually not recommended to follow this design model in designing multi-tenant applications.

Even though two-tier apps are dying and less popular among developers for the reasons mentioned above, gradually increasing adaption of cloud platforms will change that. With the unique capabilities delivered by AWS via its services, now it’s possible to design and build two-tier apps efficiently while ignoring the traditional roadblocks against it.

Two-Tier Architecture In Practice

Let’s develop and deploy a simple React application using the following technologies to demonstrate how to implement two-tier web architecture on the AWS platform.

The application we will develop is a book app that has users of two types.

  • General users (Users) are people who are logged in to the application. They can perform CRUD operations on the books they have added, but they cannot view the books others have added.
  • Admin users (Admin) can perform every action that the general users can do. In addition, the admins can also view the books added by other users.

The users will be given fine-grained access control to the DynamoDB table via integrated Cognito user pools and identity pools to implement the above requirements.

Setting up the AWS Cloud Environment

First, log into the AWS management console and go to the DynamoDB dashboard to create a new table. Use “pk” and “sk” as the partition key and the sort key.

Then, open the AWS Cognito dashboard and create a new user pool and an identity pool with the default settings. When creating the user pool, ensure that the generate secret option is unticked when creating the app client.

Now, edit the created identity pool and add Cognito as an authentication provider by specifying the user pool ID and the app client ID. Also, set the authentication role to be selected from the token.

Next, go to the IAM console and create a new policy named UserGroupPolicy with the following configuration. This policy allows general users to access only the items/records in the DynamoDB table whose partition keys start with their Cognito identity ID.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:<region>:<aws_account_id>:table/<table_name>"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${cognito-identity.amazonaws.com:sub}"
]
}
}
}
]
}

Create another policy named AdminGroupPolicy with the following configuration that will determine the access level of the admins. This policy grant admins full access to the DynamoDB table.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:<region>:<aws_account_id>:table/<table_name>"
]
}
]
}

Finally, create two roles in the IAM console, named User and Admin and attach the respective policies to the roles. Finally, create two user groups inside the created Cognito user pool, named User and Admin attaching the appropriate role of the above created IAM roles to each group.

Setting up the React Frontend

Create a new React project and initialize AWS Amplify. You should have Amplify CLI already installed.

npx create-react-app <your_app_name>
cd <your_app_name>
amplify init

Amplify helps us implement authentication and authorization in our application. First, run amplify update auth to update the Amplify Auth configuration. When prompted, enter the credentials of the user pool and identity pool created when setting up the AWS cloud environment.

The React app will have several routes. Install React Router and configure the routes in App.js as follows. You also need to create the relevant React components for the routes.

import { Amplify } from "aws-amplify"
import AwsConfig from "./aws-exports"
import { BrowserRouter, Routes, Route } from "react-router-dom"
import AWS from "aws-sdk"

// component imports
import Home from "./views/Home"
import AddOrUpdateBook from './views/AddOrUpdateBook';
import Login from './views/Login';
import Register from './views/Register';

Amplify.configure(AwsConfig)
AWS.config.update({region: process.env.REACT_APP_awsRegion});

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/book" element={<AddOrUpdateBook />}></Route>
<Route path="/" element={<Home />}></Route>
<Route path="/login" element={<Login />}></Route>
<Route path="/register" element={<Register />}></Route>
</Routes>
</BrowserRouter>
);
}

export default App;

Use the Amplify Auth library to implement signing in and signing up functions in the pertinent routes of the React app.

import {Auth} from "aws-amplify"

async function register(e){
e.preventDefault()
try {
await Auth.signUp({username,password,attributes: {email}})
console.log("Successfully signed up!")
} catch (err){
console.error("Error when registering user: "+err)
}
}

Install AWS SDK to interact with the DynamoDB database from the React app.

import {Auth} from "aws-amplify"
import AWS from "aws-sdk"
import { v4 as uuidv4 } from 'uuid';

async function addBook(e){
e.preventDefault()
const userInfo = await Auth.currentUserInfo()
if (userInfo == null){
alert("You first need to log in.")
return
}
const credentials = await Auth.currentUserCredentials()
const docClient = new AWS.DynamoDB.DocumentClient({credentials});

const params = {
TableName : <dynamodb_table_name>,
Item: {
pk: userInfo.id,
sk:"BOOK#" + uuidv4(),
name: bookName,
type: "BOOK",
author: authorName,
price:price
}
};

docClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});

}

Deploying the React App

To begin with, Create an AWS S3 bucket with the default settings. Then, create a CloudFront distribution. Select the created S3 bucket as the origin domain of the CloudFront distribution. Under S3 Bucket Access, choose to create a new OAI and update the bucket policy by CloudFront.

Next, add the following script to scripts in package.json so that the app can be deployed to S3 using the command npm run deploy. You should already have AWS CLI installed and correctly configured for this step to work.

"deploy": "npm run build && aws s3 sync build/ s3://<bucket_name>"

Demo

Copy the CloudFront URL from the Cloudfront distribution dashboard and open it in the browser. You will see the app asking you to log in to view books.

When logged in as a general user, you will only see the books added by you. However, when logged in as an admin user, you will see both your books and others’ books.

You can find the complete code example in my GitHub repository.

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favourite frameworks like React or Node. Build scalable and modular applications with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and speed up, scale, and standardize development as a team. Try composable frontends with a Design System or Micro Frontends, or explore the composable backend with serverside components.

Give it a try →

Conclusion

In this article, we have discussed how to develop a two-tier web app using React for the frontend and the AWS platform services as the backend. We have also focussed on the benefits (Which mostly fit for single-tenant applications) and limitations of the approach.

two-tier architecture makes web app development pretty fast and efficient. But the drawbacks associated with it often push the developers back to choosing the 3-tier architecture for their applications.

Emerging cloud platforms help developers develop two-tier web apps with extra convenience, with the 3-tier model’s benefits. The trend will only go up as organizations across the globe widely embrace cloud computing.

I hope you found this article interesting. Thanks for reading!

Learn more

--

--

Software Engineer at WSO2 | Tech Blogger | Open-source Enthusiast - Views and opinions are strictly my own