DEV Community

nandamtejas
nandamtejas

Posted on • Updated on

Implementing Flask application using Object Oriented Programming (OOP's) [PART-2]

Please click here to check my first part [part-1] of this blog

In previous section we have discussed about

  • About web Framework
  • About Flask framework
  • HTTP methods used in Flask framework
  • A minimal Flask application
  • A new approach using OOP's with Flask Framework

Now we are going to discuss further deep going into the concept

In the previous part we have discussed about the Flask framework which can be worked using classes and object, but not quitely.
We have just created a FlaskAppWrapper class which takes the flask app and allows us to add the endpoints and routing.

The FlaskAppWrapper class make sure functionality of add_endpoint method which is used to routing the method with appropriate endpoint given as an arguments passed to it.

In this section we are going to discuss about

  • Routing
  • Dynamic Routing
  • EndpointHandler class
  • How EndpointHandler class helps in routing

Routing

App routing is used to map the specific URL with the associated function that is intended to perform some task.
The associated function is called handler in our case.

The add_endpoint method add the new endpoint for a given handler should be a callable function executed when you invoke the url with a given endpoint should be callable type rather you pass any arguments to it or not uses add_url_rule(<url_rule>, <endpoint>, <view_function>) which we have discussed before in the previous section which is used to perform routing for flask application.

Here,

  • <url_rule> is the endpoint
  • <endpoint> is the endpoint name which rather is the name of the handler and
  • <view_function> is the associated function, rather say handler which is executed when we call the URL with the registered endpoint.

If you pass any arguments to that callable handler, you have the request.view_args method which should be imported from the flask module which will will store the arguments.

Dynamic routing

Here we use a concept of Dynamic routing. Flask provides the functionality of the dynamic routing.
It is the process of getting dynamic data(variable names) in the URL and then using it.
In Flask you can have use following converters to convert dynamic input from the URL.

  1. string
  2. int
  3. float
  4. path ( It is simple a string but also accepts shashles in the URL)
  5. uuid

Dynamic URL's in Flask play an important role in the ability to create unique URL's that aren't hard-coded into our application.

EndpointHandler class

To pass the arguments, we have to create another class name EndpointHandler which is responsible for executing the handler according to the endpoint.

class EndpointHandler(object):

    def __init__(self, action):
        self.action = action 

    def __call__(self, *args, **kwargs):
        response = self.action(*args, **kwargs)
        return response
Enter fullscreen mode Exit fullscreen mode

Let's save in handler.py file.

In the above code we have created EndpointHandler class where the instance of that class is callable. Callable in the sense that instance of the class act's similar to the function. The __call__ method makes the instance callable and executes what inside the __call__ method.

Here in the class EndpointHandler takes the action which will be the any function or any method from class.

Let's test with any built-in function in python.
There are so many built-in function in python such as print, list, len etc..

Let's try with print as an argument of an instance of the class.

handler = EndpointHandler(print)
handler("Hello world")
Enter fullscreen mode Exit fullscreen mode

The output will be like this

C:\>python handler.py
Hello world
Enter fullscreen mode Exit fullscreen mode

That means print function is an action of handler which is an instance of a class and it is callable and prints anything we pass as an arguments. That means that handler instance has the functionality of the print function and acts as the same function we passed into it.

We have to check whether it works on user defined function.

Let's take an example of the function called action shown below.

def action(a,b):
    """
    This action is an example function which takes the two parameter a and b of Integer type and returns the sum of a and b
    """
    return a + b
Enter fullscreen mode Exit fullscreen mode

Now Let's make an instance of the class name handler and pass the action function as arguments in class.

handler = EndpointHandler(action)
result = handler(5, 6)
print(result)
Enter fullscreen mode Exit fullscreen mode

You will get the output as the sum of 5 and 6 which is 11. That means we have concluded that the EndpointHandler class is the callable class which takes the associative function which is stored in the action parameter, performs the same functionality with the action.

How EndpointHandler class will help in Routing in flask?

We have the EndpointHandler class which we have discussed in the previous part of the blog is shown below, the only change is we are going to pass the endpoint of EndpointHandler

class FlaskAppWrapper(object):

    def __init__(self, app, **configs):
        self.app = app
        self.configs(**configs)

    def configs(self, **configs):
        for config, value in configs:
            self.app.config[config.upper()] = value

    def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET'], *args, **kwargs):
        self.app.add_url_rule(endpoint, endpoint_name, EndpointHandler(handler), methods=methods, *args, **kwargs)

    def run(self, **kwargs):
        self.app.run(**kwargs)
Enter fullscreen mode Exit fullscreen mode

There are some changes should be done in EndpointHandler class when you are working in flask shown below.

from flask import request, make_response

class EndpointHandler(object):

    def __init__(self, action):
        self.action = action 

    def __call__(self, *args, **kwargs):
        response = self.action(*args, **request.view_args)
        return make_response(response)
Enter fullscreen mode Exit fullscreen mode

where,

  • request.view_args A dict of view arguments that matched the request. If an exception happened when matching, this will be None.

  • make_response Convert the return value from a view function to an instance of response_class.

Now, We have to test our FlaskAppWrapper with a new function called action and we are going to pass name argument to it

def action(name):
    """
    This function takes `name` argument and returns `Hello name`.
    """
    return "Hello " + name
Enter fullscreen mode Exit fullscreen mode

Now we are going to define the flask app and we are going to register the action function.

flask_app = Flask(__name__)
app = FlaskAppWrapper(flask_app)

# register the action function to app

app.add_endpoint('/action/<string:name>', 'action', action)

if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

The whole code looks like

from flask import Flask, request, make_response

class EndpointHandler(object):

    def __init__(self, action):
        self.action = action 

    def __call__(self, *args, **kwargs):
        response = self.action(*args, **request.view_args)
        return make_response(response)

class FlaskAppWrapper(object):

    def __init__(self, app, **configs):
        self.app = app
        self.configs(**configs)

    def configs(self, **configs):
        for config, value in configs:
            self.app.config[config.upper()] = value

    def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET'], *args, **kwargs):
        self.app.add_url_rule(endpoint, endpoint_name, EndpointHandler(handler), methods=methods, *args, **kwargs)

    def run(self, **kwargs):
        self.app.run(**kwargs)

def action(name):
    """
    This function takes `name` argument and returns `Hello <name>`.
    """
    return "Hello " + name

flask_app = Flask(__name__)
app = FlaskAppWrapper(flask_app)

# register the action function to app

app.add_endpoint('/action/<string:name>', 'action', action)

if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

The code above shown works like this

  1. Firstly, I have imported some requirements from Flask framework.

  2. We have created the EndpointHandler class which is responsible for managing to pass the extra arguments or parameters to be passed when an action is invoked.

  3. Then we have worked with the FlaskAppWrapper class and we have discussed about it in the previous part and we made some changes which is menctioned in the above discussion.

  4. To test the FlaskAppWrapper class we have defined the action function which takes the name as the parameter and returns the string as Hello <name>.

  5. We have defined the flask_app as the instance of the Flask class and this flask_app instance is given to our FlaskAppWrapper class and this instance is stored in app.

  6. We have registered the action function to the app instance using the add_endpoint method by giving the appropriate endpoint to the action function. In this case /action/<string:name> is the endpoint for the action function that means, when we invoked the Flask app url with the endpoint above executes the action function which we have registered and we are going to see in the output section.

  7. We are going to run the file using app.run() method and we see the output

We save the above code as example6.py and run using the command

C://> python example6.py
Enter fullscreen mode Exit fullscreen mode

And then we are going to click on the url shown below.

run_app

We are heading over to http://127.0.0.1:5000/action/Tejas in any search engines (I'm using Google) and we get the output as shown below

part2_flask_example2

We have observed that after heading to the url above, You get the output as Hello Tejas and Tejas is the name I have passed over the action function.

We will check with other name say Subash.
Head over to http://127.0.0.1:5000/action/Subash the output is as shown below

part2_flask_example_3

A broad example

Now we will test our application by adding many actions to our FlaskAppWrapper class.

The whole code looks like

from flask import Flask, request, make_response

class EndpointHandler(object):

    def __init__(self, action):
        self.action = action 

    def __call__(self, *args, **kwargs):
        response = self.action(*args, **request.view_args)
        return make_response(response)

class FlaskAppWrapper(object):

    def __init__(self, app, **configs):
        self.app = app
        self.configs(**configs)

    def configs(self, **configs):
        for config, value in configs:
            self.app.config[config.upper()] = value

    def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET'], *args, **kwargs):
        self.app.add_url_rule(endpoint, endpoint_name, EndpointHandler(handler), methods=methods, *args, **kwargs)

    def run(self, **kwargs):
        self.app.run(**kwargs)

def action1(name):
    """
    This function takes `name` argument and returns `Hello name`.
    """
    return "Hello " + name

def action2():
    """
    This function returns "Action2 invoked"
    """

    return "Action2 invoked"

def action3(number):
    """
    This function returns the cube of the number 
    """
    return "Cube of {0} is {1}".format(number, number**3)



flask_app = Flask(__name__)
app = FlaskAppWrapper(flask_app)

# register all action functions to app

app.add_endpoint('/action1/<string:name>', 'action1', action1)
app.add_endpoint('/action2/', 'action2', action2)
app.add_endpoint('/action3/<int:number>', 'action3', action3)

if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

From above code, we have registered the 3 action functions to our app.

  • action1 takes the name parameter from the endpoint and returns Hello <name>.

  • action2 returns Action2 invoked.

  • action3 takes the number parameter from the endpoint and returns the cube of the number.

After running the above code we get the output shown below

1_1

1_2

1_3

Same url, different endpoints and different functions are invoked and executed.

We are going to declare that any number of actions can be registered in our app and I conclude that the FlaskAppWrapper class works as good as the Flask application and this is the approach I have researched.

Summary

We have discussed in this part about

  1. Routing and Dynamic Routing in Flask
  2. Handling the flask endpoint using EndpointHandler class
  3. Discussed and made some changes in the FlaskAppWrapper class.
  4. Tested the updated code with the concept of Dynamic routing.

Discussion (0)