Complete course on using React and FastAPI in an Event-Driven Architecture

Posted by


In this tutorial, we will dive into the world of Event-Driven Architecture (EDA) using React and FastAPI to build a full-stack application. Event-Driven Architecture is a design pattern that promotes the production, detection, consumption, and reaction to events happening within a system. In this tutorial, we will build a simple chat application to showcase the power of EDA.

Prerequisites:

  • Basic understanding of React and FastAPI
  • Node.js installed on your machine
  • Python installed on your machine
  • Visual Studio Code or any code editor of your choice

Let’s get started by setting up our project!

  1. Setting up the backend with FastAPI:
    First, create a new directory for your project and navigate to that directory in your terminal. Then, run the following commands to set up a new Python virtual environment and install FastAPI.
python -m venv venv
source venv/bin/activate
pip install fastapi uvicorn

Next, create a new file named main.py and add the following code to create a simple FastAPI server.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

To run the FastAPI server, use the following command in your terminal:

uvicorn main:app --reload

You should now be able to access your FastAPI server at http://localhost:8000.

  1. Setting up the frontend with React:
    Now, let’s set up the frontend of our application using React. In your project directory, run the following commands to create a new React app using Create React App.
npx create-react-app frontend
cd frontend
npm start

This will start a development server for your React app at http://localhost:3000.

  1. Building the chat application:
    In our chat application, we will showcase how EDA can be used to send and receive messages in real-time.

First, let’s add a textbox and a button to our React app to send messages. Open the App.js file in the src directory and modify it as follows:

import React, { useState } from 'react';

function App() {
  const [message, setMessage] = useState('');

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  }

  const sendMessage = () => {
    // Add code to send message
  }

  return (
    <div>
      <input type="text" value={message} onChange={handleMessageChange} />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
}

export default App;

Next, we need to send the message inputted by the user to our FastAPI server. We will use Axios, a promise-based HTTP client for the browser and node.js, to make API requests. Install Axios by running the following command in your frontend directory:

npm install axios

Now, modify the sendMessage function in App.js to send the message to the FastAPI server when the user clicks the Send button:

import axios from 'axios';

const sendMessage = () => {
  axios.post('http://localhost:8000/send-message', { message })
    .then(response => {
      console.log(response.data);
    })
    .catch(error => {
      console.error(error);
    });
}
  1. Implementing Event-Driven Architecture:
    To implement Event-Driven Architecture in our chat application, we will use a message broker called RabbitMQ. RabbitMQ is a popular open-source message broker that supports multiple messaging protocols.

First, install RabbitMQ on your machine by following the instructions on the official website: https://www.rabbitmq.com/download.html

Next, we need a library to interact with RabbitMQ in our FastAPI server. Install the pika library by running the following command in your backend directory:

pip install pika

Now, modify the main.py file in your backend directory to handle incoming messages from the frontend and publish them to RabbitMQ:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='messages')

@app.post("/send-message")
async def send_message(message: str):
    channel.basic_publish(exchange='', routing_key='messages', body=message)
    return {"message": "Message sent"}

In this code, we establish a connection to RabbitMQ and declare a queue named messages. When a message is received at the /send-message endpoint, it is published to the messages queue in RabbitMQ.

  1. Consuming messages from RabbitMQ:
    Now, let’s consume the messages published to the messages queue in RabbitMQ and send them to the frontend in real-time. Modify the main.py file in your backend directory as follows:
from fastapi import WebSocket

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue='messages')

    for method_frame, properties, body in channel.consume('messages', inactivity_timeout=1):
        if method_frame:
            await websocket.send_text(body.decode())

    connection.close()

