(Toy) Python Web Framework

Legal Tech API Support War Stories 

Having worked for a Legal Tech SaaS platform for a while now, it’s clear to me that there are a lot of people in our client's organisations, who have a great foundational knowledge of the of the web (HTML, CSS, JavaScript) and despite not necessarily being developers per se, they are still able to create web pages, usually via some editor already embedded into a web-based platform or via a ‘no-or-low-code’ tool.

Obviously that's great, but as a Legal Technologist, you will likely want to be able to populate web pages with data from the different platforms which your business uses and there may not be a clear path as to how to achieve this.All too often, consuming a REST API is something which they may not have done before, and it can quickly become a point of frustration. Further to this, the overhead of authenticating and managing tokens, etc, as well as stepping through all of the fiddly bits of constructing HTTP requests can seem overwhelming at first.

This got me thinking; is there a better way to get these types of web-curious users up and running more quickly, without necessarily giving them a crash course in becoming a full-stack developer?


Web Framework For Non-Developers

The trend in Python web development frameworks of late has decidedly been towards 'micro' frameworks, which pertain to be non-opinionated and give the developer as much flexibility as possible. But what if one was to design a web development framework for non-developers? 'Magicals' suddenly become a good thing. In this case, the proposed framework could abstract away a lot of the grubbing around required to get an integration with an external system up and running, leaving your Legal Technologists as much freedom as possible to do what they actually want to be doing, which is creating informative and beautiful web pages using the technologies that they are familiar with. 

This lead me to create a Python based micro-framework which I've dubbed 'HQSP'. Despite Python being my main interest, I could legitimately claim it to be a strategic choice here, as its a high level, dynamically typed and interpreted language, meaning its considered quicker and easier to learn than many others. A user with decent working knowledge of JavaScript, (for instance), should be able to pick up the basics without issue.

For this reason, HQSP only supports 'function' based controllers. It is easy to understand a Python function. A user developing an application in the framework, won’t have to wrap their head around Object-Oriented Programming. A function simply receives a request and returns a response... that's it, (and arguably how it should be)!


EXAMPLE APP BUILT WITH HQSP

Here is a simple app which consumes the REST API of Virtual Data Room provider, displaying the details of a specific VDR.

# demo.py

from hqsp import Application
import requests as http_handler

app = Application()

@app.set_headers
def dataroom_detail(headers, base_url, request, response, vdr_id):

    external_response = http_handler.get(
        f"{base_url}/api/1/dataroom/{vdr_id}", headers=headers
    )

    response.body = app.template("VDR.html", context=external_response.json())



app.add_routes({"/site/{vdr_id}": dataroom_detail})

 

The framework user declares an Application object, and then they are able to use a decorator on their functions, which magically pass in everything needed to make the API call to the external service. You will then see that the response's body is set to be the application's template method, which loads together the html file and a JSON structure of the data returned from the API call. Under the hood, the Framework is leveraging the popular Jinja2 templating language, as well as Whitenoise for serving static files.

Speaking of this, static resources live underneath the 'Static' directory, HTML Templates live under the 'Templates' directory. To labour an earlier point, there is no flexibility here. In terms of organising these files, HQSP is rigid and opinionated, so that its users are concentrating on the 'building the App' part of the process, rather than something like 'overriding the default path for static files',etc, etc. 

I have downloaded the Bootstrap framework, with the minified asset bundles, so along with an html template, the entire structure for my ‘app’ looks like this:

static
|--css
   |--bootstrap.min.css
|--js
   |--bootstrap.min.css

templates
|—sites.html

demo.py

In the same top level directory I have a settings.ini file, which effectively just captures the details of an initial (manual) OAuth token call.

[AUTH]
access_token = REDACTED_your_token_here
access_expiry = 2592000
refresh_token= REDACTED_your_token_here
refresh_expiry = 2628000
token_type = bearer
user = peter.simpson@blahblahexample.com

[INSTANCE]
host = https://legal.platform.com/api

[APP]
name = demo

The last thing to mention from the demo.py file is the 'add_routes' method. This creates a mapping from a path to a function and you'll notice that there is a path parameter in there {site_id}, so the page will dynamically load different data depending on the value that gets passed to it. 

HQSP conforms to the WSGI standard for Python web frameworks, so it can be run by any WSGI Server. I choose the popular Gunicorn, which means the Application can be run like so: 
 

$ gunicorn demo:app

 

Here are the results: 


 

Hardly very visually impressive, but hopefully the intent is clear. Your Legal Tech team can now write simple Python functions to fetch data from the given legal tech provider and surface it into HTML templates, along with any stylings and JavaScript required. A much more complex application could easily be extended from this core set of functionality. 

As mentioned, the framework also takes care of token refreshment, but a user purposefully doesn't know anything about that. So long as the function controllers are decorated with '@app.set_headers', behind the scenes: HQSP works out whether or not a refresh is required and persists the tokens to storage. 


Concluding Thoughts

All in all, the actual HQSP framework is less than a few hundred lines of code. Its mostly just gluing together pre-existing open source tools from the Python world. These tend to be packages for dealing with a single well trodden Web programming problem. WebOb provides the HTTP Objects, Jinja2 (already mentioned) does the templating, whilst WhiteNoise serves static files. I must give credit to the blog series ‘How to write a Python web framework’ by Jahongir Rahmonov. My framework undoubtedly heavily resembles the one built as part of those tutorials. Alcazar is a web framework which extends the ideas from those initial 4 blog posts.

Worth mentioning that I have also made 0 security considerations, hence it being a self-declared 'prototyping' framework. These Applications are intended only to be served locally. Once its users have their POCs, the idea would currently be that they would hand over to their developers, who could then build the ideas out in the MVC framework of their choice. 

HQSP was built with a particular legal tech vendor in mind, but I have obfuscated who exactly that is. The 'auth' part of the framework was made to work for their particular authentication 'flow', but the repository could easily be forked and that part of the code ripped out and/or re-written for a different system. Infact I undoubtedly think I'll revist this and use it as the basis of a more fully fledged project at some point in the future. 
 


Web Frameworks are plentiful and essentially represent a problem already solved. The only real reason to build one would be to either learn how they work (which is a valuable exercise in and of itself), or if you have a use-case so specific that it can be better served with a refinement of an already existing paradigm. I hope that the notion of a framework for non developers wanting to leverage a particular API, is clear.