diff --git a/docs/sanic/request_data.md b/docs/sanic/request_data.md index a91dd970..01a182a3 100644 --- a/docs/sanic/request_data.md +++ b/docs/sanic/request_data.md @@ -126,3 +126,40 @@ args.get('titles') # => 'Post 1' args.getlist('titles') # => ['Post 1', 'Post 2'] ``` + +## Accessing the handler name with the request.endpoint attribute + +The `request.endpoint` attribute holds the handler's name. For instance, the below +route will return "hello". + +```python +from sanic.response import text +from sanic import Sanic + +app = Sanic() + +@app.get("/") +def hello(request): + return text(request.endpoint) +``` + +Or, with a blueprint it will be include both, separated by a period. For example, + the below route would return foo.bar: + +```python +from sanic import Sanic +from sanic import Blueprint +from sanic.response import text + + +app = Sanic(__name__) +blueprint = Blueprint('foo') + +@blueprint.get('/') +async def bar(request): + return text(request.endpoint) + +app.blueprint(blueprint) + +app.run(host="0.0.0.0", port=8000, debug=True) +``` diff --git a/sanic/app.py b/sanic/app.py index e4e142ca..6673dd4c 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -454,6 +454,13 @@ class Sanic: def response(handler): async def websocket_handler(request, *args, **kwargs): request.app = self + if not getattr(handler, "__blueprintname__", False): + request.endpoint = handler.__name__ + else: + request.endpoint = ( + getattr(handler, "__blueprintname__", "") + + handler.__name__ + ) try: protocol = request.transport.get_protocol() except AttributeError: @@ -888,6 +895,16 @@ class Sanic: "handler from the router" ) ) + else: + if not getattr(handler, "__blueprintname__", False): + request.endpoint = self._build_endpoint_name( + handler.__name__ + ) + else: + request.endpoint = self._build_endpoint_name( + getattr(handler, "__blueprintname__", ""), + handler.__name__, + ) # Run response handler response = handler(request, *args, **kwargs) @@ -1276,3 +1293,7 @@ class Sanic: logger.info("Goin' Fast @ {}://{}:{}".format(proto, host, port)) return server_settings + + def _build_endpoint_name(self, *parts): + parts = [self.name, *parts] + return ".".join(parts) diff --git a/sanic/request.py b/sanic/request.py index 42237d32..e0dd7173 100644 --- a/sanic/request.py +++ b/sanic/request.py @@ -69,26 +69,27 @@ class Request(dict): """Properties of an HTTP request such as URL, headers, etc.""" __slots__ = ( - "app", - "headers", - "version", - "method", + "__weakref__", "_cookies", - "transport", - "body", - "parsed_json", - "parsed_args", - "parsed_form", - "parsed_files", "_ip", "_parsed_url", - "uri_template", - "stream", + "_port", "_remote_addr", "_socket", - "_port", - "__weakref__", + "app", + "body", + "endpoint", + "headers", + "method", + "parsed_args", + "parsed_files", + "parsed_form", + "parsed_json", "raw_url", + "stream", + "transport", + "uri_template", + "version", ) def __init__(self, url_bytes, headers, version, method, transport): @@ -111,6 +112,7 @@ class Request(dict): self.uri_template = None self._cookies = None self.stream = None + self.endpoint = None def __repr__(self): if self.method is None or not self.path: diff --git a/tests/test_logo.py b/tests/test_logo.py index c99ee5b6..1deb46f6 100644 --- a/tests/test_logo.py +++ b/tests/test_logo.py @@ -5,6 +5,7 @@ from sanic.config import BASE_LOGO try: import uvloop # noqa + ROW = 0 except BaseException: ROW = 1 diff --git a/tests/test_requests.py b/tests/test_requests.py index 09b82685..08c33b24 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -7,6 +7,8 @@ from urllib.parse import urlparse import pytest +from sanic import Sanic +from sanic import Blueprint from sanic.exceptions import ServerError from sanic.request import DEFAULT_HTTP_CONTENT_TYPE from sanic.response import json, text @@ -698,3 +700,42 @@ def test_request_form_invalid_content_type(app): request, response = app.test_client.post("/", json={"test": "OK"}) assert request.form == {} + + +def test_endpoint_basic(): + app = Sanic() + + @app.route("/") + def my_unique_handler(request): + return text("Hello") + + request, response = app.test_client.get("/") + + assert request.endpoint == "test_requests.my_unique_handler" + + +def test_endpoint_named_app(): + app = Sanic("named") + + @app.route("/") + def my_unique_handler(request): + return text("Hello") + + request, response = app.test_client.get("/") + + assert request.endpoint == "named.my_unique_handler" + + +def test_endpoint_blueprint(): + bp = Blueprint("my_blueprint", url_prefix="/bp") + + @bp.route("/") + async def bp_root(request): + return text("Hello") + + app = Sanic("named") + app.blueprint(bp) + + request, response = app.test_client.get("/bp") + + assert request.endpoint == "named.my_blueprint.bp_root"