Menu

US Region

Grandmetric LLC
Brookfield Place Office
200 Vesey Street
New York, NY 10281
EIN: 98-1615498
Phone: +1 302 691 94 10

info@grandmetric.com

EMEA Region

GRANDMETRIC Sp. z o.o.
ul. Metalowa 5, 60-118 Poznań, Poland
NIP 7792433527
+48 61 271 04 43
info@grandmetric.com

Routing order in aiohttp library in Python

Routing order in aiohttp library in Python



08.07.2020

In the Grandmetric development team, we regularly use the aiohttp library as our asynchronous HTTP client/server for Python. This D&C shows how to use and register request handlers in the aiohttp application.

In particular, we would like to focus on paths order. That’s why you might find other solutions simplified for the sake of our example.

Let’s consider the oversimplified aiohttp server, which has two endpoints:

  • /names/all – returns all names stored in the database
  • /names/{id} – returns a name with given id

We can mock the data using simple Python’s dict:

data = [
    {"name": "Andy"},
    {"name": "Bob"},
    {"name": "Charlie"},
    {"name": "Duncan"},
]

Using request handlers

To handle each of the endpoints, we can use one of the two methods listed below.

First method

import json
from aiohttp import web
async def get_single(request):
    instance_id = int(request.match_info['id'])
    return web.Response(body=json.dumps(data[instance_id]), content_type="application/json")

Second method

import json
 import json  from aiohttp import web
async def get_all(request): return web.Response(body=json.dumps(data), content_type="application/json")

Registering request handlers

After that, we can simply register endpoints and run the application:

app = web.Application()

app.add_routes([web.get('/names/all', get_all)])
app.add_routes([web.get('/names/{id}', get_single)])

web.run_app(app)

This is where we might consider two variants.

  1. registering /names/{id} as the first route
  2. registering /names/all as the first route

It is important to notice that the first pattern that matches the path will be used to handle a particular request.

In the first scenario /names/{id} pattern will match requests like:

/names/0
/names/2
/names/any_string
/names/all

As you can see, it catches everything, so it shadows the second route i.e. /names/all, and its handler will never be reached.

The second scenario, when /names/all comes first solves this issue as it matches only literal /names/all, and other paths are matched by the second route.

Of course, this is not the only solution to this problem, as in this particular case, we could register the path to match only digits as follows:

app.add_routes([web.get('/names/{id:\d+}', get_single)])

Define paths as narrow as possible

As you could see in the example above, it’s important which order of registering paths in the aiohttp library you choose. The best way to avoid issues related to this is to define the path as narrow as possible, e.g., by adding regex as an identifier.

Take a look at this complete GIST example and play around with the order of the routes.

Author

Mateusz Buczkowski

Mateusz Buczkowski is a senior software engineer and a leader of the R&D team. In Grandmetric, Mateusz is responsible for the shape of the software projects as well as takes his part in backend development. On top of that, he researches and develops IoT and wireless solutions. As an R&D engineer, he took part in two FP7 EU projects, namely 5GNOW and SOLDER, where he worked on solutions that could be used in the 5th Generation wireless networks.

Leave a Reply

Your email address will not be published. Required fields are marked *

Sign up to our newsletter!


Grandmetric