Introduction
I have always been interested in developing a financial web application to help me manage my income and expenses. There are numerous financial tracking applications available, but I find it challenging to form a habit of using them to manage my finances. When I heard that Hashnode was organizing an AWS Amplify Hackathon, I seized the opportunity to create my own web-based financial application. Let's see how well AWS Amplify can assist me with this project. In this article, I'll share my experience and demonstrate how AWS Amplify facilitated the process.
AWS Amplify is not a new tool or framework created by Amazon; it has existed for several years. AWS Amplify offers an array of tools that simplify building full-stack applications using AWS services, even without cloud expertise. Additionally, AWS Studio provides a visual interface for effortlessly constructing UI libraries, building data models, and managing content.
Business Logic
The users will be able to record their daily expenses and incomes on this web application. A beautiful visualization is provided to show the summary of their financial conditions.
Another feature is the ability to connect to their own bank accounts. This allows the application to retrieve all of the transactions made using their bank account. It utilizes the API built by GoCardless (formerly Nordigen).
Project Setup
The following technology stacks are used.
AWS Amplify CLI
AWS Amplify UI for front-end components
AWS Libraries, i.e., Authentication, In-App Messaging, DataStore (GraphQL), Lambda/ Function, DynamoDB, Hosting
Javascript & ReactJS
Data Modelling
The data model can be created directly using AWS Studio. For this project, a simple model is designed to store all financial records. When creating a model, the corresponding forms are automatically generated and can be seamlessly integrated into the code. This undoubtedly saves a significant amount of time.
This is the modified version of the generated form.
Front-End Development
One of the best features offered by AWS Amplify is the ability to convert your design figma files to react code directly. As a person who does not have deep experience and knowledge regarding front-end development, this helps a lot.
For this project, I used the template figma file made by AWS Amplify which contains some front-end components that are beautiful and ready to use.
$ amplify pull
amplify push
and amplify pull
commands are used a lot in this project.
Although some components can be directly used, some style modifications are still required to make the UI components look nice. The most common examples are width, padding, margin, etc. On the other hand, it is also easy to override component styles generated by AWS Amplify.
I used UI components generated by AWS Amplify and built custom UI components for this project.
UI Routing
I am using react-router-dom
library to manage the routes between UI components. It is very easy to navigate from one page to another page. Here on App.js
, we can specify the routes for the application.
import './App.css';
import Home from './pages/home';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Login from './pages/login';
import Contact from './pages/contact';
import Dashboard from './pages/dashboard';
import Records from './pages/records';
import SyncBank from './pages/syncBank';
import SyncBankFinish from './pages/syncBankFinish';
import Profile from './pages/profile';
function SiteRoutes() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/sync-bank" element={<SyncBank />} />
<Route path="/sync-bank-finish" element={<SyncBankFinish />} />
<Route path="/profile" element={<Profile />} />
<Route path="/records" element={<Records />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
</Routes>
</BrowserRouter>
)
}
function App() {
return (
<SiteRoutes />
);
}
export default App;
Data Collection UI
The template figma file by AWS Amplify team helped me a lot in building this page. With Amplify Studio, we can link each field to the data model directly.
For example, the label
can be directly linked to the name
field of the Record
model. No code change is required anymore.
Once everything is set, a new collection can be created by clicking the "Create Collection" button. The newly generated Collection component can be directly incorporated into the code.
Profile
On this page, I would like to show the user information. Thanks to AWS Studio, it is very easy to build this page without having to change the code. As shown in the pictures below, we can specify the value of each field directly in AWS Studio. Here I linked the 'Full name' field to user.name
and the 'Email' field to user.email
.
The code is quite simple.
import NavBarHeader2Override from '../components/NavBar';
import { Divider, Flex, Heading } from '@aws-amplify/ui-react';
import { EditProfile, MarketingFooterSimple } from '../ui-components';
import '../App.css';
export default function Profile() {
return (
<Flex direction={'column'} height={'100vh'}>
<NavBarHeader2Override width={'100%'} />
<Flex
direction={'column'}
margin={'25px auto'}
grow={'1'}
>
<Heading level={4}>Your Profile</Heading>
<Divider />
<EditProfile />
</Flex>
<Flex>
<MarketingFooterSimple
width={'100%'}
/>
</Flex>
</Flex>
);
}
Here is the result.
Dashboard UI
This is the page where the user can see the summary of their finances.
I had to construct this page manually from scratch. Ideally, one could create this page using Figma and later import it into AWS Studio, but due to my limited knowledge of Figma, I opted to code it manually using the AWS Amplify UI Library.
The final version of this file is quite complex, as it requires numerous API calls to retrieve the financial records from the database. These records are then processed and presented visually. The complete source code can be found in the GitHub repository for this project.
I would like to emphasize the ability to override components as desired. On this page, I want to display only the most recent 8 records. I can repurpose the existing data collection UI component and simply need to overwrite some of its properties.
// Dashboard.js
// ...
const [records, setRecords] = useState([])
useEffect(() => {
const fetchRecords = async () => {
try {
const records = await DataStore.query(Record, Predicates.ALL, {
sort: (s) => s.transactionDate(SortDirection.DESCENDING)
})
return records;
} catch (error) {
console.log("Error fetching records", error)
}
}
fetchRecords().then((_records) => {
setRecords(_records.slice(0, 8)) // Take top 8
// ...
<Flex
direction={'column'}
alignItems={'center'}
padding={'50px 0px 50px 0px'}
>
<Heading level={5}>Latest 8 records</Heading>
<Divider />
// Here, we re-use DataRowCollection
<DataRowCollection
width={'100%'}
margin={'0 auto'}
items={records}
isPaginated={false}
/>
<Button>
View all
</Button>
</Flex>
Now let's check the back-end.
Back-End Authentication
Every web application especially Saas application needs authentication. It is important yet so annoying to setup in some cases. AWS Amplify offers an authentication feature that can be used directly in the project. It also provides built-in UI that can be easily integrated into the codebase.
$ amplify add auth
...
$ amplify push
The built-in Login/ Sign-Up UI component is called <Authenticator />
which can be integrated directly into the project
To check if the user is authenticated or not, we can use useAuthenticator
. We can also get some user attributes from this method.
Here is an example of how it is being used.
import NavBarHeader2Override from '../components/NavBar';
import '../App.css';
import { Authenticator, Flex, View, useAuthenticator } from '@aws-amplify/ui-react';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
export default function Login() {
const { route } = useAuthenticator((context) => [context.route])
const navigate = useNavigate()
useEffect(() => {
if (route === 'authenticated') {
navigate('/dashboard', { replace: true })
}
}, [route, navigate])
return (
<>
<NavBarHeader2Override
width={'100%'}
/>
<View
textAlign={'center'}
marginTop={'5rem'}
>
<Authenticator />
</View>
</>
);
}
In-App Messaging
In-App messaging is essentially a notification system. We can use this feature to show certain messages based on certain events. For example, we can show a welcome message for a first-time user.
In this project, I incorporated in-app messaging to be able to show a welcome message for first-time users and to show interesting promos/ offers if any.
Somehow the default in-app messaging UI does not look nice (i.e., the layout does not look nice). Fortunately, it is possible to customize it.
Incorporating In-app messaging is quite easy and does not require huge changes. We need to wrap our react class with withInAppMessaging
. Here a ModalMessage
with a custom style is injected. Here is a code snippet showing the main changes for enabling in-app messaging.
const StyledModalMessage = (props) => (
<InAppMessageDisplay.ModalMessage
{...props}
style={{
container: { backgroundColor: 'antiquewhite' },
body: { padding: '50px 0px 150px 0px' },
}}
/>
);
const myFirstEvent = { name: 'first_event' };
function Dashboard() {
// ... rest of code
useEffect(() => {
///...
InAppMessaging.syncMessages();
setTimeout(() => {
InAppMessaging.dispatchEvent(myFirstEvent);
}, 3000)
}
}
export default withInAppMessaging(Dashboard, {
components: {
ModalMessage: StyledModalMessage,
}
})
Here is another example how it is used on another page.
Automatic Bank Synchronization
Another primary feature of this project is the automatic synchronization of the user's bank account. Instead of manually entering expenses one by one each day, it is far more convenient to import all transactions directly from the bank account. Users no longer need to expend their energy and time on data entry, and can instead focus on managing their financial life from a broader perspective.
After the user selects the bank they wish to synchronize with, they will be redirected to another page where they must authorize the process. Once the request is accepted, the API will retrieve the transactions from the bank account and add them to the application database.
AWS Lambda and DynamoDB
This feature is implemented as an API running on an AWS Lambda function. Running this function on the client side is not secure, as it requires an access token key. By executing it on the server side, the process becomes significantly safer. There is no need to expose the API access keys on the client side.
To enhance security, the access keys are stored using AWS System Manager. This can be configured during the creation of the Lambda function using the Amplify CLI. The impressive aspect is that the CLI also generates an example demonstrating how to access the secured access keys.
As this feature relies on the Nordigen API (specifically, the nordigen-node
package), I created a new layer where the nordigen-node
package is installed. The Lambda function utilizes the layer to access the Nordigen API. The benefits of this approach include faster function deployments and enhanced reusability.
I also configured the Lambda function to have access to DynamoDB. The goal is to store the access token key instead of creating a new one every time the Lambda function is triggered. The only way to store this token is by using DynamoDB, as Lambda functions are not persistent.
Deploying and Hosting
After completing all the necessary steps, the final stage is quite simple using the AWS Amplify CLI. I opted for the "Amazon CloudFront and S3" option to host my application.
$ amplify add hosting
? Select the plugin module to execute … (Use arrow keys or type to filter)
Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
❯ Amazon CloudFront and S3
$ amplify publish
Try It
Feel free to try this application. You can access it on https://main.d3rh19oqr156z0.amplifyapp.com/. Here is the login information.
Email: just.aries.123@gmail.com.
Password: P@ssw0rd
Conclusion
That's it for this article. Thank you so much for spending time reading this article.
What's my take on this? This article emphasizes how I use AWS Amplify to create a SaaS application. Utilizing AWS Amplify significantly accelerates my development process. I can effortlessly construct the front-end portion and some fundamental back-end components, such as authentication and data models. Once the basics are in place, I can concentrate my energy and time on developing the core business logic and components. This ultimately leads to a more efficient and enjoyable development experience.
I hope it is useful and can convince you to start exploring AWS Amplify as well.
The full source code can be found in ariesgun/amplify-personal-finance (github.com)
This project is submitted to the AWS Amplify Hackathon 2023 on Hashnode.
#AWSAmplify #AWSAmplifyHackathon