5 minute read

Code Bits&Pieces and Context

This post is not an Eureka moment, so do not expect any breakthrough or light bulb moment.

However, sometimes we forgot one of the basic rules of code development that we learned or read in the past.

Typically, if we re-utilize a bit code more than 3 to 5 times, it could to promote it to a separate function/method to consolidate it in a single place, making it easier to update or correct if necessary, since it would be a single place to change instead of all the places where we re-utilized it.

Adding to that easy to understand advantage it will also be a code refactoring exercise, since once that function/method is created, we will be able to optimize or re-code it completely without affecting the expected functionality.

Using GET and POST REST API Methods as an example

As an example we can create some wrapping functions to simplify the interaction with a REST API.

We will create 2 functions:

  • Get-RestAPICall
    • Method - GET
    • Parameters - headers, url
  • Post-RestAPICall
    • Method - POST
    • Parameters - headers, url, payload

These 2 wrappers will be a way of simplifying the use of Powershell cmdlet Invoke-RestMethod and even handling some of the errors/exceptions.

Functions code

We added some error/exception handling to the functions to give the functions to make them a bit more than a passthrough to the Invoke-RestMethod.

Get-RestAPICall

function Get-RestAPICall {
    param(
        [Parameter(Position=0, Mandatory = $true, ValueFromPipeline = $true)] `
            [string]$url,
        [Parameter(Position=1, Mandatory = $false, ValueFromPipeline = $true)] `
            [System.Collections.Generic.Dictionary[[String],[String]]]$headers
    )
    try {
        if ($headers) {
            $request = Invoke-RestMethod -Method GET -Headers $headers -Uri $url
        } else {
            $request = Invoke-RestMethod -Uri $url
        }
    } catch [System.Net.WebException] {
        $exceptionError = $_.Exception

        switch ($exceptionError.Response.StatusCode.value__) {
            "200"   {
                Write-Host "=> Get-RestAPICall -> OK - $url <=" `
                    -ForegroundColor Green
            }
            "400"   {
                Write-Host "=> Get-RestAPICall -> Bad Request - $url <=" `
                    -ForegroundColor Red
                $request = $null
            }
            "404"   {
                Write-Host "=> Get-RestAPICall -> Not Found - $url <=" `
                    -ForegroundColor Red
                $request = $null
            }
            "405"   {
                Write-Host "=> Get-RestAPICall -> Invalid Method - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
            "500"   {
                Write-Host "=> Get-RestAPICall -> Internal Server Error - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
            "503"   {
                Write-Host "=> Get-RestAPICall -> Service Unavailable - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
            default  {
                Write-Host "=> Get-RestAPICall -> Unspecified Error - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
        }
    }

    return $request
}

Post-RestAPICall

function Post-RestAPICall {
    param(
        [Parameter(Position=0, Mandatory = $true, ValueFromPipeline = $true)] `
            [string]$url,
        [Parameter(Position=2, Mandatory = $true, ValueFromPipeline = $true)] `
            [string]$payload,
        [Parameter(Position=3, Mandatory = $false, ValueFromPipeline = $true)] `
            [System.Collections.Generic.Dictionary[[String],[String]]]$headers
    )
    # Load constants
    . "$PSScriptRoot\..\shared\shared.constants.ps1"

    try {
        if ($headers) {
            $request = Invoke-RestMethod -Method POST -Headers $headers -Body $payload -Uri $url
        } else {
            $request = Invoke-RestMethod -Body $payload -Uri $url
        }
    } catch [System.Net.WebException] {
        $exceptionError = $_.Exception

        switch ($exceptionError.Response.StatusCode.value__) {
            "200"   {
                Write-Host "=> Post-RestAPICall -> OK - $url <=" -ForegroundColor Green
            }
            "400"   {
                Write-Host "=> Post-RestAPICall -> Bad Request - $url <=" -ForegroundColor Red
                $request = $null
            }
            "500"   {
                Write-Host "=> Post-RestAPICall -> Internal Server Error - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
            default  {
                Write-Host "=> Post-RestAPICall -> Unspecified Error - $url <=" `
                    -ForegroundColor Red
                Write-Host "=> StatusCode:" $exceptionError.Response.StatusCode.value__ `
                    -ForegroundColor Yellow
                Write-Host "=> StatusDescription:" $exceptionError.Response.StatusDescription `
                    -ForegroundColor Yellow
                Write-Host "=> Type:" $exceptionError.GetType() -ForegroundColor Yellow
                Exit
            }
        }
    }

    return $request
}

Examples

Examples how to use the newly defined functions.

The examples below are part of a future post where these wrapping functions will be used to interact with the VMware Cloud Foundation(VCF) bringup appliance API, to automate the deployment of a VMware cluster, following the Consolidated Architecture Model defined in the VMware Validated Designs (VVD).

Get-RestAPICall

In this example we are just making a quick GET call to the VCF bringup service to check the service version.

$url = "http://localhost:9080/bringup-app/bringup/about"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type" , "application/json")

if (($request = Get-RestAPICall -url $url -headers $headers).name -notmatch "BRINGUP") {
    Write-Host "--> bringup - Bringup service is not UP <--" -ForegroundColor Red
    Exit
} else {
    Write-Host "--> bringup - Bringup service is UP and running <--" -ForegroundColor Green
    Write-Host "--> bringup - $($request.name) - $($request.serviceId) - $($request.version) <--" -ForegroundColor Green
}

Post-RestAPICall

This example will be a POST call and will require some extra headers and a payload. The extra headers is to specify that the payload will be in JSON format. The payload will be a JSON with all the information needed by the VCF bringup service to deploy the VMware cluster.

$url = "http://localhost:9080/bringup-app/bringup/sddcs"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type" , "application/json")
$headers.Add("Content-Accept" , "application/json")

$request = Post-RestAPICall -url $url -headers $headers -payload $vpodJSON
$bringupId = $request.id