Building an archetype to my python apps
Tags: python, flask, api, web
Published: 2020-03-28 22:16:25

---
title: Building an archetype to my python apps
published: true
description: Playing with flask, a new candidate of archetype for my python apps.
tags: python, flask, api, web
---

I have built a lot of python webapps, APIs with flask. But didnt have a good aproximation for made it, really maintanible.

This weekend i have been working on a new archetype, im not sure that it will be better than my current archetype but i share it here. Anyone can comment if thinks that is not a good aproximation or if have any improvement.

If i dont comment some part of the archetype and you want an why  i choose that way of implementation just comment below and i will answer as soon as possible.


## Folders

A quick description:

* api: api endpoints.
* cfgs: server configurations folder, at this moment only one.
* host: Here will be all server configurations.
* web: jinja2 cgi clasic web, static files like css and JS.

```
├── app
│   ├── api 
│   ├── cfgs
│   ├── host
│   └── web
├── docs
└── resources
    └── docker
        └── app // sites available file
```

### Run file and configuration loader

```
└── app
    ├── api 
    ├── cfg_loader.py 
    ├── cfgs
    ├── host
    ├── main.py // main file that launch server
    └── web
```

main.py file will import server and will run it only if it is runned as a script, else will expose app for CGI apache servers.

```python
import os
import json

from host.server import Server
from cfg_loader import CfgLoader

cfg = CfgLoader(
    resource_path = "cfgs",
    debug= __name__ == "__main__",
    root_path=os.path.dirname(os.path.abspath(__file__)))

app = Server(cfg)

if __name__ == "__main__":
    app.run()

```
cfg_loader.py file isnt interesting at all, it only loads cfg depending of the runing environment.

### Host

```
└── app
    └── host
        └── server.py // host, receives api and web routes and manages cfg
```

Server file manages flask app, it will import api and web dependencies and delegates routes registration. It only manages server configuration like templates routes. If any service is needed by views or web it will be injected from here.

```python
import os
from flask import Flask

from api.my_api import MyApi
from web.web_routes import WebRoutes

class Server(Flask):
    def __init__(self, cfg):
        super(Server, self).__init__(
            __name__,
            template_folder=os.path.abspath(cfg.templates_folder),
            static_url_path=os.path.abspath(cfg.static_folder))
        self.cfg = cfg
        self.web_routes = WebRoutes(cfg)
        self.api_routes = MyApi(cfg)
        self.api_routes.register(self)
        self.web_routes.register(self)
    
    def run(self):
        super(Server, self).run(
            host=self.cfg.host,
            port=self.cfg.port,
            debug=self.cfg.debug)
```

### Api

The app Api at this moment has only uri versioning, at this point im not sure that it will not be the best choice, if anyone knows a py library for this problem any apport is welcomed. Because blueprints are not the best choice, at least in my opinion.

```
└── app
    └── api 
        ├── blueprints // Api blueprints
        │   ├── base_blueprint.py
        │   ├── v1 // Api blueprint version 1
        │   │   ├── api_blueprint.py
        │   │   └── my_view.py
        │   └── v2 // Api blueprint version 2
        │       ├── api_blueprint.py
        │       └── my_view_v2.py
        ├── errors // Errors, error handlers 
        │   ├── handlers.py
        │   └── validation_error.py
        ├── my_api.py
        └── responses // api responses
```

The funcitionality of these files is quite intuitive, my_api registers all api endpoints, default responses and error handlers. 

Error handlers has not much interest because it are implemented like in flask documentation, a note for that is that i consider a good practice used as much as possible the Built-in Exceptions. Because using it will avoid unnecesary classes.

Base blueprint only has a generic implementation for reuse on child blueprints that implementation is a refactor for classic CRUD operations.

Now i will show the my_api implementation, as a commented previously this class has the responsibility of registering api routes.

```python
from flask import Flask
from .blueprints.v1.api_blueprint import ApiBlueprint as V1
from .blueprints.v2.api_blueprint import ApiBlueprint as V2

class MyApi(object):
    def __init__(self, cfg, api_basepath="/api"):
        self.cfg = cfg
        self.api_basepath = api_basepath
        
    def register(self, app: Flask):
        #self.response_class = DefaultResponse

        # Register api with blueprints and views
        app.register_blueprint(V1(self.api_basepath))
        app.register_blueprint(V2(self.api_basepath))

        # Register error handler
        #self.register_error_handler(InvalidUsage, self.handle_invalid_usage)
```

### Web

```
└── app
    └── web
        ├── static // JS/CSS files
        ├── templates // html jinja2 templates
        │   └── index.html
        └── web_routes.py // registers web routes on app
```

Web only has static files and templates, web_routes.py will register routing and template rendering functions, if a service is needed it will be provided on constructor. 

```python
from flask import Flask, render_template

class WebRoutes(object):
    def __init__(self, cfg):
        self.cfg = cfg
        self.routes = [
            ("/", self.index, ['GET'])
        ]

    def register(self, app: Flask):
        for (path, func, methods) in self.routes:
            app.add_url_rule(path,  view_func=func, methods=methods)

    def index(self):
        return render_template('index.html')
```

That´s all for now! if any of you wants more posts, detailed implementations or more information/improvements to this archetype. Place a comment below for this rookie developer :D

# Refs
* [Flask](https://flask.palletsprojects.com/en/1.1.x/)
* [Blueprints](https://flask.palletsprojects.com/en/1.1.x/blueprints/)
* [Templates](https://flask.palletsprojects.com/en/1.1.x/templating/)
* [Error handling](https://flask.palletsprojects.com/en/1.1.x/errorhandling/)
* [Custom response classes](https://blog.miguelgrinberg.com/post/customizing-the-flask-response-class)
* [My github - asap i will upload this repo](https://github.com/mandrewcito)