Making the MiniBookDB database public

Posted on Sat 04 January 2020 in Programming

The biggest limitation (by design) of MiniBookDB is that it is designed to be deployed only on private network, so no security features. Being in a private network without being accessible from the outside make difficult to check if you already own a book when you are buying one in a shop.

Add that I no longer work with NodeJs and I am not interested to add some security features to it since they are outside the original goal of the project, this leave the problem open.

So enter Python and Flask.
The idea is to have a Flask microservice deployed to a public server (a Linode in this case but it is not really important) that is called from MiniBookDB every time a book is added to generate a set of static html pages.

The MiniBookDB call just pass some basic information about the book (title and author) to the API exposed from the microservice that store the book in a local SQLite db and then generate the HTML pages.

The code is really simple, most of it can be found in a lot of tutorial online on how to build a microservice with Python and Flask.

There are 2 class defined DbConn which handles the SQLite connection and operation and HtmlOutput which generate the HTML files. These two classes are necessary only to have some structured code and because the code can be executed as a CLI command.

The code is quite simple, a Flask app is instantiated and then a HTTPBasicAuth instance is created

    app = Flask(__name__)
    auth = HTTPBasicAuth()

then a set of routes are defined:

@auth.get_password
def get_password(uname):
   ...

@auth.error_handler
def unauthorized():
    return make_response(jsonify({'error': 'Want some tea ?'}), 418)


@app.route('/book/store', methods=['POST'])
@auth.login_required
def add_book():
   ...

The called API is defined by the /book/store POST route that call the add_book method that, as the code show, need authentication to be executed.
The authentication is performed from the @auth routes, one to check the login/password and one to return an error if the credential are not verified. Note the error code returned ;-)

The add_book method then extract the data from the POST call, store them in a JSON object and call an helper function that instantiate the HtmlOutput class to generate the HTML files.

The helper function is necessary since the script can be also used as a command from the CLI if called with the --clirun paramater, which basically regenerate all the HTML files without storing any new record.

The entry point is pretty trivial

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--clirun', action='store_true', help='Generate the html files from cli')
    args = parser.parse_args()
    if args.clirun:
        generateHtml({})
        sys.exit(0)
    else:
        app.run(debug=False)

it just parse the command line arguments and decide if it must run as service or as CLI command.