9

What is the right approach to use class-based handlers instead of functions in aiohttp library? I'm used to writing handlers as classes in Django so I am wondering how to do it correctly in aiohttp?

Claudio Floreani
  • 2,441
  • 28
  • 34
vwvolodya
  • 2,324
  • 2
  • 20
  • 30

3 Answers3

8

I assume you want to use class-based handlers for sake of applying inheritance for reusing code.

Technically aiohttp web-handler is any coroutine which accepts request parameter and returns response instance.

For example

class BaseView:
    def __init__(self, ...):
        ...

    async def __call__(self, request):
        return web.Response()

app.router.add_route('GET', '/', BaseView(...))

can be used as base class for making web-handlers hierarchy.

Or even

class Handler:
    def __init__(self, db):
        self._db = db

    async def get_from_db(self, data):
        ...

    async def handle_a(self, request):
        data = yield from self.get_from_db(
            self.extract_from_request_a(request))
        return web.Response(self.format_data(data))

    async def handle_b(self, request):
        data = yield from self.get_from_db(
            self.extract_from_request_b(request))
        return web.Response(self.format_data(data))


handler = Handler(db)
app.router.add_route('GET', '/a', hadndler.handle_a)
app.router.add_route('GET', '/b', hadndler.handle_b)
Mikhail Kashkin
  • 1,521
  • 14
  • 29
Andrew Svetlov
  • 16,730
  • 8
  • 66
  • 69
  • 2
    Still do not get the idea how to add post(request) function for example. Should I implement as_view() method to use in urls – vwvolodya Sep 28 '15 at 14:50
  • I've added example for registering an instance. The code doesn't recreate BaseView for every request -- I've found that is not required usually we use approach with `Handle` class very well. – Andrew Svetlov Sep 28 '15 at 15:27
  • 1
    Update: A recent version added [Class Based Views](https://aiohttp.readthedocs.org/en/stable/web.html#class-based-views). Note that there are complications with this, not all the `aio-libs` support it fully – nerdwaller Dec 29 '15 at 17:27
  • Unclear with class based view methods how to specify variables in the route such as you would with @routes.get('/foobar/{something}'). – Samantha Atkins Apr 05 '19 at 21:05
4

You can use it like this:

from aiohttp import web
from datetime import datetime


class TokenView(web.View):

    async def get(self):
        token = datetime.now().strftime("%Y%m%d%H%M%S")
        room = self.request.match_info.get("room", None)
        return web.json_response({"room": room, "token": token, "result": "OK"})

    async def post(self):
        room = self.request.match_info.get("room", None)
        token = datetime.now().strftime("%Y%m%d%H%M%S")
        return web.json_response({"room": room, "token": token, "result": "OK"})


if __name__ == "__main__":

    app = web.Application()
    app.router.add_view("/token/{room}", TokenView)
    print(app.router.named_resources())
    web.run_app(app)
Even
  • 41
  • 1
1

Quick example of Class-based views in aiohttp

from aiohttp import web

class Users(web.View):

    async def get(self):
        output = [
            {   
                'id': 1,
                'username': 'chuck_norris'
            },
        ]
        return web.json_response(output, status=200)

    async def post(self):
        data = await self.request.json()
        output = {
            'result': data
        }
        return web.json_response(output, status=201)

    async def delete(self):
        return web.json_response(status=204)


class Teams(web.View):

    async def get(self):
        output = [
            {   
                'id': 1,
                'team': 'team1'
            },
        ]
        return web.json_response(output, status=200)

    async def post(self):
        data = await self.request.json()
        output = {
            'result': data
        }
        return web.json_response(output, status=201)

    async def delete(self):
        return web.json_response(status=204)


app = web.Application()

app.router.add_view("/users", Users)
app.router.add_view("/teams", Teams)

web.run_app(app, port=8000)
Slipstream
  • 13,455
  • 3
  • 59
  • 45