Skip to content

Commit

Permalink
Merge pull request #53 from xsnippet/no-post-init-router
Browse files Browse the repository at this point in the history
Remove router assignment via app._router property
  • Loading branch information
malor committed Jan 4, 2018
2 parents 68be785 + 38ba94e commit 33b5178
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 78 deletions.
82 changes: 9 additions & 73 deletions xsnippet/api/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
:license: MIT, see LICENSE for details
"""

import collections
import functools

import pkg_resources
import aiohttp.web

from . import database, router, middlewares
from . import database, router, middlewares, resources


def _inject_vary_header(request, response):
Expand Down Expand Up @@ -56,24 +54,21 @@ def create_app(conf):
:return: an application instance
:rtype: :class:`aiohttp.web.Application`
"""

v1 = aiohttp.web.UrlDispatcher()
v1.add_route('*', '/snippets', resources.Snippets)
v1.add_route('*', '/snippets/{id}', resources.Snippet)
v1.add_route('*', '/syntaxes', resources.Syntaxes)

# We need to import all the resources in order to evaluate @endpoint
# decorator, so they can be collected and passed to VersionRouter.
from . import resources # noqa
app = aiohttp.web.Application(
middlewares=[
functools.partial(middlewares.auth.auth, conf['auth']),
])
],
router=router.VersionRouter({'1.0': v1}))
app.on_startup.append(middlewares.auth.setup)

# Since aiohttp 1.1, UrlDispatcher has one mandatory attribute -
# application instance, that's used internally only in subapps
# feature. Since aiohttp 1.2, application instance should be passed
# via post_init() method, however, this method must be called
# before registering any resources. That means we are forced
# to create router when application is created in order to
# do API auto discovering.
app._router = router.VersionRouter(endpoint.collect(app))

# Attach settings to the application instance in order to make them
# accessible at any point of execution (e.g. request handling).
app['conf'] = conf
Expand All @@ -84,62 +79,3 @@ def create_app(conf):
app.on_response_prepare.append(_inject_vary_header)

return app


class endpoint:
"""Define a RESTful API endpoint.
Usage example:
@endpoint('/myresources/{id}', '1.0')
class MyResource(aiohttp.web.View):
def get(self):
pass
:param route: a route to a wrapped resource
:param version: initial supported API version
:param end_version: last supported version; latest version if None
"""

_Item = collections.namedtuple('ResourceItem', [
'resource',
'route',
'version',
'end_version',
])

_registry = []

def __init__(self, route, version, end_version=None):
self._options = (route, version, end_version)

def __call__(self, resource):
self._registry.append(self._Item(resource, *self._options))
return resource

@classmethod
def collect(cls, app):
rv = {}

# Create routers for each discovered API version. The main reason why
# we need that so early is to register resources in all needed routers
# according to supported version range.
for item in cls._registry:
rv[item.version] = aiohttp.web.UrlDispatcher()
rv[item.version].post_init(app)

for item in cls._registry:
# If there's no end_version then a resource is still working, and
# latest discovered version should be considered as end_version.
end_version = item.end_version or sorted(
rv.keys(),
key=pkg_resources.parse_version
)[-1]

V = pkg_resources.parse_version

for version in rv.keys():
if V(item.version) <= V(version) <= V(end_version):
rv[version].add_route('*', item.route, item.resource)

return rv
3 changes: 0 additions & 3 deletions xsnippet/api/resources/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

from .misc import cerberus_errors_to_str, try_int
from .. import exceptions, resource, services
from ..application import endpoint


class InvalidId(Exception):
Expand Down Expand Up @@ -86,7 +85,6 @@ async def _read(resource, service_fn, *, status):
return resource.make_response(read, status=status)


@endpoint('/snippets/{id}', '1.0')
class Snippet(resource.Resource):

def checkpermissions(fn):
Expand Down Expand Up @@ -132,7 +130,6 @@ async def service_fn(snippet):
return await _write(self, service_fn, status=200)


@endpoint('/snippets', '1.0')
class Snippets(resource.Resource):

async def get(self):
Expand Down
2 changes: 0 additions & 2 deletions xsnippet/api/resources/syntaxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@
"""

from .. import resource
from ..application import endpoint


@endpoint('/syntaxes', '1.0')
class Syntaxes(resource.Resource):

async def get(self):
Expand Down

0 comments on commit 33b5178

Please sign in to comment.