Skip to main content

Aio web server

Project description

Detailed documentation
**********************

aio.web.server
==============

Web server for the aio_ asyncio framework

.. _aio: https://github.com/phlax/aio



Build status
------------

.. image:: https://travis-ci.org/phlax/aio.web.server.svg?branch=master
:target: https://travis-ci.org/phlax/aio.web.server


Installation
------------
Install with:

.. code:: bash

pip install aio.web.server


Configuration
-------------

Example configuration for a hello world web page

.. code:: ini

[server/test]
factory = aio.web.server.factory
port = 8080

[web/test/page]
match = /
route = my.example.handler

And the corresponding route handler

.. code:: python

import asyncio
import aiohttp

@asyncio.coroutine
def handler(request):
return aiohttp.web.Response(body=b"Hello, web world")


Running
-------

Run with the aio command

.. code:: bash

aio run



aio.web.server usage
-------------


Configuration
-------------

Let's create a config defining a factory method and using the aio.web.server.protocol for the protocol

In the following configuration example a server named "example-1" is set up.

Any sections that start with "web/example-1/" will be treated as route definitions.

The route definition should provide a "match" and a "route" at a minimum.

The route is given a name derived from the section name. In this case "homepage"

>>> web_server_config = """
... [aio]
... log_level: ERROR
...
... [server/example]
... factory = aio.web.server.factory
... port = 7070
...
... [web/example/homepage]
... match = /
... route = aio.web.server.tests._example_handler
... """

>>> import asyncio
>>> import aiohttp
>>> import aio.web.server.tests
>>> from aio.app.runner import runner
>>> from aio.testing import aiofuturetest

>>> @asyncio.coroutine
... def handler(request):
... return aiohttp.web.Response(body=b"Hello, web world")

>>> aio.web.server.tests._example_handler = handler

>>> @aiofuturetest(sleep=1)
... def run_web_server(config, request_page="http://localhost:7070"):
... yield from runner(['run'], config_string=config)
...
... @asyncio.coroutine
... def call_web_server():
... result = yield from (
... yield from aiohttp.request(
... "GET", request_page)).read()
...
... print(result.decode())
...
... return call_web_server

>>> run_web_server(web_server_config)
Hello, web world


Accessing web apps
------------------

You can access a webapp by name

>>> import aio.web.server
>>> aio.web.server.apps['example']
<Application>

>>> aio.web.server.apps['example']['name']
'example'

Let's clear the web apps, this will also call aio.app.clear()

>>> aio.web.server.clear()
>>> aio.web.server.apps
{}

>>> print(aio.app.config, aio.app.signals)
None None


Static directory
----------------

The "web/" section takes a static_url and a static_dir option for hosting static files

>>> config_static = """
... [aio]
... log_level: ERROR
...
... [server/test]
... factory: aio.web.server.factory
... port: 7070
...
... [web/test]
... static_url: /static
... static_dir: %s
... """

>>> import os
>>> import tempfile

>>> with tempfile.TemporaryDirectory() as tmp:
... with open(os.path.join(tmp, "test.css"), 'w') as cssfile:
... res = cssfile.write("body {}")
...
... run_web_server(
... config_static % tmp,
... request_page="http://localhost:7070/static/test.css")
body {}

And clear up...

>>> aio.web.server.clear()


Routes, templates and fragments
-------------------------------

aio.web.server uses jinja2 templates under the hood

On setup aio searches the paths of modules listed in the aio:modules option for folders named "templates" and loads any templates it finds from there

>>> config_template = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-2]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-2/homepage]
... match = /
... route = aio.web.server.tests._example_route_handler
... """


Routes
~~~~~~

By decorating a function with @aio.web.server.route, the function is called with the request and the configuration for the route that is being handled

>>> @aio.web.server.route("test_template.html")
... def route_handler(request, config):
... return {
... 'message': 'Hello, world'}

>>> aio.web.server.tests._example_route_handler = route_handler

>>> run_web_server(config_template)
<html>
<body>
Hello, world
</body>
</html>

>>> aio.web.server.clear()

Templates
~~~~~~~~~

A route handler can defer to other templates, for example according to the path.

The @aio.web.server.route decorator does not require a template, but in that case the decorated function must return an aiohttp.web.StreamResponse object

A route always takes 2 arguments - request and config, a template can take any arguments that it requires

While you can use an @aio.web.template as a route handler, doing so would bypass the normal logging and request handling operations

>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /{path:.*}
... route = aio.web.server.tests._example_route_handler
... """

>>> @aio.web.server.template("test_template.html")
... def template_handler_1(request):
... return {'message': "Hello, world from template handler 1"}

>>> @aio.web.server.template("test_template.html")
... def template_handler_2(request):
... return {'message': "Hello, world from template handler 2"}

>>> @aio.web.server.route
... def route_handler(request, config):
...
... if request.path == "/path1":
... return (yield from template_handler_1(request))
...
... elif request.path == "/path2":
... return (yield from template_handler_2(request))

>>> aio.web.server.tests._example_route_handler = route_handler

>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path1")
<html>
<body>
Hello, world from template handler 1
</body>
</html>

>>> aio.web.server.clear()

>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/path2")
<html>
<body>
Hello, world from template handler 2
</body>
</html>

>>> aio.web.server.clear()

Fragments
~~~~~~~~~

Both routes and templates are expected to return a full html page, or an html response object.

Fragments render a snippet of code, and are not expected to return a full page.

Fragments cannot return an html response object, but can raise an html error if required

>>> example_config = """
... [aio]
... modules = aio.web.server.tests
... log_level: ERROR
...
... [server/example-3]
... factory: aio.web.server.factory
... port: 7070
...
... [web/example-3/paths]
... match = /
... route = aio.web.server.tests._example_route_handler
... """

>>> @aio.web.server.fragment("fragments/test_fragment.html")
... def fragment_handler(request, test_list):
... return {'test_list': test_list}

>>> @aio.web.server.template("test_template.html")
... def template_handler(request, test_list):
... return {'message': (yield from fragment_handler(request, test_list))}

>>> @aio.web.server.route
... def route_handler(request, config):
...
... return (yield from template_handler(request, ["foo", "bar", "baz"]))

>>> aio.web.server.tests._example_route_handler = route_handler

>>> run_web_server(
... example_config,
... request_page="http://localhost:7070/")
<html>
<body>
<ul>
<li>foo</li><li>bar</li><li>baz</li>
</ul>
</body>
</html>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for aio.web.server, version 0.0.3
Filename, size File type Python version Upload date Hashes
Filename, size aio.web.server-0.0.3.tar.gz (7.5 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page