In the first part of this blog post, we talked about serverless microservice patterns and started building a human resources application using The Simple Web Service pattern. We’ve already built a web application where Admin users can manage their company departments and employee accounts.
Now, we will manage user data for our app. We will use AWS DynamoDB to store employee information and create a custom GraphQL API called EmployeeActions for accessing this data from our front-end app. Our GraphQL API will be built using AWS Appsync. With these tools, users can perform CRUD operations on their own records and view their colleagues’ personal information, including birthdays.
The Simple GraphQL Service Pattern
Before we start, please beware that this article assumes you have a basic understanding of instrumenting ReactJS and AWS serverless application development framework, called AWS Amplify.
This article may interest you: Introduction to AWS Serverless Application Model
Steps for The Simple GraphQL Service Pattern
- Setting up the Development Environment
- Create DynamoDB and Connect with GraphQL API
- Connect Front-End to API
1. Setting up the Development Environment
First, we must install Amplify CLI on our local machine. Before starting, make sure that the following technologies are installed:
- Node.js v12.x or later
- npm v5.x or later
- git v2.14.1 or later
You can install Amplify CLI with an npm package manager.
npm install -g @aws-amplify/cli
Then you must configure your AWS account with Amplify CLI by using:
npm install -g @aws-amplify/cli
The official AWS Amplify setup guide will help you to install and configure the AWS Amplify CLI. When completing the installation process, navigate to the root folder of our application and run this command:
amplify init
That will ask some questions about your application such as the project name, environment name, build commands, etc. Choose the default values and hit enter.
The next step is to install the necessary dependencies:
npm install aws-amplify @aws-amplify/ui-react
The last part of setting up Amplify is adding this code to your index.js file. This will configure Amplify and allow you to use your cloud resources with your front-end application.
import Amplify from aws-amplify;
import awsExports from ./aws-exports;
Amplify.configure(awsExports);
2. Create DynamoDB and Connect with Graphql API
You can create back-end resources with just amplify add command. We can start building our GraphQL API with this command:
amplify add api
It will ask some questions to provide cloud resources for you. Choose the ones that meet your demands. Defaults will be fine in our demo application.
Now comes the fun part: it is time to design our GraphQL schema. When you hit yes for the “Do you want to edit the schema now?” question, your text editor will open the schema.grapql file for you. In case the file doesn’t get open, you can always find your schema file in amplify/backend/api/{{apiName}}/schema.graphql directory of your application.
For our PurpleHR application, we must store the personal information of our employees, such as name, phone number, birthday, etc. So, we must define an Employee Type in our graphql schema.
type Employees
@model
@auth(
rules: [
{ allow: owner, operations: [read, update] }
{ allow: groups, groups: [Admins], operations: [create, read, update, delete] }
{ allow: groups, groups: [DevOpsTeam, GrcTeam, MarketingTeam, SecurityTeam], operations: [read] }
]
) {
id: ID!
username: String
firstName: String
lastName: String
phoneNumber: String
department: String
certifications: String
birthDay: String
university: String
uniDepartment: String
graduationYear: String
workStartDate: String
hobbies: String
favoriteTeam: String
hometown: String
}
@model directive will provide an AWS DynamoDB table with the given name, connect it with AWS Appsync with all possible CRUD operations ready for our use and create necessary permissions with AWS IAM.
With the @auth directive, we are defining our authorization rules about our type. Remember we have different user groups for different kinds of users on our application. In this example, Admin users can have permissions for all CRUD operations on Employee type. However, individual employees that are a member of one department group can only view the Employee type. After finishing the design of our schema, we can create resources in the cloud by running this push command.
amplify push
It will take up to 5 minutes and then we will have a running live API with all necessary permissions and connection to AWS DynamoDB.
Also see: What is a Web Application Firewall?
3. Connect Front-End to API
Now it is time to provide users with a nice UI for interacting with our application. To make it happen, we need to use an API Client for handling requests from the client-side. We will use graphql client that comes with Amplify package. Let’s build a sample page to list all employees that are in DynamoDB. To achieve this, we must make a list request to our Graphql API, and with the help of AWS Appsync resolvers, we will interact with AWS DynamoDB and get the result then bring it to the front-end.
Open src/App.js file and import React and necessary Amplify packages.
import React, { useState, useEffect } from react;
import { API, graphqlOperation } from aws-amplify;
Then imports the listEmployees query. You can find it in src/graphql/queries.js
import { listEmployees } from ./graphql/queries;
Now we need React state for storing our employee information and show it from the front-end. Since we have already imported the useState from react, in first-line now we can use it like this.
const [employees, setEmployees] = useState(null)
Initially, it starts will a null value because, in the beginning, we don’t have an employee until we get results from the back-end.
Create a JavaScript function that runs our list query and fetches results then sets it to our state.
async function fetchEmployees() {
try {
const result = await API.graphql(graphqlOperation(listEmployees))
setEmployees (result.listEmployees.data.listTodos.items)
} catch (err) { console.log('error fetching employees) }
}
Now, we must run our function when the app mounts for the first time. To make it happen, we must use a side effect called useEffect. It is a React Hook that manages the lifecycle of React components. We imported it in the first line.
useEffect(() => {
fetchEmployees()
}, [])
As you can see, the dependency array of the useEffect is empty because we only want to run this side effect just once when the app mounts. Now, we have our employee state which means that we are ready to render some JSX. In the return part of our component, we can map all employees and return their names for now.
return (
<div>
<h2>PurpleHR</h2>
<h3>Employee List</h3>
{employees && (
<ul>
{employees.map((employee) => (
<li key={code.id}>
{employee.firstName} - {employee.lastName}
</li>
))}
</ul>
)}
</div>
)
Finally, our App.js will look like this:
import React, { useState, useEffect } from 'react'
import { API, graphqlOperation } from 'aws-amplify'
import { listEmployees } from './graphql/queries'
const App = () => {
const [employees, setEmployees] = useState(null)
useEffect(() => {
fetchEmployees ()
}, [])
const fetchEmployees = async () => {
try {
const result = await API.graphql(graphqlOperation(listEmployees))
setEmployees (result.listEmployees.data.listTodos.items)
} catch (err) { console.log('error fetching employees) }
}
return (
<div >
<h2>PurpleHR</h2>
<h3>Employee List</h3>
{employees && (
<ul>
{employees.map((employee) => (
<li key={code.id}>
{employee.firstName} - {employee.lastName}
</li>
))}
</ul>
)}
</div>
)
}
export default App
Conclusion
In this blog post series, we have covered how to successfully create serverless web applications from scratch using AWS services. We have learned how to add authentication and authorization to web applications, create a GraphQL API and use it in front-end React applications. We will be sharing more posts related to these topics, stay tuned!
If you’re interested in maintaining the security of your web applications, we encourage you to take a look at our DevSecOps services.