How to write a Python web API with Pyramid and Cornice

Use Pyramid and Cornice to build and document scalable RESTful web services.
Register or Login to like
Searching for code

Python is a high-level, object-oriented programming language known for its simple syntax. It is consistently among the top-rated programming languages for building RESTful APIs.

Pyramid is a Python web framework designed to scale up with an application: it's simple for simple applications but can grow for big, complex applications. Among other things, Pyramid powers PyPI, the Python package index. Cornice provides helpers to build and document REST-ish web services with Pyramid.

This article will use the example of a web service to get famous quotes to show how to use these tools.

Set up a Pyramid application

Start by creating a virtual environment for your application and a file to hold the code:

$ mkdir tutorial
$ cd tutorial
$ touch
$ python3 -m venv env
$ source env/bin/activate
(env) $ pip3 install cornice twisted

Import the Cornice and Pyramid modules

Import these modules with:

from pyramid.config import Configurator
from cornice import Service

Define the service

Define the quotes service as a Service object:

QUOTES = Service(name='quotes',
                 description='Get quotes')

Write the quotes logic

So far, this only supports GETing quotes. Decorate the function with QUOTES.get; this is how you can tie in the logic to the REST service:

def get_quote(request):
    return {
        'William Shakespeare': {
            'quote': ['Love all, trust a few, do wrong to none',
            'Some are born great, some achieve greatness, and some have greatness thrust upon them.']
    'Linus': {
        'quote': ['Talk is cheap. Show me the code.']

Note that unlike in other frameworks, the get_quote function is not changed by the decorator. If you import this module, you can still call the function regularly and inspect the result.

This is useful when writing unit tests for Pyramid RESTful services.

Define the application object

Finally, use scan to find all decorated functions and add them to the configuration: 

with Configurator() as config:
    application = config.make_wsgi_app()

The default for scan is to scan the current module. You can also give the name of a package if you want to scan all modules in a package.

Run the service

I use Twisted's WSGI server to run the application, but you can use any other WSGI server, like Gunicorn or uWSGI, if you want:

(env)$ python -m twisted web --wsgi=main.application

By default, Twisted's WSGI server runs on port 8080. You can test the service with HTTPie:

(env) $ pip install httpie
(env) $ http GET http://localhost:8080/
HTTP/1.1 200 OK
Content-Length: 220
Content-Type: application/json
Date: Mon, 02 Dec 2019 16:49:27 GMT
Server: TwistedWeb/19.10.0
X-Content-Type-Options: nosniff

    "Linus": {
        "quote": [
            "Talk is cheap. Show me the code."
    "William Shakespeare": {
        "quote": [
            "Love all,trust a few,do wrong to none",
            "Some are born great, some achieve greatness, and some greatness thrust upon them."

Why use Pyramid?

Pyramid is not the most popular framework, but it is used in some high-profile projects like PyPI. I like Pyramid because it is one of the frameworks that took unit testing seriously: because the decorators do not modify the function and there are no thread-local variables, functions are callable directly from unit tests. For example, functions that need access to the database will get it from the request object passed in via request.config. This allows a unit tester to put a mock (or real) database object in the request, instead of carefully setting globals, thread-local variables, or other framework-specific things.

If you're looking for a well-tested library to build your next API, give Pyramid a try. You won't be disappointed.

What to read next
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe has been involved in the Linux community since 1998, helping in Linux "installation parties". He has been programming Python since 1999, and has contributed to the core Python interpreter. Moshe has been a DevOps/SRE since before those terms existed, caring deeply about software reliability, build reproducibility and other such things.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.