In this code, we establish a WebSocket connection with the frontend and consume messages from the messages queue in RabbitMQ. As soon as a message is received, we send it to the frontend using the WebSocket connection.

  1. Connecting the frontend to the WebSocket:
    Finally, we need to connect the frontend to the WebSocket endpoint in our FastAPI server to receive messages in real-time. Modify the App.js file in your frontend directory as follows:
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [message, setMessage] = useState('');
  const [messages, setMessages] = useState([]);

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  }

  const sendMessage = () => {
    axios.post('http://localhost:8000/send-message', { message })
      .then(response => {
        console.log(response.data);
      })
      .catch(error => {
        console.error(error);
      });
  }

  useEffect(() => {
    const socket = new WebSocket('ws://localhost:8000/ws');
    socket.onmessage = (event) => {
      setMessages([...messages, event.data]);
    }

    return () => {
      socket.close();
    }
  }, []);

  return (
    <div>
      <input type="text" value={message} onChange={handleMessageChange} />
      <button onClick={sendMessage}>Send</button>
      <ul>
        {messages.map((msg, index) => (
          <li key={index}>{msg}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

In this code, we establish a WebSocket connection with the /ws endpoint in our FastAPI server. Whenever a message is received, we update the messages state in our React app to display the message in real-time.

And that’s it! You have successfully built a chat application using Event-Driven Architecture with React and FastAPI. This tutorial covered the basics of EDA and how it can be implemented in a full-stack application. Feel free to further enhance the app with more features and functionalities using EDA. Happy coding!

0 0 votes
Article Rating
31 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
@DanielOliveira-mb1gc
1 month ago

I learned a lot, thanks for the class !

@puseletsomaraba1313
1 month ago

Thank you,this EDA illustration with the cloud DB and Python was 10/10,highly grateful ,may the Lord Jesus Christ bless you for all the hard work you put in.

@anton-r
1 month ago

nice tutorial, big thx !!

@yannb1221
1 month ago

Why pass the CREATE_DELIVERY type in the HTTP call since the URL used is deliveries/create ?
Can't the type be simply defined the the app.post(deliveries/create) endpoint ?
I don't get why this would be the client that define the event type.

@maksimkisliak4782
1 month ago

this tutorial could be brilliantly explained for dumb newbies like me, but thanks anyway, it's free after all

@yunocchika
1 month ago

This rocks!

@michahachua1312
1 month ago

This won't work by default because there's no value set to Redis so why bother?

@charlemagne7460
1 month ago

Poor content and not enough explanation. For instance, at 1:06:22 he deletes code and copy-pastes other, without explanation of the philosophy.

@illker.
1 month ago

using postman with fastapi 🤨🫣

@junyoungchoi1706
1 month ago

Seems you've forgotten to push commits of the frontend code repo.

@stuartjacobs
1 month ago

Thanks Antonio. Took me most of a day to complete but learnt a ton. Big thanks!

@sallysaunby7983
1 month ago

Despite the economic downturn, I'm happy ☺️. I have been earning $60,200 returns from my $10,000 investment every 13 days

@leniedor733
1 month ago

31:30 As we modifying a resource , "dispatch" method should be a "put" method?

@yosuahalim5149
1 month ago

why I got TypeError: unsupported operand type(s) for |: 'dict' and 'dict' when trying to update the status?

@Shutupalready47
1 month ago

So I understand the need for recreating the delivery’s current state from event history, but how important is it in this case? Since the database is Redis, wouldn’t a failure wipe both the event history AND the delivery state history?

In a real-world application, would the events be backed up somewhere else? I’m picturing the build_state function pulling from a separate, slower database.

I guess redis cloud is handling the backups, but then it seems like we’re expecting redis to lose deliveries but not events for some reason

@aiFeeling
1 month ago

Can you tell me about the dart programming language? Plzz guys 🙏

@thesofaclipsguy
1 month ago

You can make a video exploring GDevelop and Explaining everything about that.. Please?

@Peter-yd2ok
1 month ago

Please make a full angular course

@leniedor733
1 month ago

9:57 decoding is not need, Decode from UTF-8 by default is set (true is the default)

@Alex-bc3xe
1 month ago

Angular will be awesome