Created
May 23, 2018 07:37
-
-
Save asyncee/afff12559e364b0665c89b0e53341c28 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import inspect | |
from nameko.extensions import ENTRYPOINT_EXTENSIONS_ATTR | |
from nameko.web.handlers import HttpRequestHandler | |
from werkzeug.routing import Map, Rule | |
class ResolveUrlError(Exception): | |
pass | |
class Router: | |
def __init__(self, service_cls, host=None): | |
self.service_cls = service_cls | |
self.host = host | |
routes = self.get_routes() | |
self.map = self.url_map(routes) | |
def get_routes(self): | |
routes = [] | |
for method_name, method in inspect.getmembers(self.service_cls, inspect.isfunction): | |
entrypoints = getattr(method, ENTRYPOINT_EXTENSIONS_ATTR, []) | |
entrypoint_routes = [ | |
(entrypoint.url, method_name, entrypoint.method.split(',')) for entrypoint in entrypoints | |
if isinstance(entrypoint, HttpRequestHandler) | |
] | |
routes.extend(entrypoint_routes) | |
return routes | |
def url_map(self, routes): | |
rules = [Rule(path, endpoint=endpoint, methods=methods) for path, endpoint, methods in routes] | |
return Map(rules) | |
def resolve(self, endpoint, host: str = None, **values): | |
host = self.host or host | |
if host.startswith('http'): | |
scheme, host = host.split('://') | |
else: | |
scheme = 'http' | |
adapter = self.map.bind(server_name=host, url_scheme=scheme) | |
try: | |
return adapter.build(endpoint, values=values, force_external=True) | |
except Exception as e: | |
raise ResolveUrlError(f'Can not resolve url: {endpoint}') from e | |
# Dependency example | |
class RouterDependency(DependencyProvider): | |
def get_dependency(self, worker_ctx): | |
config = self.container.config.copy() | |
return http.Router(self.container.service_cls, host=config['HOST']) | |
# Usage example | |
class Service: | |
name = 'service' | |
router = RouterDependency() | |
@http('GET', '/a/b/<c>') | |
def meth(self, request): | |
pass | |
def another_method(self): | |
url = self.router.resolve('meth', c=123) | |
url = self.router.resolve('meth', host='http://example.com', c=123) # Override host | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment