GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Fix Single Value JSON null in Invoke-RestMethod by markekraus · Pull Request #5338 · PowerShell/PowerShell

Conversation

@markekraus

@markekraus Mark Kraus (markekraus) commented Nov 4, 2017

Copy link
Copy Markdown
Contributor

closes #5320

When an API returns just null, Invoke-RestMethod was serializing this as the string "null" instead of $null. Singe value literals are valid JSON according to rfc7159 section 2:

   A JSON text is a serialized value.  Note that certain previous
   specifications of JSON constrained a JSON text to be an object or an
   array.  Implementations that generate only objects or arrays where a
   JSON text is called for will be interoperable in the sense that all
   implementations will accept these as conforming JSON texts.

Invoke-RestMethod is already properly managing false, true, numbers, string, arrays, and objects.

This PR fixes the logic in Invoke-RestMethod to properly serialize a valid single value JSON null literal as $null.

This is a breaking change in the sense that users who are using Invoke-RestMethod against endpoints that returned single value null likely have logic in place to work around the current broken behavior.This change will break that logic.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@markekraus Mark Kraus (markekraus) added the Breaking-Change breaking change that may affect users label Nov 4, 2017
@markekraus
Mark Kraus (markekraus) requested review from James Truher (JamesWTruher), Paul Higinbotham (PaulHigin) and Dan Travison (dantraMSFT) as code owners November 4, 2017 12:25
@markekraus Mark Kraus (markekraus) mentioned this pull request Nov 4, 2017
Invoke-RestMethod doesn't return useful info when no data is returned. #5320
Closed
@markekraus Mark Kraus (markekraus) changed the title Fix Single Value JSON null in Invoke-WebRequest Fix Single Value JSON null in Invoke-RestMethod Nov 4, 2017
iSazonov
Ilya (iSazonov) reviewed Nov 4, 2017
View reviewed changes
Comment thread ...erShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs Outdated

@iSazonov Ilya (iSazonov) Nov 4, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I wonder why the fix so high level? It seems ConvertFromJson or just PopulateFromJDictionary is right place to fix.
We should think to return System.Management.Automation.Internal.AutomationNull.

Also please review JsonSerializerSettings.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 4, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Ilya (@iSazonov) ConvertFromJson() was already returning null. The problem is that TryConvertToJson() was using null to mean that JSON serialization failed. We want to return null and idealy keep what ever ConvertFromJson() was already returning. But, ConvertFromJson() can return null in situations that don't mean it was JSON null (at least I'm pretty sure it does). In that case we should let Invoke-RestMethod continue with its other serialization tests by returning false. This has to be fixed here because it's a problem with Invoke-RestMethod's logic, not with ConvertFromJson()

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 4, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Hmm i realize this is probably very confusing. The an API endpoint returns the following:

HTTP/1.1 200 OK
Content-Length: 4
Content-Type: application/json
Date: Sat, 04 Nov 2017 18:49:54 GMT

null

that null is the JSON literal for $null. ConvertFromJson() properly returns $null for that, but Invoke-RestMethod was interpreting that $null as failing to serialize the object. TryConvertToJson() was returning false and Invoke-RestMethod would move on to other serialization methods until ultimately falling back to a string and returning the string null.

ConvertFromJson() returns null for empty strings too, however, in this instance, an empty or whitespace string should be returned as an an empty or whitespace string, not null, because an empty or white space string is not valid JSON. I guess it could be argued that maybe that behavior of ConvertFromJson() should be changed and that it should throw on an empty or whitespace string. But, I don't see that going over well.

In any case, because ConvertFromJson() behaves like that I'm double checking it is a true JSON null.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iSazonov Ilya (iSazonov) Nov 5, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

We have the workarround. We can remove it - the bug was fixed in Newton.Json 10.0.3. But I think we can keep JArray.Parse(input); to throw on any error in Json input string.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Ilya (@iSazonov) this has nothing to do with arrays and that code path is not hit in the instace this is addressing. This is about when null is NOT in a JSON array or object, but is solitary, by it self, a single value and the only value in the JSON string. this is literally the JSON string this PR addresses:

