Have fun using AIOHTTP

Have fun using AIOHTTP

I need a simple web server framework to build a small app, I used to use django, it has everything even something I no need... I'm not blaming django, acutally django is a mature web framework. But I want some fun.

I used to use java: Struts 1, JSF, Spring MVC, node: express, koa, clojure: compojure, elixir: phoenix, python: django to build web application. Actually every framework tries to resolve the basic problem - handle request/response, manage context.

In Request side needs to think about how to handle request parameter & request body.

In Response side needs to think about the return types, html, json, xml, binary...etc

For context the problem becomes user's session and how to do access control via authorization & authentication.

On top of the basic problems the benifit and main reason why you decide to choice one fromwork rather than others, I think it should be whether this framework can support new concept or popular features e.g graphQL, webScoket, reactive. Support not meanning the framework must have everything, whenever I need that feature I can easily to integrate or install the library for that framework. So the framework must be small & flexible to start.

AIOHTTP is the one who is small and has plugable library on demand.

To describe AIOHTTP for short is that it's an Async HTTP client/server for asyncio and Python

Since I only use AIOHTTP server part, so this post only focuse on server part.

What's asyncio(coroutine)

asyncio is a builtin library for python to implement coroutine. AIOHTTP is based on this core library that means every request handler function in AIOHTTP is a async fuction and we can put the task as a couroutine task in an eventloop inside the handler function. So how the request handler looks like?

@subscription_routes.view("/subscribeList")
@aiohttp_jinja2.template("subscription.html")
async def subscription_list(request):
    web_session = await get_session(request)
    user = web_session.get("user", {})
    email = user.get("email", "")
    db_session = apply_session()
    subs = []
    for sub in db_session.query(Subscription).filter(Subscription.email == email).all():
        try:
            subs.append(await get_subscribed_item(sub.symbol))
        except:
            continue
    return {"subs": subs}

The every first two lines define request URL and response(for this example is html page).

The function body is that I get user from http session and then query user subscribed items from database after that return all subscribed items to jinja2 template for rendering html.

The important part is:

await get_subscribed_item(sub.symbol)

get_subscribed_item function relies on anohter web service so I have to wait for that API call to get full subscribed item. Since this function always take long time so I create an event loop to handle coroutine task that request will not be block each other.

There is the get_subscribed_item function:

async def get_subscribed_item(symbol):
    loop = asyncio.get_event_loop()
    score, _, close_price, result = await loop.run_in_executor(None, xg_predict, symbol)
    stock = await loop.run_in_executor(None, yf.Ticker, symbol)
    stock_data = stock.history(period="1d")
    return {
        "symbol": symbol,
        "predictScore": score,
        "currentPrice": stock_data["Close"].values[0],
        "limit_up_down": round(100 * (result / close_price), 2),
    }

Request and Response that's all

As a small web framework, AIOHTTP the basic library only handle request and response. If you need response to handle html template you need to install aiohttp-jinja2 separately. Of course only request & response can't create a web application, at least we need session and maybe DB related feature and more benefits. AIOHTTP has them but thery are all as plugin to present in AIOHTTP.

For HTTP Session & Security?

if you need to have session & security handler then you need to install aiohttp-session & aiohttp-security

For DB related CRUD/schema migration

AIOHTTP officially provide one async library for postgresQL and MySQL, but you still can use SQLAlchemy with any your favourite database. Acutally I use sqlalchemy with sqlite for fun 😊. For schema migration we also can use Alembic. I have to say SQLAlchemy + Alembic is really powerful, no matter you use python or not.

Testing

We still can use pytest to do unit test, and AIOHTTP also provides an integration testing plugin of pytest for API testing pytest-aiohttp.

Simple made easy (Summary)

Sorry to borrow Rich Hickey‘s saying for python AIOHTTP.

If I go though all AIOHTTP details, I don't think one post can finish it. I may create anohter post for AIOHTTP details such as how to orgnize a project and how to build RESTful API ...

For me I really like AIOHTTP because it has clear goal and whenever I need dependency I can find out it. Another fun is AIOHTTP has a boilerplate project call create-aio-app like reactjs has create react app. If you need to build a python based web app may think about it.