|
|
Subscribe / Log in / New account

Microdot: a web framework for microcontrollers

Did you know...?

LWN.net is a subscriber-supported publication; we rely on subscribers to keep the entire operation going. Please help out by buying a subscription and keeping LWN on the net.

By Jake Edge
January 23, 2024

There are many different Python web frameworks, from nano-frameworks all the way up to the full-stack variety. One that recently caught my eye is Microdot, the "impossibly small web framework for Python and MicroPython"; since it targets MicroPython, it is plausible for running the user interface of an "internet of things" (IoT) device, for example. Beyond that, it is Flask-inspired, which should make it reasonably familiar to many potential web developers.

Microdot was created by Miguel Grinberg, who also created the well-known Flask Mega-Tutorial that has served as the introduction to the Flask web framework for many people. While Flask is considered to be a microframework, it still requires a full CPython environment to run; another Python microframework described alongside Flask in a 2019 LWN article, Bottle, has similar needs. Microdot came about because Grinberg wanted a framework for MicroPython and did not find anything usable back in 2019.

MicroPython is a cut-down version of Python that is suitable for microcontrollers; LWN looked at version 1.20 in May 2023. There is a lengthy list of differences between MicroPython and CPython, but there is enough overlap that Python—and web—programmers will feel right at home with Microdot. Code can be moved back and forth, because Microdot can also run under CPython, though, of course, MicroPython runs on regular CPUs as well.

As shown in Grinberg's announcement blog post, a canonical "hello world" web application looks fairly straightforward:

    from microdot import Microdot

    app = Microdot()

    @app.get('/')
    async def index(request):
        return {'hello': 'world'}

    app.run(debug=True)

The @app.get() decorator describes the URL to match and the index() function returns data that is used as the response. In this case, returning a dictionary causes Microdot to format the response as JSON; a status code or custom headers can be returned as the second and third elements of a multi-value return.

One thing that does stand out in the example is the "async def" in the definition of index(). While Microdot 1.0, which was released in August 2022, had a synchronous base with an asyncio extension, Microdot 2.0, which was released in December, is designed to be fully asynchronous. Regular def can still be used with Microdot 2.0, but web-server responsiveness will suffer on microcontrollers, which generally lack threading support. Instead, inside a handler defined with async def, processing that requires I/O should be handled using await, rather than synchronously waiting for the operation to return control. Grinberg gave a talk on asynchronous Python at PyCon 2017 that may be of interest to readers who are not familiar with the topic.

While Microdot is inspired by Flask, it is not beholden to it. In particular, Grinberg said that he liked the Flask Blueprints for modularizing web applications, but thought the Flask mechanism was too complicated. So Microdot has the concept of "mounting" sub-applications at different points in the URL hierarchy. As the documentation shows, a customer_app and an orders_app can be created in two separate files, which get imported into the main application source file in order to create the full application with something like:

    def create_app():
        app = Microdot()
        app.mount(customers_app, url_prefix='/customers')
        app.mount(orders_app, url_prefix='/orders')
        return app

That allows the functionality for customers and orders to be written as if they are at the top-level of the hierarchy, then they can be mounted where they should actually appear; any reorganization would not require changes to the sub-applications, just a different mount point, as long as relative URLs are used within the sub-application code.

For rendering its pages, Microdot supports the familiar Jinja templating engine, but only for CPython. For MicroPython, utemplate can be used and it will work on CPython too; it implements a simplified version of the Jinja syntax. Other extensions provide WebSocket, secure user session, server-sent event (SSE), and other functionality.

In its most minimal configuration, Microdot clocks in at a little over 700 lines of code (plus comments and blank lines) in a single file; the full configuration is a bit over double that in 11 files. Grinberg contrasts that with Flask and FastAPI, which both come in around ten times the number of lines of code when including their main dependencies (Werkzeug and Starlette, respectively). Meanwhile, the third-party dependencies for Microdot are minimal, as one might guess:

The single-file minimal version does not require any dependencies at all, and it even includes its own web server. Some of the optional features do require third-party dependencies, and this is comparable to the larger frameworks. Like Flask, you will need to add a templating library (Jinja or uTemplate) to use templates. For user sessions, Microdot relies on PyJWT, while Flask uses its own Itsdangerous package.

Deploying a web application on MicroPython uses the built-in web server, but CPython can use Asynchronous Server Gateway Interface (ASGI) servers or those that support its predecessor of sorts: Web Server Gateway Interface (WSGI). TLS is also supported so serving can be done over HTTPS. There are several example programs using each server type, and both template engines, linked from the documentation. While WSGI is a synchronous protocol, Microdot itself runs in an asyncio event loop, so async def and await should still be used.

Overall, Microdot looks like a nice option for new projects for microcontrollers. Grinberg specifically does not recommend that people drop their current CPython framework in favor of Microdot, unless they are unhappy with it or need to really eke out the memory savings that Microdot can provide. There are now multiple MicroPython web frameworks and tools listed on the Awesome MicroPython web site, so there are lots more options than what Grinberg found five years ago. A simple web application makes for an almost ideal interface to a headless, network-connected device, so finding ways to make them easier to develop is welcome. From that perspective, Microdot is worth a look.


Index entries for this article
PythonWeb


(Log in to post comments)

Microdot: a web framework for microcontrollers

Posted Jan 24, 2024 19:27 UTC (Wed) by NightMonkey (subscriber, #23051) [Link]

Very well-written summary - good enough to really understand the place and purpose for Microdot.

I have to say that Microdot's mechanism for modularizing web applications looks... very nice. As someone who has used Blueprints, the app.mount approach seems simpler than Blueprints without reducing usefulness.


Copyright © 2024, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds