insomniacc / PSSnow

A powershell module for interacting with the ServiceNow REST API
GNU General Public License v3.0
41 stars 9 forks source link

Better rest error handling for 5.1 #33

Open insomniacc opened 1 year ago

insomniacc commented 1 year ago

If using core you'll get a relevant error from a bad rest request including the error message. example:

Invoke-RestMethod: 
Line |
2265 |              $Response = Invoke-RestMethod @RestSplat
     |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | {"result":{"errCode":"42202","errMsg":"This item cannot be submitted for multiple people as it is not configured with Requested For"}}

On 5.1 errors are basic and messages not displayed: example:

Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
+ ... $Response = Invoke-RestMethod -Method POST -Uri $URI -Headers $Header ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Enhancing the error handling and output would be a better user experience on 5.1

insomniacc commented 1 year ago

The error on core comes from the response body nested under result. On 5.1 only the typical header error is shown not the response. It would be useful to parse these and display them correctly for both core and 5.1

insomniacc commented 1 year ago

Also needs checking all commands should throw a readable exception if there are permission/authorization errors.

insomniacc commented 1 year ago

I've forced an error in 5.1 (400 bad request), checking the full exception object from both invoke-webrequest and invoke-restmethod still doesnt show any further detail than this. Not sure what the difference between that and core is, with core I'm getting

{"error":{"message":"Pagination not supported","detail":"The requested query is too long to build the response pagination header URLs. Please do one of the following: shorten the sysparm_query, or query without pagination by setting the parameter 'sysparm_suppress_pagination_header' to true, or     
                        set 'sysparm_limit' with a value larger then 621 to bypass the need for pagination."},"status":"failure"}

Under the ErrorDetails inside the exception. I think it's not going to be a straight forward one so I'll leave this for now.

liamjpeters commented 1 year ago

Hey Tom 👋,

5.1 will stop short of reading the full response body when it gets an error and will instead just read the headers. If, as in the case of ServiceNow, those headers don't contain too much useful info - you can get to the full response stream and decode it yourself by doing something like:

try {
  # ServiceNow Failing Rest Call Here
} catch {
  $StreamReader = New-Object System.IO.StreamReader -argumentList ($_.Response.GetResponseStream());
  $ErrorBody = $StreamReader.ReadToEnd()
  $StatusCode = [int] $_.Exception.Response.StatusCode
  $StatusDescription = $_.Exception.Response.StatusDescription + " " + $ErrorBody
}

I've not tested the above (it's from an old ServiceNow script of mine actually) but it should point you in the right direction.

Cheers

insomniacc commented 1 year ago

@liamjpeters Hey, thanks for this comment, interesting, I'll take a closer look this next week, haven't unfortunately had much chance of late! Hope things are going well!