Repository: sanic-org/sanic

Issue:
when HTTPRequestHandler returns empty(like: {}, []), request_exception run first than costom-response-middleware
when HTTPRequestHandler returns empty(like: {}, []), request_exception run first than costom-response-middleware


**Code snippet**
            # No middleware results
            if not response:
                # -------------------------------------------- #
                # Execute Handler
                # -------------------------------------------- #

                if handler is None:
                    raise ServerError(
                        (
                            "'None' was returned while requesting a "
                            "handler from the router"
                        )
                    )

                # Run response handler
                response = handler(request, **kwargs)
                if isawaitable(response):
                    response = await response

            if response:
                response = await request.respond(response)
            elif not hasattr(handler, "is_websocket"):
                response = request.stream.response  # type: ignore

            # Make sure that response is finished / run StreamingHTTP callback
            if isinstance(response, BaseHTTPResponse):
                await response.send(end_stream=True)
            else:
                if not hasattr(handler, "is_websocket"):
                    raise ServerError(
                        f"Invalid response type {response!r} "
                        "(need HTTPResponse)"
                    )

        except CancelledError:
            raise
        except Exception as e:
            # Response Generation Failed
            await self.handle_exception(request, e)




Discussion:
<img width="918" alt="image" src="https://user-images.githubusercontent.com/55998415/131430745-6ce06f84-9abc-42fc-9b97-bb504af5fce3.png">

sanic==21.6.2
sanic-routing==0.7.1

I don't need Sanic code posted to understand your question, I need your code. Please post a snippet of your handler and what it's returning. Is it not returning an instance of HTTPResponse?

It is not clear if you are returning 

```python 
return empty()
```

or

```
return {}
```
api method handle‘s code：

```python
class BUGHandleApi(HTTPMethodView):

    async def get(self, request):
        logger.debug(f"debug BUGHandleApi called-in..")

        return {}
```

middleware’s code，just like this

```python
async def debug_response_middleware(request, response):
    # ...
    if not isinstance(response, HTTPResponse):
        body = {
            "resultcode": StatusCode.SUCCESS.humanize_code(),
            "msg": "",
            "data": response,
        }
        response = HTTPResponse(json_dumps(body),
                                headers=None,
                                content_type="application/json; charset=utf-8",
                                status=200,)
        return response
```



why sanic==21.6.2 use "if response:" to do it --- request.respond(response)

Agreed, one should be able to use middleware to process such responses into Sanic responses. The first `if response` check marked in red could instead check if there already is a response on the request, and only use the return value if there wasn't. Probably needs some other work too.

Also, I think this used to work, or worked at least for non-empty plain dicts returned from handlers that a middleware could turn into JSON responses.

It should work for truthy values since I think the check is: `if response`. We could probably change that to a `if response is not None`. It is a one line change.
@iduosi Would you be willing to add a PR for this? We can get it into the next release for sure.

Change that one line to `if response is not None` and then add simple unit test using your example?
Just confirmed with that change both this example works and the unit tests pass.

```python
@app.on_response
def display(_, response):
    response["foo"] = "bar"
    return json(response)


@app.get("/")
async def handler(request):
    return {}
```

Resolving patch:
diff --git a/sanic/app.py b/sanic/app.py
--- a/sanic/app.py
+++ b/sanic/app.py
@@ -839,7 +839,7 @@ async def handle_request(self, request: Request):  # no cov
                 if isawaitable(response):
                     response = await response
 
-            if response:
+            if response is not None:
                 response = await request.respond(response)
             elif not hasattr(handler, "is_websocket"):
                 response = request.stream.response  # type: ignore


Test patch:
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
--- a/tests/test_middleware.py
+++ b/tests/test_middleware.py
@@ -5,7 +5,7 @@
 
 from sanic.exceptions import NotFound
 from sanic.request import Request
-from sanic.response import HTTPResponse, text
+from sanic.response import HTTPResponse, json, text
 
 
 # ------------------------------------------------------------ #
@@ -283,3 +283,17 @@ async def handler(request):
 
     request, response = app.test_client.get("/")
     assert next(i) == 3
+
+
+def test_middleware_added_response(app):
+    @app.on_response
+    def display(_, response):
+        response["foo"] = "bar"
+        return json(response)
+
+    @app.get("/")
+    async def handler(request):
+        return {}
+
+    _, response = app.test_client.get("/")
+    assert response.json["foo"] == "bar"