{"action":"opened","issue":{"url":"https://api.github.com/repos/twisted/klein/issues/73","labels_url":"https://api.github.com/repos/twisted/klein/issues/73/labels{/name}","comments_url":"https://api.github.com/repos/twisted/klein/issues/73/comments","events_url":"https://api.github.com/repos/twisted/klein/issues/73/events","html_url":"https://github.com/twisted/klein/issues/73","id":68012365,"number":73,"title":"A way to structure klein apps into (reusable) modules","user":{"login":"tehasdf","id":790215,"avatar_url":"https://avatars.githubusercontent.com/u/790215?v=3","gravatar_id":"","url":"https://api.github.com/users/tehasdf","html_url":"https://github.com/tehasdf","followers_url":"https://api.github.com/users/tehasdf/followers","following_url":"https://api.github.com/users/tehasdf/following{/other_user}","gists_url":"https://api.github.com/users/tehasdf/gists{/gist_id}","starred_url":"https://api.github.com/users/tehasdf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tehasdf/subscriptions","organizations_url":"https://api.github.com/users/tehasdf/orgs","repos_url":"https://api.github.com/users/tehasdf/repos","events_url":"https://api.github.com/users/tehasdf/events{/privacy}","received_events_url":"https://api.github.com/users/tehasdf/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-04-13T05:39:07Z","updated_at":"2015-04-13T05:39:07Z","closed_at":null,"body":"**nb. the pattern I'm showing here is basically flask's blueprints**\r\n\r\nIt seems that currently Klein doesn't have any builtin way to help factoring out view functions to separate modules.\r\n\r\nFor example, if you had the following app:\r\n```python\r\napp = Klein()\r\n\r\n@app.route('/users')\r\ndef list_all_users(request):\r\n    return 'all users'\r\n```\r\nthen you could divide it into two modules like this:\r\n```python\r\n# main.py\r\napp = Klein()\r\n```\r\n```python\r\n# users.py - version 1\r\nfrom main import app\r\n\r\n@app.route('/users')\r\n# ...\r\n```\r\nThis is bad because it leads to several problems, the most immediate being circular import issues, but also this is only a separate module technically, not logically: you can't really re-use that module with another app, or test it in isolation. An easy way to help that would be to use dependency injection:\r\n```python\r\n# main.py\r\nfrom users import add_users_routes\r\n\r\napp = Klein()\r\nadd_users_routes(app)\r\n```\r\n```python\r\n# users.py - version 2\r\n\r\ndef list_all_users(request): \r\n    return 'all_users'\r\n\r\ndef add_users_routes(app):\r\n    app.route('/users')(list_all_users)\r\n```\r\nNow `users` is a separate logical module, but it's a bit awkward, with the central `add_users_routes` function. We could use Klein's `.resource()` to help that:\r\n```python\r\n# users.py - version 3\r\nusers = Klein()\r\n\r\n@users.route('/')\r\ndef list_all_users(request):\r\n    return 'all users'\r\n\r\ndef add_users_routes(app):\r\n    @app.route('/users', branch=True)\r\n    def branch_to_users(request):\r\n        return users.resource()\r\n```\r\nThis is already pretty nice, could maybe use some helpers so that you wouldn't need to implement that branch function, but is reusable and possible to test in isolation. The problem however is, routing to a Klein resource returns control to twisted.web, which then calls `.render()` on the nested resource, which causes a werkzeug map bind, etc - it's a performance hit. A simple hello-world-grade benchmark shown that a root Klein can serve ~2200 requests per second, routing one branch deep: ~1700, two branches deep: ~1400 (experience with flask's blueprints shows that 2 levels of nesting are enough in practice)\r\n\r\nI'm aware Klein is a web framework, and web applications aren't typically constrained by strict real-time requirements, and they're often easy to scale, but I think Klein needs some guideline on structuring applications, and while we're at it, might as well make it fast :)\r\n\r\nBasically I think we want the syntax of `users.py` version 2, with the performance of version 3. Here's how flask does it (translated to Klein):\r\n```python\r\n# main.py\r\nfrom users import users_blueprint\r\napp = Klein()\r\nusers_blueprint.register(app, url_prefix='/users')\r\n```\r\n```python\r\n# users.py\r\nusers_blueprint = Blueprint()\r\n\r\n@users_blueprint.route('/')\r\n# ...\r\n```\r\nThe Blueprint is simply a container that records all `@route()` calls it was used for, and does them on the app when `.register` is called. This makes it only a setup-time thing, with no runtime (performance) effects.\r\n\r\nI've put together a proof-of-concept implementation for reference, see https://github.com/tehasdf/klein/tree/blueprints"}}