Building Real-Time Communication: Harnessing WebRTC with FastAPI Part 2
Published: 2024-03-10 16:35:48

Welcome to the second part of my series where we will be building a google-meet-clone using FastAPI and WebRTC. If you haven't read the previous article you can read it here.

- [Part 1 of the series.](https://dev.to/wassafshahzad/building-real-time-communication-harnessing-webrtc-with-fastapi-part-1-ael)

In this tutorial we will be going through the 💻 meat of things.

## 🔮 On the last episode of DBZ
When we last left, we created a basic hello world app in FastAPI and provided an introductory overview of how WebRTC functions.
Our Folder structure looked something like this.
📁
|-- 🗋 main.py
|-- 🗋 requirements.py
|-- 📁 .env

### 💼 Business at the Front.
So first lets get started with front-end. As described in the previous tutorial we will be using Jinja templates. So create a templates folder in your root directory. The folder structure then becomes the following.

📁
|-- 🗋 main.py
|-- 🗋 requirements.py
|-- 📁 templates
|-- 📁 .env

You can name this folder whatever you want but for consistency, I will be using templates. You can get an overview of jinja [template from here](https://jinja.palletsprojects.com/en/3.1.x/). Don't worry about python dependencies, we handled that in the previous tutorial.

Now create a `main.html` file in templates directory. This will be our entry point and any JS or CSS dependencies or stylesheets will be loaded here.

Paste to following code in `main.html`, We will go over the important part line by line.
```
<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>PeerChat</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    {% block script %} {% endblock %}
    <link href=" https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
    {% block content %} {% endblock %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
``` 
The first important part is the `{% block script %} {% endblock %}`.
This is a Jinja inheritance, which allows us to use this `main.html` as a parent for other templates. Since each child template will need to load its on scripts tags, we use this feature to dynamically load those. You can find more [info here](https://jinja.palletsprojects.com/en/3.1.x/templates/#template-inheritance).
Other then that we are just loading some bootstrap dependencies and creating a block for out content using jinja inheritance mentioned above.

### 🚀 Creating the Home Page
We will be creating a simple Home page with a title, input field and button.
For this create a `home.html` inside the the template directory.
📁
|-- 🗋 main.py
|-- 🗋 requirements.py
|-- 📁 templates
|--   |-- main.html
|--   |-- home.html
|-- 📁 .env

with the following code.
```
{% extends "main.html" %}
{% block script  %}
    <link rel='stylesheet' type='text/css' media='screen' href="{{ url_for('static', path='/home.css') }}">
    <script src="{{ url_for('static', path='/home.js') }}""></script>
{% endblock %}
{% block content %}
    <div class="main-container">
            <div>
                <h1>Video Call for Every One</h1>
                <div class="input-row">
                    <div>
                        <button  type="button" class="btn btn-success" onclick="createRoom()">Create room</button>
                    </div>
                    <div class="input-container">
                        <input id="createRoom" class="form-control" placeholder="Enter room name">
                    </div>
                </div>
            </div>
    </div>
{% endblock %}

```
Don't worry about the CSS or the JS, we will create that later.
Know open up the 🐍 `main.py` and use the following code to load and return templates
Add the following imports
```
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.templating import Jinja2Templates
```
We will be using `Jinja2Templates` here to load the templates.
The following code loads the `templates` object from the templates directory.
```
templates = Jinja2Templates(directory="templates")
```
Add the following code to enable CORS Middleware. Since we will be making requests moving forward.
```
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

```
Now lets update the read_root function and rename it as well while we are at it.
```
@app.get("/")
def home(request: Request):
    return templates.TemplateResponse(request=request, name="home.html")
```
Run the fast application and you should get the following page.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jiu52d51sh45qgdzg1wf.png)

### 🧩 Adding Static files
As you can see we need to add a bit of styling and some onclick functionality to our home page. For that we will be using the static files.
**Static files are files which are downloaded by the client on first load**. Unlike templates which are sent from the server on a per request basis, static files are automatically downloading by the user client (browser) when the first connection is made.

Create a static directory in your root folder. The folder structure becomes something like this.
📁
|-- 🗋 main.py
|-- 🗋 requirements.py
|-- 📁 static
|-- 📁 templates
|--   |-- main.html
|--   |-- home.html
|-- 📁 .env

To load static files from the server, add the following code to `main.py`

```
from fastapi import staticfiles

app.mount("/static", staticfiles.StaticFiles(directory="static"), name="static")
```
In the above code we are telling out application to mount the static directory under `/static` url.

Create a home.css, home.js file under the static directory and add the following code.
for home.css
```
.main-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.main-container * {
    padding-top: 5%;
    padding-bottom: 5%;
}

.input-row {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.input-container {
    width: 70%;
}
``` 
In home.js, add the following
```
let createRoom = () => {
    const roomName = document.getElementById("createRoom").value
    if (roomName){
        window.location.href = `/room/${roomName}`
    }
    else {
        alert("Room Name cannot be empty")
    }
}
```
The above is just a JS funtion which tells the browser to redirect to `/room/roomName` where roomName is the value given in the input field.
Update home.html with the following code
```
{% extends "main.html" %}
{% block script  %}
    <link rel='stylesheet' type='text/css' media='screen' href="{{ url_for('static', path='/home.css') }}">
    <script src="{{ url_for('static', path='/home.js') }}""></script>
{% endblock %}
{% block content %}
    <div class="main-container">
            <div>
                <h1>Video Call for Every One</h1>
                <div class="input-row">
                    <div>
                        <button  type="button" class="btn btn-success" onclick="createRoom()">Create room</button>
                    </div>
                    <div class="input-container">
                        <input id="createRoom" class="form-control" placeholder="Enter room name">
                    </div>
                </div>
            </div>
    </div>
{% endblock %}

```
Here we update the **onclick button property with out function** and **the script block with the valid static file paths**. Now reload the fast app and you Would get Something like this.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qp3f4itqrxc1tfuu75j.png)

### 🧨 Setting up the Video Page.
Create a new template called `video.html` and paste the following code.
```
{% extends "main.html" %}
{% block script  %}
    <link rel='stylesheet' type='text/css' media='screen' href="{{ url_for('static', path='/index.css') }}">
    <script src="{{ url_for('static', path='/index.js') }}""></script>
{% endblock %}
{% block content %}
    <div id="videos">
        <video class="video-player" id="user-1" autoplay></video>
        <video class="video-player" id="user-2" autoplay></video>
    </div>
{% endblock %}
```
Here 2 video players for people who will join the video call.
Now for the css. Create a video.css in the `static` folder and paste the following code.
```
.main-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.main-container * {
    padding-top: 5%;
    padding-bottom: 5%;
}

.input-row {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.input-container {
    width: 70%;
}
```

I think this is good enough for now. In the next tutorial we will wrapping up the RTCpeerConnection logic and the singling server logic.