Menu

Poland

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

Sweden

Drottninggatan 86
111 36 Stockholm
+46 762 041 514
info@grandmetric.com

UK

Grandmetric LTD
Office 584b
182-184 High Street North
London
E6 2JA
+44 20 3321 5276
info@grandmetric.com

US Region

Grandmetric LLC
Lewes DE 19958
16192 Coastal Hwy USA
EIN: 98-1615498
+1 302 691 94 10
info@grandmetric.com

  • en
  • pl
  • se
  • Routing order in aiohttp library in Python

    Routing order in aiohttp library in Python

    Date: 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 *


    Grandmetric