0
\$\begingroup\$

I'm using SAP's Raylight RESTful SDK to get a list of universes from the BusinessObject Enterprise repository.

To get all of the universes, the request needs to be called repeatedly, incrementing the offset parameter until the request returns a Not Found [404] error.

Current approach:

$baseUrl = 'http://<server>:6405/biprws/raylight/v1'

$headers = @{}
$headers.Add("Accept", "application/json")
$headers.Add("Content-Type", "application/json")
$headers.Add("x-sap-logontoken", $Token)

$offset = 0
$limit = 50

try {
    do {

        $Path = "/universes?offset=$offset&limit=$limit"

        $response = Invoke-WebRequest "$baseUrl$Path" -Headers $headers 
        ($response | ConvertFrom-Json).universes.universe

        $offset += $limit

    } until ( $response.StatusCode -eq [System.Net.HttpStatusCode]::NotFound )
}
catch {
    # catches 404 too
    Write-Debug "StatusCode: $($_.Exception.Response.StatusCode.Value__)"
}

While the code returns the expected results, I not sure that I like how the code will always exit via the catch. I could remove the try/catch, but that will leave the code exposed to other errors.

Is there a way to improve this?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

You appear to have some incorrect logic. The until expression will never get evaluated in the case of a 404 exception. It will get skipped over. So it's kind of pointless.

So let's replace the repeat ... until with a while ($true). That is, an infinite loop. This works the same as what you already had, but the logic is clearer. I added a comment at the top, too, to let the reader know that a 404 exception will break the loop:

while ($true) {
    # Will throw 404 exception when finished.

    $Path = "/universes?offset=$offset&limit=$limit"

    $response = Invoke-WebRequest "$baseUrl$Path" -Headers $headers 
    ($response | ConvertFrom-Json).universes.universe

    $offset += $limit
}

Now, in general it's not good to use exceptions for normal program control flow. They should normally be used for exceptional cases only. But sometimes—such as in this case it would seem—we do have to use them. In such cases the usual pattern is to catch the exception and then examine it to see if it's a normal control flow exception or if it's a true exception, and respond accordingly.

So let's do that. If we catch a 404 exception, then we will just ignore it. If it's anything else, then we will rethrow it:

try {
    while ($true) {
        # Will throw 404 exception when finished.

        $Path = "/universes?offset=$offset&limit=$limit"

        $response = Invoke-WebRequest "$baseUrl$Path" -Headers $headers 
        ($response | ConvertFrom-Json).universes.universe

        $offset += $limit
    }
}
catch [System.Net.WebException] {
    $statusCode = $_.Exception.Response.StatusCode.Value__

    if ($statusCode -eq 404) {
        # Normal end case. Do nothing.
    }
    else {
        throw
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I considered using an infinite loop, too. I'd probably change the catch to use a switch: Switch ($_.Exception.Response.StatusCode) { [System.Net.HttpStatusCode]::NotFound { # nada } default { throw } } \$\endgroup\$
    – craig
    Jan 18, 2018 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.