Hello and welcome to the second part of this tutorial.
So let’s see how to structure our app.
Given my experience with Symfony and Laravel as work tools, I decided to pick the things that I liked the most from them.
As you can see I divided my app into bundles which are like containers used to divide our apps in different modules.
The first module that I created is the one related to users, therefore I named it users_bundle.
This bundle is made of models (entities), controllers and some helper functions.
I recall you that the project is freely available at https://github.com/Deviad/adhesive therefore hereby I am going only to discuss the most important parts.
In Flask in order to mark your function as a controller you must indicate this in two places:
1. in your init.py inside “theroot” folder of your app by registering your controller assigning it a name. I gave it the same name as my bundle.
app.register_blueprint(users_bundle) which allows us to register a service and use it along with the function in the controller without knowing how the service is implemented.
Here is what is inside Flask core code:
def register(self, app, options, first_registration=False): """Called by :meth:`Flask.register_blueprint` to register a blueprint on the application. This can be overridden to customize the register behavior. Keyword arguments from :func:`~flask.Flask.register_blueprint` are directly forwarded to this method in the `options` dictionary. """ self._got_registered_once = True state = self.make_setup_state(app, options, first_registration) if self.has_static_folder: state.add_url_rule(self.static_url_path + '/<path:filename>', view_func=self.send_static_file, endpoint='static') for deferred in self.deferred_functions: deferred(state)
So this is pretty much like an observer that waits for an event to occur does.
- you have to instantiate the blueprint somewhere, this will tell Flask that that’s where your controller lies and will also allow you to provide some parameters in order to construct the object with the desired configuration options.
users_bundle = Blueprint("user", __name__, url_prefix="/api")
As you can easily understand url_prefix like in Laravel allows me to set a prefix for the paths calling.
In Flask and in Python we can use the decorator pattern which works pretty much like in Angular or Java.
Therefore we can use e.g.
@users_bundle.route("/user", methods=['POST']) to say: hey, when a user calls the route /api/user, he must use a post type. Also, it says that this function is a routing function.
Looking into Flask core code (blueprints.py) you can see this:
def route(self, rule, **options): """Like :meth:`Flask.route` but for a blueprint. The endpoint for the :func:`url_for` function is prefixed with the name of the blueprint. """ def decorator(f): endpoint = options.pop("endpoint", f.__name__) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
In the next part, I will show you how I used the decorator pattern to create an ACL. The decorator pattern helped me me to have more choesive, SOLID, DRY and loosely coupled code.