diff --git a/responder/models.py b/responder/models.py index 5d3695c..bbf8a97 100644 --- a/responder/models.py +++ b/responder/models.py @@ -14,7 +14,7 @@ import yaml from requests.structures import CaseInsensitiveDict from requests.cookies import RequestsCookieJar from starlette.datastructures import MutableHeaders -from starlette.requests import Request as StarletteRequest +from starlette.requests import Request as StarletteRequest, State from starlette.responses import ( Response as StarletteResponse, StreamingResponse as StarletteStreamingResponse, @@ -178,6 +178,19 @@ class Request: except AttributeError: return QueryDict({}) + @property + def state(self) -> State: + """ + Use the state to store additional information. + + This can be a very helpful feature, if you want to hand over + information from a middelware or a route decorator to the + actual route handler. + + For example: ``request.state.time_started = time.time()`` + """ + return self._starlette.state + @property async def encoding(self): """The encoding of the Request's body. Can be set, manually. Must be awaited.""" diff --git a/tests/test_responder.py b/tests/test_responder.py index 7ef7c6f..2debc2b 100644 --- a/tests/test_responder.py +++ b/tests/test_responder.py @@ -8,6 +8,7 @@ import requests import string import io +from starlette.middleware.base import BaseHTTPMiddleware from starlette.responses import PlainTextResponse from starlette.testclient import TestClient as StarletteTestClient @@ -886,3 +887,20 @@ def test_empty_req_text(api): r = api.requests.post("/") assert r.text == content + + def test_api_request_state(api, url): + class StateMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request, call_next): + request.state.test1 = 42 + request.state.test2 = "Foo" + + response = await call_next(request) + return response + + api.add_middleware(StateMiddleware) + + @api.route("/") + def home(req, resp): + resp.text = "{}_{}".format(req.state.test2, req.state.test1) + + assert api.requests.get(url("/")).text == "Foo_42"