Build a fullstack twitter clone using Flask and React | PART 1
Tags: react, python, tutorial, webdev
Published: 2020-06-11 08:20:15

Hello, community! It's my first post here, and in this post, I want to show you how you can make a simple fullstack twitter clone using React and Flask. This will be a 3 part series and in this part, we will build the application.

Before we start, I assume you know flask, react, javascript, python and html

---

## Project setup
I will be using VSCode as my IDE, but you can use anything you like (Pycharm, Webstorm, Atom are some examples). I'll be showing instructions for my IDE.

### Creating our project
Create a folder which will house your project and open a terminal window there. I like to do things using the UNIX terminal (BASH SHELL), but, you can use a GUI based file explorer too. Let's create the `backend` folder.
```
mkdir backend
```
I'll use `create-react-app` to create the `frontend` folder with a react app initialised.
```bash
npx create-react-app frontend
```

Now, you should have 2 folders, frontend and backend.
```bash
$ ls
backend
frontend
```

Nice! Now, let's set up the backend. `cd` into the backend folder and create a virtual environment for flask. 
*You can use `pipenv` or not use a virtual environment at all!*
```bash
python3 -m venv venv && . venv/bin/activate
```
That should create a virtual environment named `venv` and activate it. Now, `cd` into our main project folder and open it using VSCode by typing `code .`.

---

### Creating a basic `Flask` project
Now, let's set up the backend. First, we need to install flask.
```bash
pip install flask
```
*Make sure your virtualenv is activated*

Now, create a file named `app.py`. This will be the main file for our backend.
```python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello, world!"

if __name__ == "__main__":
    app.run(debug=True) # debug=True restarts the server everytime we make a change in our code
```

Now, let's run the backend by typing
```bash
python3 app.py
```
Let's test if the server works. You can visit [localhost:5000](http://localhost:5000) in your browser or use a `REST Client` like [Insomnia]("https://insomnia.rest") if you want. For testing post methods, I'll be using `cURL`, which is a command-line utility, but you can use a GUI REST Client.

For a database, we can use something called `Flask-SQLAlchemy`, which is `SQLAlchemy` or `sqlite3` for `Flask`. Let's first shutdown our server by pressing `CTRL + C` to terminate it and let's install `flask-sqlalchemy`.
```bash
pip install flask-sqlalchemy
```

Now, back in `app.py`, let's import `flask-sqlalchemy`.
```python
from flask_sqlalchemy import SQLAlchemy
```

And under where we defined `app`, write this code:
```python
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///twitter.db"

# DB
db = SQLAlchemy(app)
class Users(db.Model):
    id = db.Column('student_id', db.Integer, primary_key = True) # primary_key makes it so that this value is unique and can be used to identify this record.
    username = db.Column(db.String(24))
    email = db.Column(db.String(64))
    pwd = db.Column(db.String(64))

    # Constructor
    def __init__(self, username, email, pwd):
        self.username = username
        self.email = email
        self.pwd = pwd
```

So what this code does, is first, it sets our database file as `twitter.db`. You can change this name if you want. Then, the `users` class you see is a `Model`, which lays out what your `users` table's columns are. Pretty standard SQL Stuff.

Now, temporarily, above the `return` statement in the `index` function write this:
```python
db.create_all()
```
Your file should look like this:
```python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///twitter.db"

# DB
db = SQLAlchemy(app)
class Users(db.Model):
    id = db.Column('student_id', db.Integer, primary_key = True) # primary_key makes it so that this value is unique and can be used to identify this record.
    username = db.Column(db.String(24))
    email = db.Column(db.String(64))
    pwd = db.Column(db.String(64))

    # Constructor
    def __init__(self, username, email, pwd):
        self.username = username
        self.email = email
        self.pwd = pwd

@app.route('/')
def index():
    return "Hello, world!"

if __name__ == "__main__":
    app.run(debug=True)
```

