Reflection Journal #4: A better way to write Flask app

Featured image

One of the reason I like Flask is because it has no pattern of project folder structure, it is very flexible. It is very good for beginners as they can learn how to organise their applications such as routes, view function, templates, etc. For small application, compare to Django (A python fullstack framework), Flask gives more performance.

But in my point of view, I want to make something simple and easy for my future develoments with Flask. I don’t want to spend too much time on writing view functions and write every single route. Or everytime I write something, I will need to import it to the main file.

The development of this package or framework will be somewhat complicated but will handle most of the hard works for me. Following the previous post The flask microframework

The new approach

Building a new framework on top of Flask. All of the below functons are implemented inside framework folder. If you wish to change the location of the framework folder, the path will need to rewrite. For example, app.framework.requests to pandoru.request or framework.request if you would like to move it outside app folder.

The power of controller

As discussed earlier in the previous post, I have made somewhat big update for the controller part. Before, everytime I delcared a controller file, I had to import it through __init__.py file. And then that file was automatically imported to kernel folder. It took quite a few works to do it but with new version. All I have to do is to create a .py file with the word controller or Controller at the end.

This is the full code for this part

"""
Reposible for handling controller files. DO NOT MODIFY!
"""
import os
controller_files = os.listdir('./app/http/controllers')
controllers = {}
files = []

def file_endswith(filename, suffix):
    """Check if file correctly ends"""
    return filename.endswith(suffix) or filename.endswith(suffix.lower())

for controller_file in controller_files:
    filename, file_extension = os.path.splitext(controller_file)
    if file_extension == '.py':
        controllers.update({filename: file_extension})

for controller_name in controllers.keys():
    if file_endswith(controller_name, 'Controller'):
        files.append(controller_name)


__all__ = files

This will need to be improved such as recursively looping through subfolders.

The Flask request

In the docs describes all the available attribute available on request. Some common attributes are request.args request.form request.values follow by either get() or getlist() functions. However, the code will look a lot messy. We have to remember the correct attributes and if we use the wrong one it will not work properly.

I came up with the new way of approaching.

Retreive input value

By simplify a few methods, I can access all of the user input without worrying about which HTTP verb was used for the request. Regardless of the HTTP verb, the input method may be used to retrieve only user input:

email = request.input('email')

Retreive input from query string

While the input method gets values from form request. The query method will only retrieve values from the query string:

name = request.query('name')

If I wish to retrieve all query string value, I can call the query method without any arguments

query = request.query()

Determine if an input value is present

The has() method is used to determine if a value is present on the request. The has() method returns True if the value is present on the request

if request.has('name'):
    pass

Or I can also give them an array of values to check. The has() method will return True if all values in array are present

if request.has(['name', 'email']):
    pass

Or I can also check if the value is present and is not empty

if request.filled('name'):
    pass

I don’t need Flask WTForm.

Let’s take a look at a simple controller that handle our routes

from app import app
from app.framework.controller import *
from app.framework.requests import FormRequest
from app.framework.requests.request import request



class UserController(Controller):
    def construct(cls):
        UserController.register(app)

    @route('/dashboard', methods=['GET'])
    def dashboard_view(self):
        return view('dashboard')

    @route('/login', methods=['GET'])
    def login_view(self):
        return view('auth/login')

    @route('/login', methods=['POST'])
    def login_action(self):

        pass

Now I need to fill in my login_action() method with the logic to validate the new user post. To do this, I can use FormRequest() class from framework.request then I will need to check if the validation passes. To do this, I can use the is_validated() method provided by framework.request . If the validation rules pass, the code will keep executing normally.

However, if it fails, an exception will be thrown and the proper error response will automatically be sent back to the user.


# import statement here


class UserController(Controller):
    def construct(cls):
        UserController.register(app)

    @route('/dashboard', methods=['GET'])
    def dashboard_view(self):
        return view('dashboard')

    @route('/login', methods=['GET'])
    def login_view(self):
        return view('auth/login')

    @route('/login', methods=['POST'])
    def login_action(self):

        form = FormRequest({
            'user_email': 'email'
        })

        if form.is_validated():
            user = {'username': request.input('user_email')}
            return view('dashboard', user=user)
        else:
            return redirect('/login')

There are many validation attributes such as

form = FormRequest({
    'user_email': 'email',
    'username': 'alphanumeric',
    'remember_me': 'boolean'
    #more goes here...
})

Display errors from FormRequest

You can just display the errors like how you usually do in flask


{% with messages = get_flashed_messages() %}
      {% if messages %}
        {% for message in messages %}
            <p style="margin-left: 10px; color:red;">{{ message }}</p>
        {% endfor %}
      {% endif %}
    {% endwith %}

Alternatively, if I wish to display specify message, I can just simply use the error_message() function. Again, this is built inside framework folder. I don’t have to reimplement it again for other projects


{% if error('user_email') %}
      <p style="margin-left: 10px; color:red; font-size: 13px;">{{ error_message('user_email')}}</p>
      {% endif %}

Future plans

I want to improve the FormRequest class instead of just validate one attribute:

form = FormRequest({
    'user_email': 'email',
    'username': 'alphanumeric',
    'remember_me': 'boolean'
    #more goes here...
})

I would like to make it better by having more attribute field

form = FormRequest({
    'user_email': 'required|email|max:32|min:1',
    'username': 'required|alphanumeric|min: 8',
    'remember_me': 'boolean'
    #more goes here...
})

And instead of having like form.is_validated(), the validation part can just redirect the user back with error code if fails, there is no need to have is_validated() function.