Sanic: How to response 204 using response.json()

Created on 28 Jan 2018  路  9Comments  路  Source: sanic-org/sanic

Usually the DELETE request should return a 204 response. How can I send 204 response using sanic. I was trying something like below.

return response.json(
        None,
        status=204
    )

But it doesn't work, it response with null.

bug

All 9 comments

That looks right to me. Can you post the raw response. Are you sure you are not getting the right status code? I do something similar, albeit with response.text

text('', status=204)

Works just fine.

If I use response.text() it's working fine. Why can't get the same response using response .json()?

The following response with 204 but with "" string in the response body. For 204 response, content-length should be 0.

return response.json(
       '',
        status=204
    )

Try this:

return response.json(None, status=204)

As I mentioned in my first comment. the following doesn't work.

return response.json(None, status=204)

It return a response with 204 but with null in the response body

@alaminopu are you using a delete route? With the below example, I do get a 0 length response:

from sanic import Sanic
from sanic.response import json

app = Sanic()

@app.delete("/")
async def test(request):
    return json(None, status=204)

if __name__ == "__main__":
    app.run(host="localhost", port=8010)
$ curl -s -XDELETE localhost:8010 | wc -l
0

However, the Content-Length header is incorrect.

 curl -v -XDELETE localhost:8010
* Rebuilt URL to: localhost:8010/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8010 (#0)
> DELETE / HTTP/1.1
> Host: localhost:8010
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 204 No Content
< Connection: keep-alive
< Keep-Alive: 5
< Content-Length: 4
< Content-Type: application/json
< 
* Excess found in a non pipelined read: excess = 4 url = / (zero-length body)
* Connection #0 to host localhost left intact

@alaminopu @ahopkins @r0fls This is happening because the json_dumps functions try to deserialize None which returns 'null' as a string, making this a response length of 4 even tho the HTTP code is 204 with no content, as I can see (maybe I'm incorrect) Sanic indeed returns 'null'.
So, technically returning None is correct as returns null, when you use the 204 code then tecnically there's no body (you can read this RFC for HTTP/1.1) this means the according to the specification:

The 204 response MUST NOT include a message-body, and thus is always
terminated by the first empty line after the header fields.

Therefore the Header is proper, but the body is cut off.

I would propose to have a None response to have '' (empty string) as no content, instead of 'null' making the header Content-Length: 0 (for all response codes using the json response method)

What you think?

I have created a PR with the proposal above, please let me know about your thoughts :)

Edit

I was thinking, maybe we want to change the behavior of the response when being a 204 status.
For now, in the PR I only affect the json method. Maybe we want to remove always the body from a 204 response.

Edit (02.02.18)

The PR will affect all responses having the HTTP status 204

@r0fls It is NOT a bug. The status code 204 shows 'no content'. It means we check status code first and ignore check it's content.
@alaminopu @abhishek7 @arnulfojr json.dumps(None) and json.dumps('') isn't normal usage. Consider this explicit statement json.dumps({}). we can check it in python3 cli.

@h-wei the fact that the content-length and the actual body length differ is a bug. Please see RFC 2616:

When a Content-Length is given in a message where a message-body is allowed, its field value MUST exactly match the number of OCTETs in the message-body.

closing per #1113

Was this page helpful?
0 / 5 - 0 ratings

Related issues

davidtgq picture davidtgq  路  3Comments

ZeeRoc picture ZeeRoc  路  3Comments

olalonde picture olalonde  路  3Comments

woutor picture woutor  路  3Comments

geekpy picture geekpy  路  4Comments