The hitchhiker's guide to building a React + Flask web app (part2).

Introduction

So we would be building the back end for our Todo-reminder application. But first let understand why we need a backend. A backend or server end is an invisible layer we don't see but is responsible for a lot of things that we interact with, like the storage of our information in the database, so that whenever we need to continue from where we stop, it brings up the data we have already stored. If we store our data in the frontend only, each time there is a refresh of our page, the DOM (document object model) which is a connector between the HTML, CSS and Javascript making them function as one is going to be refreshed, meaning we automatically lose all of our data.

But in recent years backend development has gone way beyond that, now backend is used for much more, like real time communication, passwordless login, real time video or voice chat, application architecture design, machine learning uses, etc. We can see the application is not complete without the backend service. This is why we have many languages pertaining to backend, starting from javascript itself in form of Node.js, to Python in forms like Flask, Django, Fast Api, to Ruby with its sole form Rails, talk about C#, C ++ using Api.Net, Golang isn't left out with Mux, etc. It is also good to note that most of these languages have internalised http server but not easy to use and less efficient, gave rise to these frameworks / libraries mentioned above used to connect the backend to the frontend.

So we will look using Flask framework to build a backend service as a continuation from the last part/series, which you can check here. We would be using a noSQL database called mongoDB for our database here and also will be using the first folder structure (separated folder structure) discussed in the last part/series.

Prerequisites

  • A basic knowledge of python
  • Flask is installed in your environment, if it isn't installed yet you can install it by
    pip install flask
    
  • dotenv and pymongo also needs to be installed.
    pip install dotenv
    
    and
    pip install pymongo
    

Set up

First we would need to install needed libraries to our server.py file.

from flask import Flask, render_template, request
from dotenv import load_dotenv
from pymongo import MongoClient, DESCENDING
from bson.objectid import ObjectId
import os

bson comes with pymongo, so we import the needed modules, MongoClient for connecting and adding to our database, ObjectId because we would need to query based on our unique Id created by MongoDB python driver. load_dotenv to get our environment variable which is an api key needed to connect to our server. If you haven't registered for MongoDB, you can do so here, one amazing thing about MongoDB is their nice documentation which you can check it out here.

Next we connect to our database, which is shown below;

load_dotenv()
dbe=os.getenv('DB')
client=MongoClient(dbe) #mongo_url
db=client.Cluster0['todo']

I first called the function load_dotenv, which loads the data stored in a .env file to the environment. So we can comfortably call "DB" which is the name I assigned to the api key, we call DB with os.getenv and store it in a variable, we call dbe. We would now connect to the database using MongoClient and the api key and save to another variable. We then access an already created cluster called Cluster0, we don't already have, it creates one for us automatically. We then choose a database, or create if there isn't one with that name in that cluster and assign it to a variable db. This db is what we now use to query or save data needed to be save or retrieved from our database.

Then we also need to create a server with instructions to do some specific things when some routes are accessed. We do that by

app = Flask(__name__,template_folder='../client/build', static_folder='../client/build/static')

Now, you must be thinking what do we need those template and static folders arguments for? These are not required arguments of course, and if we're trying to build a server with microservice architecture, we probably won't need them. But our main goal here is a monolith application, meaning when we go to the root route or our application, the server should send a html file to the user, which should be found in the build folder in the client folder, the index.html is connected to a js file that utilizes React, also we have css files, not forgetting maybe needing assets like pictures and videos needed to be used in our frontend, these are stored in the static folder in the build folder. If you're using create-react-app, the build and static folder is already generated for you, after you do

npm run build

But, if you're manually setting up, make sure your js files are in a js folder in the static folder, css and media also.

Routes and Responses

  • first route

    So for our first route, we would go with '/',
    @app.route('/',methods=["POST","GET"])
    def home():
      return render_template("index.html")
    
    We have 4 main methods GET, POST, PATCH, DELETE. The main ones used are GET and POST. So either you request for the page from the server through GET or POST to the server for a reply, it'll return the same 'index.html' gotten from the template folder.
  • save route

    We also need a route to save our todo item and date created with date we plan to fulfill them and whether we have already fulfilled or completed them.
    @app.route('/save',methods=["POST"])
    def save():
      data=request.json
      db.insert_one({"todo":data["todo"], "start":data["start"], "target":data["target"], "fulfilled":False})
      response=({"status":"success"})
      return response
    
    Note that we only used the POST request method, this is because we only want the server to reply if it is a POST request from the client and not a GET nor PATCH/ PUT nor DELETE request. We use the request to get the data sent through the POST request and save the needed data like the todo, date we entered the todo, date we plan on finishing and whether we have finished or not, of course we just put this in so we sure haven't finished. We also send a response back with the return function.
  • retrieve route

    We also need a route and function to retrieve the data we stored in the database.

    @app.route('/retrieve',methods=["POST"])
    def retrieve():
      result = db.find().sort('start',DESCENDING)
      result=list(result)
      for i in result:
          i["_id"]= str(i["_id"])
      response=({"status":"success", "result":result})
      return response
    

    We get the entire documents we have entered by putting no query in the find function and we sort by date and in descending order, so latest to earliest. The result is in cursor form so we convert to a list and send the result as a response.

  • change route

    We also need another route function to change the state of any todo task we finish, from fulfilled is false to fulfilled is true.

    @app.route('/change',methods=["POST"])
    def change():
      data=request.json
      result = db.find_one_and_update({"_id":ObjectId(data["idd"])}, {"$set": {"fulfilled": True} })
      if result !=None:
          response=({"status":"success"})
      else: 
          response=({"status":"failed"})
      return response
    

    We query for the id of the todo item, using ObjectId we imported earlier, then we update the fulfilled part of the document with the new data using $set variable as a feature of MongoDB python driver. So if we have a query match we should get a positive response, if we don't we should get a negative response.

  • Finally

    To finalize the setup of our server we run

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

    Since we're in development stage we should use debug is true, in production stage, we should use debug is false, to avoid server restarting.

  • What else can I do with this?

    We just built the bare minimum server end for our todo app, you can add more features, depending on your abilities, you can create a extend route, where the user can extend the time and it will update the database with the updated date-target. You can also create a delete route for deleting todo items you don't need, or recap route for recurrent todo items and much more.

What Next?

We will be moving on to the front end in the next and last part of this series, we would be using typescript and React to build amazing things. Can't wait to see you there!