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

fix(common): serialize string to JSON if explicitly set in Content-Type #31974

Closed
wants to merge 1 commit into from

Conversation

dasois
Copy link

@dasois dasois commented Aug 2, 2019

RFC 8259 and ECMA-404 define that a simple string is valid JSON.
If Content-Type has been explicitly set to 'application/json' the HttpClient should
assume that it needs to be serialized.

Closes #31973

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • [ x ] Bugfix

What is the current behavior?

Issue Number: #31973

What is the new behavior?

If Content-Type is set to 'application/json' the body will also be serialized, if it is typeof string already.

Does this PR introduce a breaking change?

  • [ x ] Yes

Existing POST requests, that have a pure string payload, are serializing the body before calling http.post at the moment. This change would cause them to be serialized a second time, which would break the consistency of their POST-request.

@dasois dasois requested a review from a team as a code owner August 2, 2019 21:33
@dasois dasois force-pushed the fix_request-json-stringify branch 2 times, most recently from d78190c to 3845eb5 Compare August 2, 2019 22:20
@Airblader
Copy link
Contributor

Isn't this a breaking change?

In our project we have a setup of automatically generated bindings to the backend. This includes serializing the payload (there's some custom stuff going on, not just a simple JSON stringify). Since we also set the content type, this would probably break our framework.

@trotyl
Copy link
Contributor

trotyl commented Aug 3, 2019

what if the request body string is already the stringified result? Say that:

this.http.post('/api', JSON.stringify(something));

RFC 8259 and ECMA-404 define that a simple string is valid JSON.
If Content-Type has been explicitly set to 'application/json' the HttpClient should
assume that it needs to be serialized.

Closes  angular#31973
@dasois dasois force-pushed the fix_request-json-stringify branch from 3845eb5 to 318e18c Compare August 3, 2019 08:00
@dasois
Copy link
Author

dasois commented Aug 3, 2019

Isn't this a breaking change?

In our project we have a setup of automatically generated bindings to the backend. This includes serializing the payload (there's some custom stuff going on, not just a simple JSON stringify). Since we also set the content type, this would probably break our framework.

Exactly, this is why it's marked as breaking change.

@dasois
Copy link
Author

dasois commented Aug 3, 2019

what if the request body string is already the stringified result? Say that:

this.http.post('/api', JSON.stringify(something));

http.post should not try to be "smart". If you are used to it stringifying everything (arrays, objects, strings) that you provide as a body parameter, if you set the Content-Type, then you would not stringify the body yourself and it behaves as expected.

@Airblader
Copy link
Contributor

And how should affected users mitigate that breakage? Having to manually parse the string before sending it is hardly an improvement.

@dasois
Copy link
Author

dasois commented Aug 3, 2019

And how should affected users mitigate that breakage? Having to manually parse the string before sending it is hardly an improvement.

Well, your issue is that you want to disable automatic stringify of http.post entirely because you want to do it manually. This stands against the "convenience" of not having to stringify the payload yourself if it is e.g. a object. So one could think about an option to disable that default behaviour for example, do you have an idea?

@Airblader
Copy link
Contributor

I don't have a proposal, and for the record I'm not entirely disagreeing with you*. But it's existing behavior, so if we break it we should make sure that users can fix their existing code (in a sane way), and ideally just fix it for them during the upgrade (if possible). :-)

*) That said, there's nothing "wrong" with not making use of the convenience, passing a stringified object is perfectly fine. So I'm not sure either one of the two scenarios is worth favoring, and in that case I'd let existing behavior win the battle rather than fixing one thing for some users while breaking the opposite scenario for others.

Random thought: a non-breaking solution would be detecting whether the passed string is a stringified object or not. This is a bit ugly, yes, but would preserve compatibility.

@trotyl
Copy link
Contributor

trotyl commented Aug 3, 2019

if you set the Content-Type, then you would not stringify the body yourself and it behaves as expected.

I feel the opposite, if Angular helps you serialize to JSON, then Angular is responsible to add the Content-Type header. And only if you provide a serialization result you should manually set it.

@dasois
Copy link
Author

dasois commented Aug 3, 2019

Random thought: a non-breaking solution would be detecting whether the passed string is a stringified object or not. This is a bit ugly, yes, but would preserve compatibility.

I had that thought already, but I don't like such things to be "intelligent". Maybe it's doable though...
What do you think about the following: https://regex101.com/r/rJuSo4/1

@dasois
Copy link
Author

dasois commented Aug 3, 2019

I feel the opposite, if Angular helps you serialize to JSON, then Angular is responsible to add the Content-Type header. And only if you provide a serialization result you should manually set it.

Angular currently has no way to know if you have already provided a serialized result.

@Airblader
Copy link
Contributor

What I meant is to try and JSON parse it, and if it succeeds check if it's of type object. If yes, then the user provided a serialized result. If it's of type string, they provided a serialized string. If it fails, they provided a plain string (or something invalid).

@dasois
Copy link
Author

dasois commented Aug 3, 2019

What I meant is to try and JSON parse it, and if it succeeds check if it's of type object. If yes, then the user provided a serialized result. If it's of type string, they provided a serialized string. If it fails, they provided a plain string (or something invalid).

What about arrays, null, true, false?
Also parsing can be unnecessarily expensive for large json, if you can just determine this by the first few chars.

@trotyl
Copy link
Contributor

trotyl commented Aug 3, 2019

Angular currently has no way to know if you have already provided a serialized result.

Yep, and that's why enforced serialization not valid.

@dasois
Copy link
Author

dasois commented Aug 3, 2019

Closing and providing a new PR with a non-breaking way of dealing with this.

@dasois dasois closed this Aug 3, 2019
@Airblader
Copy link
Contributor

I would leave both PRs open. I'm just giving my opinion here, the Angular team will have to decide. :-) Appreciate your time in this!

@dasois
Copy link
Author

dasois commented Aug 3, 2019 via email

@dasois
Copy link
Author

dasois commented Aug 3, 2019

I would leave both PRs open. I'm just giving my opinion here, the Angular team will have to decide. :-) Appreciate your time in this!

Thanks for providing your valuable feedback and your use case. I will reference the PRs to each other.

@dasois dasois reopened this Aug 3, 2019
dasois added a commit to dasois/angular that referenced this pull request Aug 3, 2019
… not already serialized

RFC 8259 and ECMA-404 define a simple string, boolean and null as valid JSON.
If Content-Type has been explicitly set to 'application/json' the HttpClient should
determine, if the body has already been serialized and if not, serialize it.

Not breaking.
Relates to angular#31973, angular#31974
@ngbot ngbot bot added this to the needsTriage milestone Aug 8, 2019
@jessicajaniuk
Copy link
Contributor

jessicajaniuk commented Oct 27, 2021

This would be a hugely breaking change, but it's definitely a valid concern. We're going to close this PR for now, but we're discussing internally a good solution to this problem. There is no ETA at this moment.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 27, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

http.post with string as request body is not serialized to JSON if explicitly set in Content-Type
6 participants