null

This has nothing to do with either of these which already work properly:

[
  null
]
{
  "key": null
}

Removing that workaround in ConvertFromJson() will not affect the logic in this PR.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iSazonov Ilya (iSazonov) Nov 5, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

What about JToken.Parse()? I believe it throw on null string.

And I wonder that ConvertFromJson throw if there is out Error parameter - I expect that it return an ErrorRecord.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Are you suggesting to use JToken.Parse() instead of the regex? I guess we could do that. It does throw on empty and whitespace only strings.

ConvertFromJson() does both. It throws and sets the out Error. Invalid JSON throws, trouble serializing JSON into PowerShell objects gives errors.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iSazonov Ilya (iSazonov) Nov 5, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Yes, sorry I walk around :-), I think we should use JToken.Parse() - maybe it'll catch other mistakes we don't know yet.

As for ConvertFromJson() - I guess it is common convention - no throw if there is out Error?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

As for ConvertFromJson() - I guess it is common convention - no throw if there is out Error?

I'm not sure what you are asking.

Here are the kinds of strings it throws on: {, [, [ null null]
Here is a string it errors on: { "": "value"}

Errors arise from valid JSON that cannot serialized into PowerShell objects while exceptions arise from invalid JSON. The only invalid JSON I'm aware of that doesn't throw an exception is String.Empty and a string with just whitespace. An empty string and whitespace-only string are technically not valid JSON.

In any case, when there is an error it returns null. so we can just ensure that the null it is returning is an actual null literal with JToken.Parse() In Invoke-RestMethod. It might be a bit redundant, but I will run it on a null check only. Otherwise, I'd rather trust everything else that comes from ConvertFromJson(). It's just that the existing Invoke-RestMethod logic was assuming null was always a failure, when null is a legitimate single value for JSON.

But, this does bring to light some shortcomings of ConvertFromJson(). I think you are the better person to decide how serious they are. but if we want/need to change that behavior, we need to do it before 6.0.0 as I doubt we can get away with that kind of breaking change until 7.0.0. What do you think?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iSazonov Ilya (iSazonov) Nov 5, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I really don't like the API but we already have no time to discuss and make changes in depth. 😕

I'm sure we'll be with CoreFX implementation in 7.0. 😄 So I would document the API as obsolete or make it internal - the later allow us to migrate on CoreFX implementation in any time before 7.0.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@iSazonov Ilya (iSazonov) self-assigned this Nov 4, 2017
@markekraus

Mark Kraus (markekraus) commented Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

Ilya (@iSazonov) I switched to JToken.Parse() and re did some of the logic to make it cleaner (less false assignments).
I borrowed the the exception handling code for JToken.Parse() from ConvertFfomJson() for consistency, though, I'm not sure that exception ever actually sees the light of day.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

iSazonov
Ilya (iSazonov) reviewed Nov 5, 2017
View reviewed changes
Comment thread ...erShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs Outdated

@iSazonov Ilya (iSazonov) Nov 5, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

After I see the change I'm even more confident that we should make this check in ConvertFromJson - we should remove if ((Regex.Match(input, @"^\s*\[")).Success) and replace JArray.Parse(input); with JToken.Parse(json);. So we'll be closer to JavaScriptSerializer, and we can make it easier to move on one in the future. Also we exclude the same catch on level above.

I review a history of the code and discover that I see ways to clean up and refactor the code. So I agree to merge the PR as is and ready to refactor in days.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Awesome. Just note that just like the change here, making that change ConvertFromJson() will be a breaking change since empty strings and whitespace-only strings will produce errors where as before they returned $null. I think that's appropriate, but the world at large may not. But you are right, we don't have much time. Will you handle the ConvertFromJson() refactor?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iSazonov Ilya (iSazonov) Nov 5, 2017

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I'd refactor the code in any case because it provokes troubles.

As for a breaking change I have the thoughts - should we fix the Issue now or leave the behavior as in Windows PowerShell? Will MSFT fix the Issue in Windows PowerShell too and when? Will MSFT fix the Issue in .Net JavaScriptSerializer and when? Should we request the fix in Newton.Json as we did for JArray?
I think to get sync fixes is better then a breaking change in only PowerShell Core.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 5, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Ilya (@iSazonov) Good questions, but we should track that in a separate issue.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@markekraus

Mark Kraus (markekraus) commented Nov 10, 2017

Copy link
Copy Markdown
Contributor Author

/cc Steve Lee (@SteveL-MSFT) this one should probably be merged before RC unless we plan to break this in 6.1. committee approved breaking change here #5320 (comment)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iSazonov
Ilya (iSazonov) requested review from Steve Lee (SteveL-MSFT) and Travis Plunk (TravisEz13) November 10, 2017 17:58
TravisEz13
Travis Plunk (TravisEz13) approved these changes Nov 10, 2017
View reviewed changes
Comment thread test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 Outdated

@TravisEz13 Travis Plunk (TravisEz13) Nov 10, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Perhaps, add test(s) for the error case where the JSON cannot be parsed?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 10, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Travis Plunk (@TravisEz13) if by "error" you mean empty strings or whitspace-only? I can add the tests, but they will just be ensuring a a String.Empty returns a String.Empty and that a whitespace string returns a whitespace string. When that error condition hits, the cmdlet just goes to the next serialization type (xml) and then when that fails it just returns the string.

It also looks like I would need to either add a WebListener controller to another switch option to HttpListener. Currently none of the available tests can return whitespace only responses. All of them truncate to 0 bytes when the body payload is all whitespace.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@TravisEz13 Travis Plunk (TravisEz13) Nov 10, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

It would be good to have the test to ensure good coverage, but I think this is adequate.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 10, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I've created #5414 to add coverage for that. I have a backlog of test and cleanup activities to do, I'll start on those after RC is underway.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@TravisEz13

Travis Plunk (TravisEz13) commented Nov 10, 2017

Copy link
Copy Markdown
Member

@PowerShell/powershell-maintainers Steve Lee (@SteveL-MSFT) Joey Aiello (@joeyaiello) I recommend we take this for RC.

daxian-dbw reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markekraus Mark Kraus (markekraus) mentioned this pull request Nov 10, 2017
Add String.Empty and whitespace only tests for Web Cmdletes #5414
Closed
@SteveL-MSFT

Steve Lee (SteveL-MSFT) commented Nov 11, 2017

Copy link
Copy Markdown
Member

Mark Kraus (@markekraus) Travis Plunk (@TravisEz13) yes, please take for RC

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@SteveL-MSFT Steve Lee (SteveL-MSFT) added this to the 6.0.0-RC milestone Nov 11, 2017
@iSazonov

Ilya (iSazonov) commented Nov 11, 2017

Copy link
Copy Markdown
Collaborator

Are we ready to merge?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

SteveL-MSFT
Steve Lee (SteveL-MSFT) requested changes Nov 11, 2017
View reviewed changes
Comment thread test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 Outdated

@SteveL-MSFT Steve Lee (SteveL-MSFT) Nov 11, 2017

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I would prefer to use `n for newline whitespace than rely on the line endings of the file

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@markekraus Mark Kraus (markekraus) Nov 11, 2017

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

fixed.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
TravisEz13
Travis Plunk (TravisEz13) approved these changes Nov 11, 2017
View reviewed changes
SteveL-MSFT
Steve Lee (SteveL-MSFT) approved these changes Nov 11, 2017
View reviewed changes
@SteveL-MSFT

Steve Lee (SteveL-MSFT) commented Nov 11, 2017

Copy link
Copy Markdown
Member

Ilya (@iSazonov) I think this is ready to merge

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iSazonov Ilya (iSazonov) closed this Nov 13, 2017
@iSazonov Ilya (iSazonov) reopened this Nov 13, 2017
@iSazonov

Ilya (iSazonov) commented Nov 13, 2017

Copy link
Copy Markdown
Collaborator

Reopen to restart CI.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markekraus

Mark Kraus (markekraus) commented Nov 13, 2017

Copy link
Copy Markdown
Contributor Author

Ilya (@iSazonov) *sigh. It looks like both Travis CI tests passed, but it has not updated the PR.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iSazonov

Ilya (iSazonov) commented Nov 13, 2017

Copy link
Copy Markdown
Collaborator

I can not manually merge 😕

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@SteveL-MSFT

Steve Lee (SteveL-MSFT) commented Nov 13, 2017

Copy link
Copy Markdown
Member

Mark Kraus (@markekraus) can you rebase and pick up #5249?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markekraus
Mark Kraus (markekraus) force-pushed the FixIrmSingleValueNull branch from 1c58efc to 4a5d6f7 Compare November 13, 2017 18:33
@markekraus

Mark Kraus (markekraus) commented Nov 13, 2017

Copy link
Copy Markdown
Contributor Author

rebased.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@TravisEz13

Travis Plunk (TravisEz13) commented Nov 13, 2017

Copy link
Copy Markdown
Member

Mark Kraus (@markekraus) there is a merge conflict now.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Mark Kraus (markekraus) added 3 commits November 13, 2017 14:29
@markekraus
[Feature] Fix Single Value JSON null in Invoke-WebRequest
11983cd
@markekraus
[Feature] Switch from Regex to JToken.Parse()
f6e173b
@markekraus
[Feature] Address PR Feedback: use `n
d968c99
@markekraus
Mark Kraus (markekraus) force-pushed the FixIrmSingleValueNull branch from 4a5d6f7 to d968c99 Compare November 13, 2017 20:29
@markekraus

Mark Kraus (markekraus) commented Nov 13, 2017

Copy link
Copy Markdown
Contributor Author

rebased.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@TravisEz13

Travis Plunk (TravisEz13) commented Nov 13, 2017

Copy link
Copy Markdown
Member

restarted appveyor due to github rate limit failure

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iSazonov
Ilya (iSazonov) merged commit 87bcd41 into PowerShell:master Nov 14, 2017
@markekraus
Mark Kraus (markekraus) deleted the FixIrmSingleValueNull branch January 19, 2018 18:58
Thatgfsj (Thatgfsj) pushed a commit to Thatgfsj-contribs/PowerShell that referenced this pull request Aug 6, 2026
@markekraus @iSazonov
Fix Single Value JSON null in Invoke-RestMethod (PowerShell#5338)
62610d7
* [Feature] Fix Single Value JSON null in Invoke-WebRequest

* [Feature] Switch from Regex to JToken.Parse()

* [Feature] Address PR Feedback: use `n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@iSazonov Ilya (iSazonov) iSazonov left review comments
@TravisEz13 Travis Plunk (TravisEz13) TravisEz13 approved these changes
@SteveL-MSFT Steve Lee (SteveL-MSFT) SteveL-MSFT approved these changes
@dantraMSFT Dan Travison (dantraMSFT) Awaiting requested review from dantraMSFT
@JamesWTruher James Truher (JamesWTruher) Awaiting requested review from JamesWTruher
@PaulHigin Paul Higinbotham (PaulHigin) Awaiting requested review from PaulHigin

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@iSazonov Ilya (iSazonov)

Labels

Breaking-Change breaking change that may affect users

Projects

None yet

Milestone

6.0.0-RC

Development

Successfully merging this pull request may close these issues.

Invoke-RestMethod doesn't return useful info when no data is returned.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@markekraus @TravisEz13 @SteveL-MSFT @iSazonov
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.