New-PSUEndpoint - few issues

Hi!

I’m trying to use REST APIs in Universal and thus far it was not great experience.
Compared to UD - it feels like it went back few steps. :frowning:

  • adding param block is breaking endpoint, not sure if that is intended, but if so - it seems like a pure design choice to me. I want to be able to explicitly configure parameters on my endpoints
  • error handling feels completely broken: exception that are not handled are eaten up, New-PSUApiResponse would send StatusCode over but whole body is missing

Example endpoints.ps1 that should highlight basics:

New-PSUEndpoint -Url /broken -Endpoint {
    New-PSUApiResponse -StatusCode 404 -Body 'Failed!'
} -Role Reader

New-PSUEndpoint -Url /params/:test -Endpoint {
    Param (
        [String]$Test
    )

    @{
        test = $Test
    } | ConvertTo-JsonEx
} -Role Reader

New-PSUEndpoint -Url /noparams/:test -Endpoint {
    @{
        test = $Test
    } | ConvertTo-JsonEx
} -Role Reader

And results when I try to call both:

# calling /broken
try {  irm http://psu-test/broken -used } catch { $_ | fl * -Force }

# result for /broken
PSMessageDetails      :
Exception             : System.Net.WebException: The remote server returned an error: (404) Not Found.
                           at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
                           at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
TargetObject          : System.Net.HttpWebRequest
CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}


# calling /params
irm http://psu-test/params/myTest -UseDefaultCredentials

# result for /params
test
----

# calling /noparams
irm http://psu-test/noparams/myTest -UseDefaultCredentials

# result for /noparams
test
----
myTest

For us both parameters definition on even more importantly proper error handling are crucial elements of the puzzle…

Hi Bartek,

Sorry you are having trouble.

Re: Param block

We can implement it to work this way. It currently is just setting variables into the runspace and not passing parameters.

Re: Error Handling:

I think what you are looking for is -ErrorAction. If you set it to stop on your endpoint, it will return any error that happens within the endpoint.

https://docs.ironmansoftware.com/api/about#error-handling

For example:

    New-PSUEndpoint -Url /error -Endpoint {
        throw "Uh oh!"
    } -ErrorAction Stop

    New-PSUEndpoint -Url /error2 -Endpoint {
        Write-Error "Whoa!"
    } -ErrorAction Stop

Calling this from PS7.1 looks like this:

PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/error 

Invoke-RestMethod: Uh oh!
at , : line 2
at , : line 1

PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/error2

Invoke-RestMethod: Whoa
at , : line 2
at , : line 1

Calling from WinPS. The error isn’t as good.

PS C:\Users\adamr> invoke-restmethod http://localhost:5000/error2
invoke-restmethod : The remote server returned an error: (500) Internal Server Error.
At line:1 char:1
+ invoke-restmethod http://localhost:5000/error2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], Web
   Exception
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

The body is passed back by PSU but WinPS doesn’t show it as well for non 200 status codes. Here’s how to get the body out.

PS C:\Users\adamr> try { invoke-restmethod http://localhost:5000/error2 } catch { [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()).ReadToEnd()}
Whoa!
at <ScriptBlock>, <No file>: line 2
at <ScriptBlock>, <No file>: line 1

This is the same for 404s. Using your broken example:

    New-PSUEndpoint -Url /broken -Endpoint {
        New-PSUApiResponse -StatusCode 404 -Body 'Failed!'
    }

When I call this in PS7.1:

PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/broken

Invoke-RestMethod: Failed!

I have to use the same technique in WinPS to see the 404 error body.

PS C:\Users\adamr> try { invoke-restmethod http://localhost:5000/broken } catch { [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()).ReadToEnd()}
Failed!
PS C:\Users\adamr> invoke-restmethod http://localhost:5000/broken
invoke-restmethod : The remote server returned an error: (404) Not Found.
At line:1 char:1
+ invoke-restmethod http://localhost:5000/broken
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], Web
   Exception
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

If I’m remembering correctly, I think the difference here was in UD, if there was an error, it would still return a 200 status code but pass back a JSON blob with the error in it. That’s why WinPS would show the errors and now with PSU it doesn’t. We could change how PSU does this by default so that if an error is thrown and ErrorAction isn’t set to stop (e.g. Default), it would return the JSON string with the error in it.

I’ll make sure to get all this into the documentation for PSU in the morning.

Now to go back to sleep for a bit :wink: