Building a Full-Stack Serverless Application with React, AWS Amplify, and TypeScript
Introduction
This article demonstrates how to quickly build a full-stack serverless application using React for the frontend, AWS Amplify for managing backend services, and TypeScript for a type-safe codebase. We'll focus on a basic application that allows users to create and display notes.
Prerequisites
- An AWS account
- Node.js and npm installed
- Basic knowledge of React and TypeScript
Setting Up the Amplify Project
First, install the Amplify CLI:
npm install -g @aws-amplify/cli
Configure Amplify with your AWS account:
amplify configure
Create a new React application with TypeScript:
npx create-react-app my-notes-app --template typescript
cd my-notes-app
Initialize Amplify in your project:
amplify init
Answer the prompts to configure your Amplify project.
Adding Authentication
Add authentication using Amplify:
amplify add auth
Accept the default configuration. Push the changes to AWS:
amplify push
Creating the API
Now, add an API using GraphQL:
amplify add api
Select "GraphQL" as the API type and accept the default schema. Push the changes:
amplify push
Amplify will generate a GraphQL schema, resolvers, and database tables (using DynamoDB) based on your chosen configuration.
Connecting React to the API
Install the necessary Amplify libraries:
npm install aws-amplify @aws-amplify/ui-react
Configure Amplify in your src/index.tsx file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Amplify } from 'aws-amplify';
import awsconfig from './aws-exports';
import '@aws-amplify/ui-react/styles.css';
Amplify.configure(awsconfig);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
aws-exports.js: This file should have been created when amplify push was used.
Building the UI
Here's a simple React component for creating and displaying notes (App.tsx):
import React, { useState, useEffect } from 'react';
import { API, graphqlOperation } from 'aws-amplify';
import { withAuthenticator, Button, Heading, Input, Text, Flex, Card } from '@aws-amplify/ui-react';
import { listNotes } from './graphql/queries';
import { createNote, deleteNote } from './graphql/mutations';
import '@aws-amplify/ui-react/styles.css';
interface Note {
id: string;
name: string;
description: string;
}
const App = ({ signOut, user }: any) => {
const [notes, setNotes] = useState<Note[]>([]);
const [noteName, setNoteName] = useState('');
const [noteDescription, setNoteDescription] = useState('');
useEffect(() => {
fetchNotes();
}, []);
async function fetchNotes() {
const apiData: any = await API.graphql(graphqlOperation(listNotes));
setNotes(apiData.data.listNotes.items);
}
async function addNote() {
if (!noteName || !noteDescription) return;
const note = { name: noteName, description: noteDescription };
await API.graphql(graphqlOperation(createNote, { input: note }));
setNotes([...notes, note]);
setNoteName('');
setNoteDescription('');
fetchNotes();
}
async function removeNote(note: Note) {
if (!note?.id) return;
const input = {id: note.id};
await API.graphql(graphqlOperation(deleteNote, {input: input}));
let newNotes = notes.filter((currentNote) => currentNote.id !== note.id);
setNotes(newNotes);
}
return (
<Flex direction="column">
<Heading level={1}>My Notes App</Heading>
<Text>Hello {user.username}</Text>
<Button onClick={signOut}>Sign Out</Button>
<Input
placeholder="Note Name"
value={noteName}
onChange={(e) => setNoteName(e.target.value)}
/>
<Input
placeholder="Note Description"
value={noteDescription}
onChange={(e) => setNoteDescription(e.target.value)}
/>
<Button onClick={addNote}>Add Note</Button>
{notes.map((note: Note, index) => (
<Card key={index}>
<h2>{note.name}</h2>
<p>{note.description}</p>
<Button onClick={() => removeNote(note)}>Delete note</Button>
</Card>
))}
</Flex>
);
};
export default withAuthenticator(App);
Ensure that your graphql/queries.js, graphql/mutations.js have been generated. These should have been created when you ran amplify push.
Conclusion
This example provides a foundation for building more complex serverless applications using React, AWS Amplify, and TypeScript. You can expand upon this by adding more features, such as image uploading, user profiles, and real-time updates.