Start the server and visit [localhost:5000](http://localhost:5000) or perform a `GET` request using your favorite `REST` client. For example, in `cURL`, you'd type
```
curl "http://localhost:5000"
```
And you should get the same response back, but now, when you look in your folder, you can find a new file called `twitter.db` created. This is your database. Unlike something like `MYSQL`, `MariaDB` or `MongoDB`, `sqlite` does not need a server to function.

---

## Basic CRUD routes

Now, let's perform some basic `CRUD` (**C**reate **R**ead **U**pdate **D**estroy) actions by adding some more routes to our app. First, delete the index route entirely. We won't be needing it. I'm gonna prefix all of my routes with `/api`.
```python
@app.route("/api/users", methods=["GET", "POST", "DELETE"])
def users():
    method = request.method
    if (method.lower() == "get"): # READ
        users = Users.query.all()
        return jsonify([{"id": i.id, "username": i.username, "email": i.email, "password": i.pwd} for i in users]) # Get all values from db
    elif (method.lower() == "post"): # CREATE
        try:
            username = request.json["username"]
            email = request.json["email"]
            pwd = request.json["pwd"]
            if (username and pwd and email): # Checks if username, pwd or email are empty
                try:
                    user = Users(username, email, pwd) # Creates a new record
                    db.session.add(user) # Adds the record for committing
                    db.session.commit() # Saves our changes
                    return jsonify({"success": True})
                except Exception as e:
                    return ({"error": e})
            else:
                return jsonify({"error": "Invalid form"}) # jsonify converts python vars to json
        except:
            return jsonify({"error": "Invalid form"})
    elif (method.lower() == "delete"): # DESTROY
        try:
            uid = request.json["id"]
            if (uid):
                try:
                    user = Users.query.get(uid) # Gets user with id = uid (because id is primary key)
                    db.session.delete(user) # Delete the user
                    db.session.commit() # Save
                    return jsonify({"success": True})
                except Exception as e:
                    return jsonify({"error": e})
            else:
                return jsonify({"error": "Invalid form"})
        except:
            return jsonify({"error": "m"})
```
* We'll work on the PUT method a bit later *
Now, we have a route in our app called `/api/users`. We can perform Create, Read and Destroy actions through different HTTP methods. More about that [here](https://www.tutorialspoint.com/http/http_methods.htm)

Now, this is what our code should look like:
```python
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///twitter.db"

# DB
db = SQLAlchemy(app)
class Users(db.Model):
    id = db.Column('student_id', db.Integer, primary_key = True) # primary_key makes it so that this value is unique and can be used to identify this record.
    username = db.Column(db.String(24))
    email = db.Column(db.String(64))
    pwd = db.Column(db.String(64))

    # Constructor
    def __init__(self, username, email, pwd):
        self.username = username
        self.email = email
        self.pwd = pwd

# Routes

# Users
@app.route("/api/users", methods=["GET", "POST", "DELETE"])
def users():
    method = request.method
    if (method.lower() == "get"): # READ
        users = Users.query.all()
        return jsonify([{"id": i.id, "username": i.username, "email": i.email, "password": i.pwd} for i in users]) # Get all values from db
    elif (method.lower() == "post"): # CREATE
        try:
            username = request.json["username"]
            email = request.json["email"]
            pwd = request.json["pwd"]
            if (username and pwd and email): # Checks if username, pwd or email are empty
                try:
                    user = Users(username, email, pwd) # Creates a new record
                    db.session.add(user) # Adds the record for committing
                    db.session.commit() # Saves our changes
                    return jsonify({"success": True})
                except Exception as e:
                    return ({"error": e})
            else:
                return jsonify({"error": "Invalid form"}) # jsonify converts python vars to json
        except:
            return jsonify({"error": "Invalid form"})
    elif (method.lower() == "delete"): # DESTROY
        try:
            uid = request.json["id"]
            if (uid):
                try:
                    user = Users.query.get(uid) # Gets user with id = uid (because id is primary key)
                    db.session.delete(user) # Delete the user
                    db.session.commit() # Save
                    return jsonify({"success": True})
                except Exception as e:
                    return jsonify({"error": e})
            else:
                return jsonify({"error": "Invalid form"})
        except:
            return jsonify({"error": "m"})
                return ({"error": "Invalid form"})
        except:
            return ({"error": "Invalid form"})

if __name__ == "__main__":
    app.run(debug=True)
```
Let's give this man a test drive!
First, lets perform a `GET` request to `/api/users`.
```shell
curl "http://localhost:5000/api/users"
# OUTPUT: []
```
*We get an empty array because the database has no data*

Now, let's give it some data. Perform a `POST` request to `/api/users` with some data.
```shell
curl -X POST -H "Content-Type: application/json" -d '{"username": "foo", "email": "foo@bar.com", "pwd": "bar"}' "http://localhost:5000/api/users"
```
If you `GET` the data again, you can notice a record has been made. Now, let's delete a user
```shell
curl -X DELETE -H "Content-Type: application/json" -d '{"id": 1}' "http://localhost:5000/api/users"
```
And if we query the data, we should get back an empty string! We'll do `PUT` later.

And that should be it (for now) for our flask application. Go ahead and stop the server(`^C`)

---

## Creating the frontend

Now, let's focus on the frontend. Open the `frontend` folder (or whatever you called it) in the terminal and type:
```shell
npm start
```
This should open a webpage at [localhost:3000](http://localhost:3000) and you should see this:
![localhost:3000](https://dev-to-uploads.s3.amazonaws.com/i/1a85ajnvixrwol634cck.png)

### Creating the homepage
The default template `create-react-app` gives us is not what we need, so, let's delete the content of our `public` and `src` folder. You will see your app crash, but that's fine. Also, create `public/index.html`, `src/index.js`, `src/components`, `src/components/App.jsx`, `src/components/Home.jsx`, `src/components/Navbar.jsx`
```shell
rm -r public/* src/*  
mkdir src/components  
touch public/index.html src/index.js src/components/App.jsx src/components/Home.jsx src/components/Navbar.jsx
```
Now, let's set the code for index.html
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Quickr</title>
        <!-- W3CSS -->
        <link rel="stylesheet" href="https://w3schools.com/w3css/4/w3.css" />
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>
```
*I am using [W3CSS](https://w3schools.com/w3css/4/w3.css) for my css styling as it is quick and easy to use*

Now, for all the javascript files:
```javascript
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";

ReactDOM.render(<App />, document.getElementById("root"));
```

```javascript
// src/components/App.jsx
import React from "react";
import Home from "./Home";
import Navbar from "./Navbar";

function App() {
    return (
        <React.Fragment>
            <Navbar />
            <Home />
        </React.Fragment>
    );
}

export default App;

```

```javascript
// src/components/Home.jsx
import React from "react";

function Home() {
    return (
        <React.Fragment>
            <div
                className="w3-container w3-center w3-blue"
                style={{ padding: "2rem" }}>
                <h1 className="w3-jumbo">Quickr - Quick Twitter</h1>
                <button
                    className="w3-button w3-pink"
                    style={{ marginRight: "1rem" }}>
                    Login
                </button>
                <button className="w3-button w3-pink">Register</button>
            </div>

            <div
                className="w3-container w3-blue"
                style={{ padding: "2rem", marginTop: "2rem" }}>
                <h2>Lorem ipsum dolor sit amet</h2>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                    Integer consectetur libero nibh, non sodales urna malesuada
                    nec. Sed tortor eros, blandit eget fringilla at, gravida a
                    nibh. Etiam dui nulla, aliquam vitae purus a, auctor
                    malesuada arcu. Vestibulum venenatis orci nisl, sed
                    elementum leo tincidunt eget. Nullam convallis nisi in.
                </p>
            </div>

            <div
                className="w3-container w3-blue"
                style={{ padding: "2rem", marginTop: "2rem" }}>
                <h2>Lorem ipsum dolor sit amet</h2>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                    Integer consectetur libero nibh, non sodales urna malesuada
                    nec. Sed tortor eros, blandit eget fringilla at, gravida a
                    nibh. Etiam dui nulla, aliquam vitae purus a, auctor
                    malesuada arcu. Vestibulum venenatis orci nisl, sed
                    elementum leo tincidunt eget. Nullam convallis nisi in.
                </p>
            </div>

            <div
                className="w3-container w3-blue"
                style={{ padding: "2rem", marginTop: "2rem" }}>
                <h2>Lorem ipsum dolor sit amet</h2>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                    Integer consectetur libero nibh, non sodales urna malesuada
                    nec. Sed tortor eros, blandit eget fringilla at, gravida a
                    nibh. Etiam dui nulla, aliquam vitae purus a, auctor
                    malesuada arcu. Vestibulum venenatis orci nisl, sed
                    elementum leo tincidunt eget. Nullam convallis nisi in.
                </p>
            </div>
        </React.Fragment>
    );
}

export default Home;
```

```javascript
// src/components/Navbar.jsx
import React from "react";

function Navbar() {
    return (
        <div className="w3-bar w3-black">
            <a className="w3-bar-item w3-button" href="/">
                Quickr
            </a>
            <div style={{ float: "right" }}>
                <a className="w3-bar-item w3-button" href="/">
                    Login
                </a>
                <a className="w3-bar-item w3-button" href="/">
                    Register
                </a>
            </div>
        </div>
    );
}

export default Navbar;
```

And finally, your website should look like this:
![Website](https://dev-to-uploads.s3.amazonaws.com/i/b6emdvnriuecz7ufnasv.png)

Now, let's add some functionality!

---

## Connecting backend to frontend

Now, let's implement login and register. Remember the routes we made earlier? Let's convert them to functions

```python
def getUsers():
    users = Users.query.all()
    return [{"id": i.id, "username": i.username, "email": i.email, "password": i.pwd} for i in users]

def addUser(username, email, pwd):
    if (username and pwd and email):
        try:
            user = Users(username, email, pwd)
            db.session.add(user)
            db.session.commit()
            return True
        except Exception as e:
            print(e)
            return False
    else:
        return False

def removeUser(uid):
    uid = request.json["id"]
    if (uid):
        try:
            user = Users.query.get(uid)
            db.session.delete(user)
            db.session.commit()
            return True
        except Exception as e:
            print(e)
            return False
    else:
        return False
```
Now, let's add a login and register api route. I'm gonna prefix my routes with `/api` like before.

```python
@app.route("/api/login", methods=["POST"])
def login():
    try:
        email = request.json["email"]
        password = request.json["pwd"]
        if (email and password):
            users = getUsers()
            # Check if user exists
            return jsonify(len(list(filter(lambda x: x["email"] == email and x["password"] == password, users))) == 1)
        else:
            return jsonify({"error": "Invalid form"})
    except:
        return jsonify({"error": "Invalid form"})

@app.route("/api/register", methods=["POST"])
def register():
    try:
        email = request.json["email"]
        email = email.lower()
        password = request.json["pwd"]
        username = request.json["username"]
        # Check to see if user already exists
        users = getUsers()
        if(len(list(filter(lambda x: x["email"] == email, users))) == 1):
            return jsonify({"error": "Invalid form"})
        # Email validation check
        if not re.match(r"[\w\._]{5,}@\w{3,}.\w{2,4}", email):
            return jsonify({"error": "Invalid form"})
        addUser(username, email, password)
        return jsonify({"success": True})
    except:
        return jsonify({"error": "Invalid form"})
```

In our register method, we have some form validation. It checks if the email is already registered and if the email is a valid email. Now, let's test it out. Start your server and make some requests.
```shell
# REGISTER
curl -X POST -H "Content-Type: application/json" -d '{"email": "foo@bar.dev", "pwd": "foobar", "username": "foobar"}' "http://localhost:5000/api/register" 
```

```shell
# LOGIN
curl -X POST -H "Content-Type: application/json" -d '{"email": "azeez@man.com", "pwd": "azeez"}' "http://localhost:5000/api/login"
```

So, now, we can login to our database using the CLI. But, we need to allow users to login using the Website. Let's head over to the frontend.

---

So, I have made 2 files, `Login.jsx` and `Register.jsx`. These files contain a login and register form separately. You can use your own markup, but for anyone wanting to use mine, here you go:

```javascript
// src/components/Login.jsx
import React, { Component } from "react";

class Login extends Component {
    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    LOGIN
                </div>
                <div className="w3-container">
                    <form>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                class="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                class="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Login
                            </button>
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Login;
```

```javascript
// src/components/Register.jsx
import React, { Component } from "react";

class Register extends Component {
    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    REGISTER
                </div>
                <div className="w3-container">
                    <form>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                class="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="username">Username</label>
                            <input
                                type="username"
                                class="w3-input w3-border"
                                id="text"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                class="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Register
                            </button>
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Register;
```

Ok, we're done with our markup, but, how can we render it in a different route? For example, if I type `https://mywebsite.com/login`, I need to see the login page. This can be done by using `react-router-dom`. First, install `react-router-dom`
```shell
npm i react-router-dom
```

And, now, let's implement it in our `App.jsx`
```javascript
// src/components/App.jsx
import React from "react";
import Home from "./Home";
import Navbar from "./Navbar";
import Login from "./Login";
import Register from "./Register";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

function App() {
    return (
        <React.Fragment>
            <Navbar />
            <Router>
                <Route path="/" exact component={Home} />
                <Route path="/login" exact component={Login} />
                <Route path="/register" exact component={Register} />
            </Router>
        </React.Fragment>
    );
}

export default App;
```
I also updated the routes in `Navbar.jsx`.
```javascript
// src/components/Navbar.jsx
import React from "react";

function Navbar() {
    return (
        <div className="w3-bar w3-black">
            <a className="w3-bar-item w3-button" href="/">
                Quickr
            </a>
            <div style={{ float: "right" }}>
                <a className="w3-bar-item w3-button" href="/login"> // Updated
                    Login
                </a>
                <a className="w3-bar-item w3-button" href="/register"> // Updated
                    Register
                </a>
            </div>
        </div>
    );
}

export default Navbar;
```

Now, when you click on the login and register buttons in the navbar, you should see the components we created. Now, let's add some functionality to the components.

### Login
First, let's install something called `axios`.
```javascript
npm i axios
```

Now, let's add a function that sends a `POST` request to the backend.

```javascript
// Login.jsx
import React, { Component } from "react";
import axios from "axios";

class Login extends Component {
    login = (e) => {
        e.preventDefault();
        axios
            .post("http://localhost:5000/api/login", {
                email: document.getElementById("email").value,
                pwd: document.getElementById("password").value,
            })
            .then((res) => {
                console.log(res.data);
            });
    };

    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    LOGIN
                </div>
                <div className="w3-container">
                    <form onSubmit={this.login}>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                className="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                className="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Login
                            </button>
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Login;
```

```javascript
import React, { Component } from "react";
import axios from "axios";

class Register extends Component {
    register = (e) => {
        e.preventDefault();
        axios
            .post("http://localhost:5000/api/register", {
                email: document.getElementById("email").value,
                username: document.getElementById("username").value,
                pwd: document.getElementById("password").value,
            })
            .then((res) => {
                console.log(res.data);
            });
    };

    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    REGISTER
                </div>
                <div className="w3-container">
                    <form onSubmit={this.register}>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                className="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="username">Username</label>
                            <input
                                type="text"
                                className="w3-input w3-border"
                                id="username"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                className="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Register
                            </button>
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Register;
```

So what we're doing here, is whenever the form is submitted, we send a request to the backend to the login and register routes. And when we get a response, we log it. Now, enter some rubbish data in Register, and open the in-browser console (or devtools) by pressing `Ctrl+Shift+I` for Windows/Linux or `Cmd+Option+I` for Mac. Press the register button and in the console, you should see an error like this:
![Error](https://dev-to-uploads.s3.amazonaws.com/i/3qmt0rp0lhgw0ayj6pii.png)

Now, this error is a security measure put in place by something called CORS. To bypass this, we need to install something called `flask-cors` in our backend.
```shell
pip install flask-cors
```
Now, change the starting of your `app.py` to this:
```python
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import re

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///twitter.db"
CORS(app)
# ...
```
If you now click register, you should see `{success: true}` in the console. And now, if we login using the same email and password, you can see `true` in the console, meaning everything is working! Now, let's give the user some feedback. Create a new file called `Alert.jsx` and put this in it:
```javascript
import React from "react";

function Alert(props) {
    return (
        <div
            className="w3-pale-red w3-text-red w3-border w3-border-red w3-round-large"
            style={{ padding: "1rem", marginTop: "1rem" }}>
            {props.message}
        </div>
    );
}

export default Alert;
```

`Alert` is now a reusable component that we can use anywhere in our code and we can give it a message. It'll display that message in a red background and in red text. We can make use of this component in `Register.jsx`:

```javascript
import React, { Component } from "react";
import axios from "axios";
import Alert from "./Alert";

class Register extends Component {
    state = { err: "" };

    register = (e) => {
        e.preventDefault();
        axios
            .post("http://localhost:5000/api/register", {
                email: document.getElementById("email").value,
                username: document.getElementById("username").value,
                pwd: document.getElementById("password").value,
            })
            .then((res) => {
                if (res.data.error) {
                    this.setState({ err: res.data.error });
                } else {
                    this.setState({ register: true });
                }
            });
    };

    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    REGISTER
                </div>
                <div className="w3-container">
                    {this.state.err.length > 0 && (
                        <Alert
                            message={`Check your form and try again! (${this.state.err})`}
                        />
                    )}
                    <form onSubmit={this.register}>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                class="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="username">Username</label>
                            <input
                                type="text"
                                class="w3-input w3-border"
                                id="username"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                class="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Register
                            </button>
                            {this.state.register && <p>You're registered!</p>}
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Register;
```

Now, if we enter an invalid email, (a valid email, according to my RegEx, is one that has 5 or more alphanumberic characters including . and _, an @, 3 or more alphanumeric characters, a . and 2-4 more alphanumberic characters), we should get this:
![Register](https://dev-to-uploads.s3.amazonaws.com/i/92bzbb95jmmbpfpwiw73.png)

Awesome! `Login.jsx` can also use some error handling.

```javascript
import React, { Component } from "react";
import axios from "axios";
import Alert from "./Alert";

class Login extends Component {
    state = { err: "" };

    login = (e) => {
        e.preventDefault();
        axios
            .post("http://localhost:5000/api/login", {
                email: document.getElementById("email").value,
                pwd: document.getElementById("password").value,
            })
            .then((res) => {
                if (res.data.error) {
                    this.setState({ err: res.data.error });
                } else {
                    this.setState({ login: true });
                }
            });
    };

    render() {
        return (
            <div className="w3-card-4" style={{ margin: "2rem" }}>
                <div className="w3-container w3-blue w3-center w3-xlarge">
                    LOGIN
                </div>
                <div className="w3-container">
                    {this.state.err.length > 0 && (
                        <Alert
                            message={`Check your form and try again! (${this.state.err})`}
                        />
                    )}
                    <form onSubmit={this.login}>
                        <p>
                            <label htmlFor="email">Email</label>
                            <input
                                type="email"
                                class="w3-input w3-border"
                                id="email"
                            />
                        </p>
                        <p>
                            <label htmlFor="password">Password</label>
                            <input
                                type="password"
                                class="w3-input w3-border"
                                id="password"
                            />
                        </p>
                        <p>
                            <button type="submit" class="w3-button w3-blue">
                                Login
                            </button>
                            {this.state.register && <p>You're logged in!</p>}
                        </p>
                    </form>
                </div>
            </div>
        );
    }
}

export default Login;
```

And now, if we type wrong credentials, we should get this:
![Login](https://dev-to-uploads.s3.amazonaws.com/i/ipsgct10dm4cttxymp31.png)

---

## Conclusion
Nice! Now, you've learnt how to connect flask and react together using a RESTful API. In the next part, we'll add the ability to post and see tweets. This post has been pretty long. I'll try to make a youtube video about it, and if I do, I'll be sure to link it here. All the code is available on [Github](https://github.com/arnu515/twitter-clone). This was pretty long for a first post! 

**[Part Two is now out!](https://dev.to/arnu515/build-a-twitter-clone-with-flask-and-react-part-2-5deb)**