1. A tiny “Hello, World” service

In this tutorial, we’re going to build up a simple service to show off various aspects of Baseplate.py.

Prerequisites

This tutorial expects you to be familiar with Python and the basics of web application development. We will use Python 3.7 and virtual environments. To get set up, see this guide on installing Python.

Make a home for our service

First, let’s create a folder and virtual environment to isolate the code and dependencies for this project.

$ mkdir tutorial
$ cd tutorial
$ virtualenv --python=python3.7 venv
Running virtualenv with interpreter /usr/bin/python3.7
Using base prefix '/usr'
New python executable in /home/user/tutorial/venv/bin/python3.7
Also creating executable in /home/user/tutorial/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
$ source venv/bin/activate

Build a simple Pyramid service

Pyramid is a mature web framework for Python that we build HTTP services with. We’ll start our service out by using it without Baseplate.py at all:

$ pip install pyramid

Now let’s write a tiny Pyramid service, open your editor and put the following in helloworld.py:

from wsgiref.simple_server import make_server

from pyramid.config import Configurator
from pyramid.view import view_config


@view_config(route_name="hello_world", renderer="json")
def hello_world(request):
    return {"Hello": "World"}


def make_wsgi_app():
    configurator = Configurator()
    configurator.add_route("hello_world", "/", request_method="GET")
    configurator.scan()
    return configurator.make_wsgi_app()


if __name__ == "__main__":
    app = make_wsgi_app()
    server = make_server("127.0.0.1", 9090, app)
    server.serve_forever()

Then run it:

$ python helloworld.py

Now that you have got a server running, let’s try talking to it. From another terminal:

$ curl localhost:9090
{"Hello": "World"}

and the server should have logged about that request:

127.0.0.1 - - [06/Aug/2019 23:32:40] "GET / HTTP/1.1" 200 18

Great! It does not do much, but we have got a very basic service up and running now.

Breaking it down

See also

You can get way more detail about what’s going on in Pyramid in Pyramid’s own tutorial.

There are three things going on in this tiny service. Following how the code actually runs, we start out at the end of the file with the creation of the HTTP server:

if __name__ == "__main__":
    app = make_wsgi_app()
    server = make_server("127.0.0.1", 9090, app)
    server.serve_forever()

This is using the wsgiref module from the Python standard library to run a basic development server. WSGI is the Python standard interface between HTTP servers and applications. Pyramid applications are WSGI applications and can be run on any WSGI server.

Note

This server will do fine for this quick start, but we won’t want to stick with it as we scale up as it can’t handle multiple requests at the same time.

This server code calls our make_wsgi_app function to get the actual application. Let’s look at that next:

def make_wsgi_app():
    configurator = Configurator()
    configurator.add_route("hello_world", "/", request_method="GET")
    configurator.scan()
    return configurator.make_wsgi_app()

The real workhorse here is the Configurator object from Pyramid. This object helps us configure and build an application.

    configurator.add_route("hello_world", "/", request_method="GET")

First off, we add a route that maps the URL path / to the route named hello_world when the HTTP verb is GET. This means that when a request comes in that matches those criteria, Pyramid will try to find a “view” function that is registered for that route name.

    configurator.scan()

Then we tell Pyramid to scan the current module for declarative registrations. Because of the @view_config decorator, Pyramid will find the hello_world function in our service and recognize that we have registered it to handle the hello_world route.

    return configurator.make_wsgi_app()

Finally, we ask the configurator to build a WSGI application based on what we have configured and return that to the server.

At this point, we have done the one-time application startup and handed off our application to the server which is ready to call into it when requests come in. Now it’s time to look at the code that actually runs on each request.

@view_config(route_name="hello_world", renderer="json")
def hello_world(request):
    return {"Hello": "World"}

This function gets called each time a matching request comes in. Pyramid will build a Request object and pass it into our function as request. This contains all the extra information about the request, like form fields and header values. Whatever gets returned from this function will be rendered by the renderer we specified in the @view_config and then sent to the client.

Summary

We have built a tiny service on Pyramid and understand how the code all fits together. So far, there’s been no Baseplate.py at all. Next up, we’ll look at what’s involved with adding it in.