Bocadillo 0.13 released!

March 16th, 2019 ยท Florimond Manca

This release represents an important milestone for Bocadillo: it brings a pack of new exciting features, including providers, SSE support and cookie-based sessions. Here's a summary of what's new.


Upgrade instructions

This release removes items that were deprecated by the 0.12.0 release:

  • The API class no longer exists โ€” use App instead!
  • App instances no longer have the .template(), .template_sync() and .template_string() methods. Instead, use the Templates helper.

All 0.12.x releases are compatible with these new APIs. If you're not up to date yet, I recommend you update your apps while staying under 0.12.x, and only then upgrade to 0.13.

Once you're ready to upgrade, you can grab the new version from PyPI:

pip install -U bocadillo

If you have any questions, feel free to get in touch!

Providers: dependency injection for web views

Providers is a new powerful dependency injection mechanism baked right into Bocadillo.

What they allow to do is inject resources into web views. This is done by declaring providers as function parameters, much in the style of pytest fixtures. ๐Ÿ™Œ

Besides being very easy to use, I think that providers:

  • Help build applications that are easy to test, change and maintain.
  • Make the development experience much more enjoyable.

They're quite a big deal, so let's review them more in depth, shall we?

Hello, providers!

Here's the mandatory "Hello, world" example:

# providerconf.py
from bocadillo import provider

@provider
def hello():
    return "Hello, world!"
# app.py
from bocadillo import App

app = App()

@app.route("/")
async def index(req, res, hello):  # <- โœจ
    res.text = hello

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

Motivation and design

Up to now, there was no elegant way to abstract logic into reusable services without resorting to global variables or similar hacks. This often led to cluttered, hard-to-test code, and ultimately impaired the usability of Bocadillo as a web framework.

To solve this, providers were designed to be:

  • Explicit: it's clear which views use which resources.
  • Modular: providers can use other providers, allowing to build an ecosystem of reusable components.
  • Flexible: providers support a variety of syntaxes (sync/async, function/generator) and scopes (request or app), making them suitable for a wide range of use cases.

Besides, providers can be overridden at anytime, thus improving testability.

We extracted the core of this feature into aiodine, an async-first dependency injection library. Be sure to check it out!

Next steps

Providers are a major addition to Bocadillo indeed, and quite a unique feature in the Python web framework space! If you can't wait to try them out, head to the docs: Introduction to providers.

Server-Sent Event support

You may already be familiar with WebSocket โ€” Bocadillo has had built-in support for them since v0.9.

This release pushes the real-time capabilities of Bocadillo even further by introducing support for Server-Sent Events. This technique can be used to cheaply stream events from the server to the client, and build systems such as notifications or live-updating feeds.

Because this builds upon response streaming, you can very easily obtain those events from an external source โ€” such as a message queue or a message broker.

Everything you need to know is in the SSE usage guide, but here's a sneak peak to get you going:

from datetime import datetime
from asyncio import sleep
from bocadillo import App, server_event

app = App()


@app.route("/clock")
async def clock(req, res):
    @res.event_stream
    async def stream():
        while True:
            millis = datetime.now().timestamp() * 1000
            yield server_event(data=str(millis))
            await sleep(1)


@app.route("/")
async def index(req, res):
    res.html = """
        <html>
        <head><meta charset="utf-8"/></head>
        <body>
            <h1>โฑ SSE-powered Clock</h1>
            <div id="time"></div>
            <script>
                const counter = new EventSource("/clock");
                const time = document.getElementById("time");
                counter.onmessage = (e) => {
                    time.innerText = new Date(+e.data).toString();
                };
            </script>
        </body>
    </html>
    """


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

Signed cookie-based sessions have landed in Bocadillo! Thanks a lot to @zgoda for helping bring this feature in.

Sessions allow you to persist data between requests from a given client. You can find an example as well as usage tips in the new Sessions guide.

Testing utilities

This release brings in new testing utilities that you can use to ensure the quality of your Bocadillo applications: create_client and LiveServer.

We also wrote a brand new Testing guide as well as a pytest how-to guide to help you get started with Bocadillo testing! โœ…

Chatbot tutorial

To showcase the real-time capabilities of Bocadillo as well as the new providers feature, the "Getting started" section of the docs got an overhaul.

In particular, there's a brand new tutorial. There, you'll learn how to build a chatbot server using ChatterBot and WebSocket. ๐Ÿค–

Miscellaneous

Middleware improvements

  • The new ASGIMiddleware base class streamlines the writing of ASGI middleware.
  • HTTP middleware classes can now expect both the inner middleware and the app instance to be passed to the constructor, instead of only inner. This allows to perform initialisation on the app by overriding the constructor. The same goes for the new ASGIMiddleware base class. See Configuration and initialization.
  • Fix: ASGI middleware is now properly applied even when the request is routed to a sub-application (e.g. a recipe). In the past, this could lead to CORS headers not being added on a recipe despite them being configured on the root application.

Streaming

  • Fix: stream responses (and SSE streams by extension) now stop as soon as a client disconnects.