Build a FullStack App with React and Python with Flask

full stackflaskobject-oriented programmingpythonjavascript

Wednesday, March 27, 2024

In this blog post I will be covering the fundamentals of creating a full stack application using JavaScript/React for the frontend and Python/Flask for the backend.

Flask is a lightweight web application framework written in Python, designed to make getting started quick and easy, with the ability to scale up to complex applications. It provides tools, libraries, and technologies that allow developers to build a web application, including support for routing, request handling, and templates, in a minimal and flexible manner.

This tutorial is intended to be beginner friendly, with step-by-step instructions on how to get started. If you’re new to developing and curious about creating your first full stack application, you’re in the right place.

Getting Started

The first thing we will do, is create a folder that will hold the contents of our application. I am using VSCode as my code editor, if you don’t have it installed, I highly recommend installing to follow along.

To get started, open up your terminal and type in the following:

$ mkdir full-stack-project
$ cd full-stack-project
$ code .

This will open up your new folder in VSCode. We will be using Pipfile to manage our Python packages for this project. Create a file, name it Pipfile and paste the following into it:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"
flask-sqlalchemy = "3.0.3"
Werkzeug = "2.2.2"
flask-migrate = "*"
sqlalchemy-serializer = "*"
flask-cors = "*"

[requires]
python_full_version = "3.8.13"

A quick summary of dependencies:

1. flask (*): Flask is our web framework, providing us with the tools and libraries to build a web application.

2. flask-sqlalchemy (3.0.3): This extension for Flask simplifies the use of SQLAlchemy, a powerful ORM (Object-Relational Mapping) for Python, with Flask applications. We will be using it for database operations within our Flask app.

3. Werkzeug (2.2.2): Werkzeug is a comprehensive WSGI (Web Server Gateway Interface) web application library. It is the foundation of Flask and provides utilities for requests and response handling.

4. flask-migrate (*): This Flask extension handles SQLAlchemy database migrations for Flask applications using Alembic. We will be using it for database migrations within our application.

5. sqlalchemy-serializer (*): This library provides us with the ability to convert SQLAlchemy model data into JSON format and vice versa, which we will need in order to send our database data to our React application in the correct format.

7. flask-cors (*): Allows us to make fetch API requests from our frontend to our backend.

8. Python 3.8.13, is the version of Python we will be using in our application.

Creating config and app files

Next create a folder within your application called server. Create two files, an app.py file and a config.py file. In your config file copy the following:

from flask import Flask
from flask_cors import CORS
from flask_migrate import Migrate
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData


# Instantiate app, set attributes
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.json.compact = False

# Define metadata, instantiate db
metadata = MetaData(naming_convention={
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
})
db = SQLAlchemy(metadata=metadata)
migrate = Migrate(app, db)
db.init_app(app)

# Instantiate REST API
api = Api(app)

# Instantiate CORS
CORS(app)

This code initializes our Flask application and sets up Flask with SQLAlchemy for ORM-based database interactions, Flask-Migrate for handling database migrations, and Flask-RESTful for creating RESTful web services.

In your config.py file, copy the following:

#!/usr/bin/env python3

from config import app



@app.route('/')
def index():
    return '<h1>Project Server</h1>'


if __name__ == '__main__':
    app.run(port=5555, debug=True)

Now run the following commands in the terminal of the root file of your project:

$ pipenv install 
$ pipenv shell
$ cd server
$ python app.py

And you should see the following in your browser after following the link:

image of server running

Congrats! You’ve officially set up a Flask application. But we are not quite finished yet. Grab a coffee and a snack and get ready to create some data!

Setting up your Database Model

In your server folder, create a models.py folder and copy the following into it:

from sqlalchemy_serializer import SerializerMixin
from config import db


class Movie(db.Model, SerializerMixin):
    __tablename__ ='movies'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)
    def __repr__(self):
        return f'Movie: {self.title}'

In this file we have created a Movie model for our application. This model inherits the db.Model class, which essentially defines the structure of a database table in a Python class.

Each attribute of the class represents a column in the table, with types and options like primary keys, unique constraints, and even relationships to other tables. This model also inherits from SerializerMixin, which allows us to convert the model data into JSON format. The model itself represents a movies table with id and title columns, where id serves as the primary key and title is a required string field.

Database Migrations

Now that we have our model, we will create our first database migration. In your app.py folder, import your model.

from models import Movie

Now open a new terminal in your projects folder, run pipenv shell to enter your virtual environment and run the following commands:

$ flask db init
$ flask db migrate -m "initial migration"
$ flask db upgrade head 

1. flask db init: Initializes a migration environment for the application by creating a migrations folder, which will store our migration scripts and configuration for managing database schema changes.

2. flask db migrate -m “initial migration”: Generates an initial migration script based on the differences between the current database schema (if any) and the models defined in the application. The -m flag adds a human-readable message to the migration script, in this case, “initial migration.”

3. flask db upgrade head: Applies the migration scripts up to the latest version (referred to as “head”) to the database, effectively upgrading the database schema to match the current state of the application models.

You should see two new folders, an instance folder, that contains app.db and a migrations folder. If you open your app.db folder (I am using SQLite View extension) you should see your new table — movies.

Now that we have our table, lets input some data. In your server folder, create a new file seed.py and copy the following:

#!/usr/bin/env python3
from models import Movie

from config import db, app


if __name__ == '__main__':
    with app.app_context():
        def create_movie_data():
            movies = ['Pulp Fiction', 'Star Trek', 'Kill Bill Volume1', 'No Country for Old Men' ]
            movie_list = []
            print("Deleting existing movie data...")
            Movie.query.delete()
            for movie in movies:
                movie_list.append(Movie(title=movie))
                
            db.session.add_all(movie_list)
            db.session.commit()
            print("Adding movie data...")
        create_movie_data()

In this code we have:

1. We’ve imported our Movie model, along with db and app.

2. db represents the SQLAlchemy database instance, and app is the Flask application instance.

3. We’ve included if name == ‘__main__’ to ensure our code only executes if the script is the main program being run, and not when it’s imported as a module elsewhere.

4. We establish an application context using app.app_context(), to execute database operations.

5. We create a function create_movie_data() to seed our database.

6. Movie.query.delete() deletes existing movies, so that we don’t duplicate any items in our seed file if we rerun the script.

7. We then create Movie instances for each title in the list, and add these instances using db.session.add_all(movie_list) and commit the changes to the db using db.session.commit().

8. Finally we call our function create_movie_data().

To seed our database, head over to the terminal, making sure you are in your virtual environment and in the server folder and run:

$ python seed.py

Now when you open your database within your application you should see the following data:

screenshot of database

Creating our React Application

Now it’s time to get started on working on our frontend. We will be using Vite to create our React application.

In your project’s root directory, create a new file titled client. Then in a new terminal run the following:

$ cd client
$ npm create vite@latest

You will then be prompted to enter some information. Enter a name for the project and hit Enter, then choose React for your framework and hit Enter and JavaScript for your variant and hit Enter.

Once you are done run the following in your terminal:

$ cd your-project-name
$ npm install
$ npm run dev

Creating a Route in your Flask Application

Now that we have our React app in place, it’s time to create a route to send over data from our database model to our frontend. In your app.py file create the following route:

#!/usr/bin/env python3

from flask import make_response
from config import app
from models import Movie



@app.route('/movies', methods=['GET'])
def movies():
    movies = [movie.to_dict() for movie in Movie.query.all()]
    response = make_response(movies, 200)
    return response


if __name__ == '__main__':
    app.run(port=5555, debug=True)

In this code block we have defined a route /movies to handle GET Requests. When we access this endpoint it will return a list of all the entries from our Movie database model converted to JSON along with a 200 OK status code.

Connecting Our React Application to Our Flask API EndPoint

Now the last thing we have to do is retrieve the data from our Flask API to display in the browser. To do so, head over to your client folder, and open up the App.jsx file within the src folder and enter the following:

import React,  {useEffect, useState } from 'react'
import './App.css'

function App() {
    const [movies, setMovies] = useState([])

    useEffect(() => {
      fetch("http://127.0.0.1:5555/movies")
        .then((r) => r.json())
        .then((movies) => setMovies(movies));
    }, []);


  return (
    <>
      {
        movies.map((movie)=>{
          return(
            <div>
              {movie.title}
            </div>
          )
        })
      }
    </>
  )
}

export default App;

In this code, we are using the useEffect hook and JavaScript Fetch API to request the data from our Flask API. We use .then((r) => r.json()) to convert the response from the fetch call from its raw format into a JavaScript objet by parsing the JSON response body. We can then update the state of our movies variable with the returned data in our application.

Once you are done, you should see the following in your browser:

Conclusion

Congrats on making it this far in the tutorial. You have now built your first full-stack application using React and Flask. This combination of technologies offers a powerful yet streamlined approach to building web applications that have the flexibility to grow and scale with your application.

I hope you enjoyed this article, good luck in your next adventure and happy coding!