Blueprint support, with docs, example, and tests
This commit is contained in:
parent
993d81090c
commit
17cc2928d0
56
docs/blueprints.md
Normal file
56
docs/blueprints.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Blueprints
|
||||
|
||||
Blueprints are objects that can be used for sub-routing within an application.
|
||||
Instead of adding routes to the application object, blueprints define similar
|
||||
methods for adding routes, which are then registered with the application in a
|
||||
flexible and plugable manner.
|
||||
|
||||
## Why?
|
||||
|
||||
Blueprints are especially useful for larger applications, where your application
|
||||
logic can be broken down into several groups or areas of responsibility.
|
||||
|
||||
It is also useful for API versioning, where one blueprint may point at
|
||||
`/v1/<routes>`, and another pointing at `/v2/<routes>`.
|
||||
|
||||
|
||||
## My First Blueprint
|
||||
|
||||
The following shows a very simple blueprint that registers a handler-function at
|
||||
the root `/` of your application.
|
||||
|
||||
Suppose you save this file as `my_blueprint.py`, this can be imported in your
|
||||
main application later.
|
||||
|
||||
```python
|
||||
from sanic.response import json
|
||||
from sanic import Blueprint
|
||||
|
||||
bp = Blueprint('my_blueprint')
|
||||
|
||||
@bp.route('/')
|
||||
async def bp_root():
|
||||
return json({'my': 'blueprint'})
|
||||
|
||||
```
|
||||
|
||||
## Registering Blueprints
|
||||
Blueprints must be registered with the application.
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from my_blueprint import bp
|
||||
|
||||
app = Sanic(__name__)
|
||||
app.register_blueprint(bp)
|
||||
|
||||
app.run(host='0.0.0.0', port=8000, debug=True)
|
||||
```
|
||||
|
||||
This will add the blueprint to the application and register any routes defined
|
||||
by that blueprint.
|
||||
In this example, the registered routes in the `app.router` will look like:
|
||||
|
||||
```python
|
||||
[Route(handler=<function bp_root at 0x7f908382f9d8>, methods=None, pattern=re.compile('^/$'), parameters=[])]
|
||||
```
|
24
examples/blueprints.py
Normal file
24
examples/blueprints.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from sanic import Sanic
|
||||
from sanic import Blueprint
|
||||
from sanic.response import json, text
|
||||
|
||||
|
||||
app = Sanic(__name__)
|
||||
blueprint = Blueprint('name', url_prefix='/my_blueprint')
|
||||
blueprint2 = Blueprint('name2', url_prefix='/my_blueprint2')
|
||||
|
||||
|
||||
@blueprint.route('/foo')
|
||||
async def foo(request):
|
||||
return json({'msg': 'hi from blueprint'})
|
||||
|
||||
|
||||
@blueprint2.route('/foo')
|
||||
async def foo2(request):
|
||||
return json({'msg': 'hi from blueprint2'})
|
||||
|
||||
|
||||
app.register_blueprint(blueprint)
|
||||
app.register_blueprint(blueprint2)
|
||||
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
|
@ -1 +1,2 @@
|
|||
from .sanic import Sanic
|
||||
from .blueprints import Blueprint
|
||||
|
|
24
sanic/blueprints.py
Normal file
24
sanic/blueprints.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from sanic import Sanic
|
||||
from sanic import Blueprint
|
||||
from sanic.response import json, text
|
||||
|
||||
|
||||
app = Sanic(__name__)
|
||||
blueprint = Blueprint('name', url_prefix='/my_blueprint')
|
||||
blueprint2 = Blueprint('name2', url_prefix='/my_blueprint2')
|
||||
|
||||
|
||||
@blueprint.route('/foo')
|
||||
async def foo(request):
|
||||
return json({'msg': 'hi from blueprint'})
|
||||
|
||||
|
||||
@blueprint2.route('/foo')
|
||||
async def foo2(request):
|
||||
return json({'msg': 'hi from blueprint2'})
|
||||
|
||||
|
||||
app.register_blueprint(blueprint)
|
||||
app.register_blueprint(blueprint2)
|
||||
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
|
@ -22,6 +22,8 @@ class Sanic:
|
|||
self.config = Config()
|
||||
self.request_middleware = []
|
||||
self.response_middleware = []
|
||||
self.blueprints = {}
|
||||
self._blueprint_order = []
|
||||
|
||||
# -------------------------------------------------------------------- #
|
||||
# Registration
|
||||
|
@ -86,6 +88,24 @@ class Sanic:
|
|||
|
||||
return middleware
|
||||
|
||||
def register_blueprint(self, blueprint, **options):
|
||||
"""
|
||||
Registers a blueprint on the application.
|
||||
:param blueprint: Blueprint object
|
||||
:param options: option dictionary with blueprint defaults
|
||||
:return: Nothing
|
||||
"""
|
||||
if blueprint.name in self.blueprints:
|
||||
assert self.blueprints[blueprint.name] is blueprint, \
|
||||
'A blueprint\'s name collision occurred between %r and ' \
|
||||
'%r. Both share the same name "%s". ' % \
|
||||
(blueprint, self.blueprints[blueprint.name], blueprint.name)
|
||||
else:
|
||||
self.blueprints[blueprint.name] = blueprint
|
||||
self._blueprint_order.append(blueprint)
|
||||
blueprint.register(self, options)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------- #
|
||||
# Request Handling
|
||||
# -------------------------------------------------------------------- #
|
||||
|
|
60
tests/test_blueprints.py
Normal file
60
tests/test_blueprints.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
from json import loads as json_loads, dumps as json_dumps
|
||||
from sanic import Sanic
|
||||
from sanic import Blueprint
|
||||
from sanic.response import json, text
|
||||
from sanic.utils import sanic_endpoint_test
|
||||
from sanic.exceptions import SanicException
|
||||
|
||||
|
||||
# ------------------------------------------------------------ #
|
||||
# GET
|
||||
# ------------------------------------------------------------ #
|
||||
|
||||
def test_bp():
|
||||
app = Sanic('test_text')
|
||||
bp = Blueprint('test_text')
|
||||
|
||||
@bp.route('/')
|
||||
def handler(request):
|
||||
return text('Hello')
|
||||
|
||||
app.register_blueprint(bp)
|
||||
request, response = sanic_endpoint_test(app)
|
||||
|
||||
assert response.text == 'Hello'
|
||||
|
||||
def test_bp_with_url_prefix():
|
||||
app = Sanic('test_text')
|
||||
bp = Blueprint('test_text', url_prefix='/test1')
|
||||
|
||||
@bp.route('/')
|
||||
def handler(request):
|
||||
return text('Hello')
|
||||
|
||||
app.register_blueprint(bp)
|
||||
request, response = sanic_endpoint_test(app, uri='/test1/')
|
||||
|
||||
assert response.text == 'Hello'
|
||||
|
||||
|
||||
def test_several_bp_with_url_prefix():
|
||||
app = Sanic('test_text')
|
||||
bp = Blueprint('test_text', url_prefix='/test1')
|
||||
bp2 = Blueprint('test_text2', url_prefix='/test2')
|
||||
|
||||
@bp.route('/')
|
||||
def handler(request):
|
||||
return text('Hello')
|
||||
|
||||
@bp2.route('/')
|
||||
def handler2(request):
|
||||
return text('Hello2')
|
||||
|
||||
app.register_blueprint(bp)
|
||||
app.register_blueprint(bp2)
|
||||
request, response = sanic_endpoint_test(app, uri='/test1/')
|
||||
assert response.text == 'Hello'
|
||||
|
||||
request, response = sanic_endpoint_test(app, uri='/test2/')
|
||||
assert response.text == 'Hello2'
|
||||
|
Loading…
Reference in New Issue
Block a user