Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make content argument required to JSONResponse #1431

Merged
merged 17 commits into from Jan 26, 2022
Merged

Make content argument required to JSONResponse #1431

merged 17 commits into from Jan 26, 2022

Conversation

aminalaee
Copy link
Member

@aminalaee aminalaee commented Jan 25, 2022

Making content argument required in JSONResponse:

  • Response will work as before defaulting to b"" when content is None
  • JSONResponse() will fail as content is required
  • JSONResponse({}) will work as expected
  • JSONResponse(None) will be rendered as null

sondrelg and others added 2 commits January 25, 2022 11:43
Remove count of available convertors (#1409)

Co-authored-by: Micheal Gendy <micheal@sonono.ch>

Fix md5_hexdigest wrapper on FIPS enabled systems (#1410)

* Fix md5_hexdigest wrapper on FIPS enabled systems

* Update _compat.py

* lint

Use typing `NoReturn` (#1412)

change github issues template

Sort third-party packages and add `starlette-wtf` (#1415)

Improvements on authentication documentation (#1420)

* Use `conn` in `AuthenticationBackend` documentation

* Remove unused import in `AuthenticationBackend` documentation

* Add missing imports in authentication documentation

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>

Add third-party CSRF middlewares (#1414)

* change github issues template

* Add third-party CSRF middlewares

Co-authored-by: Tom Christie <tom@tomchristie.com>

Allow Environment options in `Jinja2Templates` (#1401)

Adjust type of `exception_handlers` to allow async callable (#1423)

Default WebSocket accept message headers to an empty list (#1422)

* If no extra headers are passed, set it to an empty list

* Test websocket.accept() with no additional headers

* Update starlette/websockets.py

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>

* Update tests/test_websockets.py

Co-authored-by: Amin Alaee <mohammadamin.alaee@gmail.com>

* Update tests/test_websockets.py

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
Co-authored-by: Amin Alaee <mohammadamin.alaee@gmail.com>

Add reason to WebSocket closure (#1417)

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>

Version 0.18.0 (#1380)

* Version 0.18.0

* Add changes until 14 jan

* Update release-notes.md

* Update release-notes.md

* Update release-notes.md

* Update release-notes.md

Co-authored-by: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>
Co-authored-by: Amin Alaee <mohammadamin.alaee@gmail.com>

draft

Update publish.yml (#1430)
@tomchristie
Copy link
Member

Okay - neat starting point.

We'll need to expand on the actual motivation here, and the desired behavioural changes, but lemme first jump in with some review points.

starlette/responses.py Outdated Show resolved Hide resolved
Copy link
Member

@tomchristie tomchristie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so my expectations around the changes we'd want to see are:

  • The status code becomes "defaults to either 200 or 204" rather than "defaults to 200".
  • Omitting the content or passing content=None defaults to "don't render anything, body is b''" rather than "render None and return that as the body".

We've probably also got a follow up tweak that we'd want to not set any content-type in that case, but let's take this step by step.

starlette/responses.py Outdated Show resolved Hide resolved
starlette/responses.py Outdated Show resolved Hide resolved
starlette/responses.py Outdated Show resolved Hide resolved
starlette/responses.py Outdated Show resolved Hide resolved
tests/test_responses.py Outdated Show resolved Hide resolved
tests/test_responses.py Outdated Show resolved Hide resolved
tests/test_responses.py Outdated Show resolved Hide resolved
@tomchristie
Copy link
Member

Okay, see whatcya think about that.

@Kludex
Copy link
Sponsor Member

Kludex commented Jan 25, 2022

The status code becomes "defaults to either 200 or 204" rather than "defaults to 200".

What about 307?

@tomchristie
Copy link
Member

What about 307?

RedirectResponse continues to use 307 as the default in it's __init__ signature, and life is happy and good.

@aminalaee
Copy link
Member Author

aminalaee commented Jan 25, 2022

@Kludex I think the RedirectResponse passes the status_code=307 to Response so it's overriden.

aminalaee and others added 6 commits January 25, 2022 12:46
Co-authored-by: Tom Christie <tom@tomchristie.com>
Co-authored-by: Tom Christie <tom@tomchristie.com>
Co-authored-by: Tom Christie <tom@tomchristie.com>
Co-authored-by: Tom Christie <tom@tomchristie.com>
Co-authored-by: Tom Christie <tom@tomchristie.com>
@aminalaee
Copy link
Member Author

This makes sense now. Thank you for the feedback. I'll take a look at the tests later today.

tests/test_responses.py Outdated Show resolved Hide resolved
@t1waz
Copy link

t1waz commented Jan 25, 2022

hi guys, maybe You should consider my point of view:
I think 200 status code is better as default than 204. 204 is something more just than No Content:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204

from my expierence 204 should also be used in cases when request was process successfully on some entity. It's inform that it was process and do not need to reload or something (look link above)

200 is more general, more intuitive, for empty responses it's like standard. It is also good when default status code will remain same, not to create confusion for someone new :).

I think it's good idea to stay with is there is not content body should be b''.

Let me now, what You guys think

@Kludex
Copy link
Sponsor Member

Kludex commented Jan 25, 2022

@aminalaee a humbly remind to add the motivation of this PR on the description 🙏

@aminalaee aminalaee changed the title Modify response class and status code Changing Response default status_code to 200 or 204 depending on content Jan 25, 2022
@aminalaee aminalaee changed the title Changing Response default status_code to 200 or 204 depending on content Change Response default status_code to 200 or 204 depending on content Jan 25, 2022
@Kludex
Copy link
Sponsor Member

Kludex commented Jan 25, 2022

Flask's Response class defaults to 200, jfyk:

ref.: https://github.com/pallets/werkzeug/blob/b611af2f5bf5f447d1d535b45f7c19309b0dc48d/src/werkzeug/sansio/response.py#L92

@tomchristie
Copy link
Member

Hrm. I'm just not sure here. We're actually bundling up two different but related concerns...

  1. If content=None do we still want to call render() or do we just b"" it?
  2. For empty content do we want to default to 204.

It's possible we should consider those separately.

I'm maybe not that fussed about (2) - it probably ends up being slightly unexpected for some users.

However (1) probably? sounds like a good idea. Practically the behavioural change it makes within Starlette itself is only for the JSONResponse() and JSONResponse(None) cases, where we'll render b"" instead of null. Which... I think is probably better. Returning null is just. Well.. let's not help folks to do that.

Having said that, we'd also want to adapt init_headers to not include a content type header on those cases. Because we're not including any content. So "JSONResponse()" is a bit of a big ol' fib, if it doesn't actually have any content.

Forgetting about (2) for now, I think options are...

  • Leave things as they are. JSONResponse() can render null. S'all good. Move along folks.
  • Don't render anything when content=None. return JSONResponse() is actually the same as return Response().
  • Make the content argument mandatory on JSONResponse(...). (Optional: disallow None)

After reading that through, I think the last one is a pretty neat plan.

Eg...

  • Response() - An empty response - no content type.
  • JSONResponse() - Raises an error - missing mandatory argument.
  • JSONResponse(...) - Exactly what you'd expect.
  • JSONResponse(None) - Little bit of a silly thing to do, but renders null.

I quite like that approach overall. Doesn't allow me to do things that's ambiguous. Has the behaviour I'd expect in all other cases.

It's a breaking change, but it's only a breaking change for users doing something a bit wrong and marginally broken.

We'd describe it to users in this way...

"If you're currently returning JSONResponse() you now need to either return Response() (which is an empty response), or JSONResponse(None) (which is a JSON response, rendering null as the content)"

@aminalaee aminalaee changed the title Change Response default status_code to 200 or 204 depending on content Make content argument required to JSONResponse Jan 26, 2022
@tomchristie
Copy link
Member

This seems better to me, right?

Also - I don't think we really need to deal with auto-defaulting 204 for Response() - let's just leave it up to the user. It might very often not be what they want.

This change on it's own is actually a neat enough bit of guard-railing.

Copy link
Member

@tomchristie tomchristie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes a lot of sense to me, yup.

@aminalaee aminalaee merged commit 5a5a5c3 into encode:master Jan 26, 2022
@aminalaee aminalaee deleted the modify-response-class-and-status-code branch January 26, 2022 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants