squeaky-pl / japronto

Screaming-fast Python 3.5+ HTTP toolkit integrated with pipelining HTTP server based on uvloop and picohttpparser.
MIT License
8.61k stars 581 forks source link

Request.Response can only be called once per request #6

Open agalera opened 7 years ago

agalera commented 7 years ago

If an exception is generated in the response this error appears and the request is blocked

from japronto import Application

app = Application()

def hello(request):
    request.Response(json=['invalid', 'json'])

app.router.add_route(url, hello, method='GET')
app.run()
ValueError: View did not return Response instance
Unhandled exception in event loop
Traceback (most recent call last):
  File "uvloop/handles/stream.pyx", line 785, in uvloop.loop.__uv_stream_on_read_impl (uvloop/loop.c:76261)
  File "uvloop/handles/stream.pyx", line 559, in uvloop.loop.UVStream._on_read (uvloop/loop.c:73525)
  File "/root/japronto-env/lib/python3.6/site-packages/japronto/app/__init__.py", line 99, in error_handler
    return self.default_error_handler(request, exception)
  File "/root/japronto-env/lib/python3.6/site-packages/japronto/app/__init__.py", line 81, in default_error_handler
    text=tb if self._debug else 'Internval Server Error')
ilia-khaustov commented 7 years ago
def hello(request):
    return request.Response(json=['invalid', 'json'])
agalera commented 7 years ago

Is voluntary, a valid json is always a dict, here fails to make the conversion to json.

squeaky-pl commented 7 years ago

It's a wart in the API design, I need to refactor this part. What is happening here is that an error is generated in an error handler and since request.Response was already constructed and it's immutable. It fails in a weird way swallowing the real reason.

So this is really about making Response mutable.

squeaky-pl commented 7 years ago

@kianxineki The error doesnt happen because of invalid JSON. Python JSON module will happily transform a list in a JSON array. I don't impose any extra restrictions here. This happens because of missing return.

Anyway this is an error and needs to be fixed.

ilia-khaustov commented 7 years ago

Finally figured out what it is all about.

from japronto import Application

app = Application()

def hello(request):
    try:
        return request.Response(json=object())
    except TypeError:
        return request.Response(code=500)  # RuntimeError due to immutable Response

app.router.add_route('/', hello, method='GET')
app.run()