HTTP

Creating an HTTP Interface – be it RESTful or otherwise – is done using the BaseHttpController class.

API

class aioli.controller.BaseHttpController(pkg)[source]

HTTP API Controller

Parameters

pkg – Attach to this package

Variables
  • pkg – Parent Package

  • config – Package configuration

  • log – Controller logger

async on_request(*args)[source]

Called on request arrival for this Controller

async on_shutdown()

Called when the Application is shutting down gracefully

async on_startup()

Called after the Package has been successfully attached to the Application

Example – Controller without route handlers

from aioli.controller import BaseHttpController

from .service import VisitService


class HttpController(BaseHttpController):
    def __init__(self):
        self.visit = VisitService()
        self.log.debug("Guestbook opening")

    async def on_startup(self):
        self.log.debug(f"Guestbook opened at {self.package.path}")

    async def on_request(self, request):
        self.log.debug(f"Request received: {request}")

Routing

Route handlers are standard Python methods decorated with the @route.

API

aioli.controller.decorators.route(path, method, description=None)[source]

Prepares route registration, and performs handler injection.

Parameters
  • path – Handler path, relative to application and package paths

  • method – HTTP Method

  • description – Endpoint description

Returns

Route handler

Example – Route handler without transformation helpers

from aioli.controller import BaseHttpController, Method, route

from .service import VisitService


class Controller(BaseController):
    def __init__(self):
        self.visit = VisitService()

    @route("/", Method.GET, "List of entries")
    async def visits_get(self, request):
        # Just pass along the query params as-is.
        #
        # Serialize and return whatever get_many() returns.
        return await self.visit.get_many(**request.query_params)

Transformation

Transformation is implemented on route handlers using @takes and @returns. These decorators offer a simple yet powerful way of shaping and validating request data, while also making sure API endpoints only returns expected data.

This makes the API more secure and consistent.

Takes

The @takes decorator is used to instruct Aioli how to deserialize and validate parts of a request, and injects the resulting dictionaries as arguments to the decorated function.

API

aioli.controller.decorators.takes(props=None, **schemas)[source]

Takes a list of schemas used to validate and transform parts of a request object. The selected parts are injected into the route handler as arguments.

Parameters
  • props – List of Pluck targets

  • schemas – list of schemas (kwargs)

Returns

Route handler

Example – Route handler making use of @takes

from aioli.controller import (
    BaseHttpController, ParamsSchema, RequestProp,
    Method, route, takes
)

from .service import VisitService


class Controller(BaseController):
    def __init__(self):
        self.visit = VisitService()

    @route("/", Method.GET, "List of entries")
    @takes(query=ParamsSchema)
    async def visits_get(self, query):
        # Transform and validate query params against ParamsSchema,
        # then pass it along to get_many().
        #
        # Serialize and return whatever get_many() returns.
        return serialize(await self.visit.get_many(**query))

Returns

The @returns decorator takes care of serializing the data returned by the route handler.

API

aioli.controller.decorators.returns(schema_cls=None, status=200, many=False)[source]

Returns a transformed and serialized Response

Parameters
  • schema_cls – Marshmallow.Schema class

  • status – Return status (on success)

  • many – Whether to return a list or single object

Returns

Response

Example – Route handler making use of @takes and @returns

from aioli.controller import (
    BaseHttpController, ParamsSchema, RequestProp,
    Method, route, takes, returns
)

from .service import VisitService


class Controller(BaseController):
    def __init__(self):
        self.visit = VisitService()

    @route("/", Method.GET, "List of entries")
    @takes(query=ParamsSchema)
    @returns(Visit, many=True)
    async def visits_get(self, query):
        # Transform and validate query params against ParamsSchema,
        # then pass it along to get_many().
        #
        # Transform and dump the object returned from get_many() -
        # according to the Visit schema, as a JSON encoded response
        return await self.visit.get_many(**query)