Back to articles

Building a Full-Stack Serverless Application with React, AWS Amplify, and TypeScript

AuthorMajd Muhtaseb10/27/202510 minutes

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.