Understanding the VMware REST API interface

SOAP (Simple Object Access Protocol) is a Web services access protocol that was originally developed by Microsoft. It relies exclusively on XML and was developed because existing messaging services Microsoft was using like DCOM (Distributed Component Object Model) and COBRA (Common Object Request Broker Architecture) didn’t work that well over the Internet. After developing SOAP, Microsoft turned it over to the IEFT, which standardized it, spawning a host of other web services standards like WS-Federation, WS-Addressing, WS-Policy, WS-Security, and so on, which are defined using WSDL (Web Services Description Language). REST is basically a lightweight alternative to SOAP that uses HTTP 1.1 methods like GET, POST, PUT, and DELETE for making requests instead of XML, which SOAP uses. Many REST-based web services are available that can output data in simple formats like CSV, JSON, and even RSS. This makes REST much easier to use, for example, when using JavaScript to develop a dynamic website or web application. VMware vSphere 6.5 introduces a number of new REST-based APIs in addition to the existing SOAP APIs in the platform. This may indicate that VMware regards REST as being the future over SOAP. To help us understand the VMware REST API and how to utilize it, I’ve asked Luc Dekens to share some of his expertise with us. Luc is a vExpert and MVP and is interested in all things automation, and more specifically through PowerShell and PowerCLI. He is a co-author of the PowerCLI Reference and a regular speaker at conferences. You can read Luc’s blog here, or follow him on Twitter as @LucD22.

The REST API in practice

The last couple of years, more and more vendors are advertising that they are providing a RESTful interface to their product. On the risk of already starting a flame war in the introductory section of this article, I tend to disagree with most of these vendors.

No, you are not providing a RESTful interface to your product; you are following some REST rules in your new API. But hey, what you are providing definitely makes my life as a consumer of your product, a lot simpler and easier.

What is REST API?

So why the bold statement in the previous section? As in most cases, there is a difference between theory and practice, and more specifically between a RESTful interface and basic REST rules. While the RESTful theory, as originally described by Roy T. Fielding, in chapter 5 of his doctoral dissertation “Architectural Styles and the Design of Network-based Software Architectures,” and more specifically in his blog post “REST APIs must be hypertext-driven,” stresses the importance of the discoverability of actions a client can perform on an object, most REST implementations seem to deviate from this principle.

As a practical example, take a virtual machine, with the GET action we can request information about that virtual machine, but it will be the client that needs to interpret the returned PowerState of the Virtual Machine, “on” or “off,” to determine if he can POST a “power off” or a “power on” action.

In a REST API that offers a RESTful interface, it should adhere to the HATEOAS (Hypermedia As The Engine Of Application State) constraints. More specifically, the object returned by the GET verb should contain the “links” to the actions that are available on the object in its current state.

Why use REST API?

Does the previous mean that we shouldn’t be using REST API that are not “pure,” aka RESTful? Of course not. REST API offers more than just discoverability of actions to the consumer. And on the provider side (the vendor), it offers the possibility to simplify their API. On top of that, since most REST API implementations are predominantly using HTTP(S) as a protocol, it also makes an architecture based on REST concepts more manageable for the network teams. And finally, our preferred language of automation, PowerShell, makes consuming REST API via HTTP quite easy with the Invoke-RestMethod and Invoke-WebRequest cmdlets.

VMware and REST API

There might be several reasons, and that’s my personal interpretation, VMware is going for REST API to replace their SOAP API. One of these would definitely be that it allows VMware to switch to Swagger to define their API in a much simpler way than used to be the case with WADL (Web Application Design Language) for their SOAP API.

As an example, the API Explorer that is available since VMware vCenter 6.5 is a direct result from this switch to Swagger. This API Explorer available in vCenter allows one to explore and “try out” the available REST API, without actually writing any code:

API Explorer

Calling the REST API

We already mentioned that PowerShell has built-in cmdlets to work with REST API, but there are a few intricacies that one needs to understand to make a valid call to a REST API:

calling a REST API

In the VMware REST API that is available in vCenter 6.5, there is an API that allows one to retrieve (Get) all the available commands (/com/vmware/vapi/metadata/cli/command), and then through a second API to fetch (Post) more details on the parameters that are available (rest/com/vmware/vapi/metadata/cli/command?~action=get).

A simple script to use these two API could look like this.


$vCenterName = ‘vcsa.local.lab’
$auth = @{
‘vmware-api-session-id’ = ‘8d377b7ee718b9fdead33d8f3230019c’
}
$get_command = “https://$($vCenterName)/rest/com/vmware/vapi/metadata/cli/command”
$get_Command_detail = “https://$($vCenterName)/rest/com/vmware/vapi/metadata/cli/command?~action=get”
# Get all command identifiers
$result = Invoke-RestMethod -Uri $get_command -Headers $auth
$sRest = @{
Method = ‘Post’
Uri = $get_Command_detail
Body = ‘‘
Headers = $auth
ContentType = ‘application/json’
}
# Get more information about each command
$report = @()
foreach($command in $result.value){
$sRest.Body = @{‘identity’ = $command} | ConvertTo-Json
$detail = Invoke-RestMethod @sRest
$report += $detail.value.options |
Select-Object @{N=‘Path’;E={$command.path}},
@{N=‘Operation’;E={$command.name}},
@{N=‘Description’;E={$detail.value.description}},
@{N=‘Field’;E={$_.field_name}},
@{N=‘Type’;E={$_.type}},
@{N=‘Field Descriptoin’;E={$_.description}}
}
$report | Export-Csv -Path C:\Temp\rest-commands.csv -UseCulture


 

Don’t mind the $auth header for now, it is the way to refer to a session we opened before. We’ll get back to that later.

There are two Invoke-RestMethod calls in this snippet. The first one uses the API to retrieve all commands, the second uses the API to fetch more details for each command. Note that in the second call to the Invoke-RestMethod, the snippet uses “splatting” to pass the parameters to the cmdlet. This is my personal preference since I feel that it makes code more readable and organized.

Since we are using the Invoke-RestMethod cmdlet, we will have to convert the objects we pass in the Body to the correct format. In this case, we convert to JSON. The resulting CSV file contains information about all the commands (330 at the time of writing this), and the available parameters for each command:

CSV file

Note that this contains the same information that we also find in the API Explorer for this specific call:

API Explorer

Invoke-RestMethod vs. Invoke-WebRequest

In the previous snippet, we used the Invoke-RestMethod cmdlet to make the call to the REST API. Could we have done that through the Invoke-WebRequest cmdlet?

Of course, both cmdlets can be used to execute REST API calls, but there are some differences that you should be aware off. I prefer to classify the Invoke-WebRequest as “raw,” while the Invoke-RestMethod is “interpreted.” A sample should make that clear. The following are two calls to the same REST API:


$vCenterName = ‘vcsa.local.lab’
$auth = @{
‘vmware-api-session-id’ = ‘10e8e9965cd56bdd5478951fbe52c33f’
}
$uri = “https://$($vCenterName)/rest/com/vmware/cis/session?~action=get”
$sRest = @{
Uri = $uri
Method = ‘Post’
Headers = $auth
}
$resultRest = Invoke-RestMethod @sRest
$resultWeb = Invoke-WebRequest @sRest
The Invoke-RestMethod returns “interpreted” data, as we can see when we expand the result:
value
—–
@{created_time=2017-12-04T12:38:11.232Z; last_accessed_time=2017-12-04T12:49:38.850Z; [email protected]}
The Invoke-WebRequest returns the “raw” data. Notice how the “Content” property contains the (only) data we see with the Invoke-RestMethod:
StatusCode : 200
StatusDescription : OK
Content : {“value”:{“created_time”:”2017-12-04T12:38:11.232Z”,”last_accessed_time”:”2017-12-04T12:49:38.859Z”,”user”:”[email protected]”}}
RawContent : HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json
Date: Mon, 04 Dec 2017 12:49:38 GMT
{“value”:{“created_time”:”2017-12-04T12:38:11.232Z”,”last_accessed_time”:”2017-12-04…
Forms : {}
Headers : {[Transfer-Encoding, chunked], [Content-Type, application/json], [Date, Mon, 04 Dec 2017 12:49:38 GMT]}
Images : {}
InputFields : {}
Links : {}
ParsedHtml : mshtml.HTMLDocumentClass
RawContentLength : 138


 

What happens is that the Invoke-RestMethod cmdlet does a lot of the work for you. This includes translating the StatusCode into an error message, when it is not 200. But it also converts JSON into a PowerShell object.

Which cmdlet you use is a matter of choice, but my personal preference is to use the Invoke-RestMethod cmdlet. Why would you recode some of the functionality that is available in the cmdlet in each and every one of your scripts?

Authentication

Since we want to make secure calls to SOAP and REST API, both of them have implemented an authentication mechanism. Our scripts that use SOAP API calls, use the same session that we established with the Connect-VIServer cmdlet.

For REST API calls to vSphere, we also need to authenticate. That is done — how else — through a specific REST API call. We convert our credentials to a “basic” Base64 string:


$user = ‘[email protected]
$pswd = ‘VMware1!’
$vCenterName = ‘vcsa.local.lab’
$encoded = [System.Text.Encoding]::UTF8.GetBytes(($user, $pswd -Join ‘:’))
$encodedPassword = [System.Convert]::ToBase64String($Encoded)
$authHeader = @{
Authorization = “Basic $($EncodedPassword)”
}
$sRest = @{
Method = ‘Post’
Uri = “https://$($vCenterName)/rest/com/vmware/cis/session”
Headers = $authHeader
}
$result = Invoke-RestMethod @sRest


 

Once we created a session this way, we can use the returned session token in future calls to the REST API. This authorization header can be created as follows. Note the nonstandard way (‘vmware-api-session-id’) VMware selected to name the session token header field:


$authHeader = @{
‘vmware-api-session-id’ = $result.value
}


We’ll follow this article with another soon that shows how to perform the same action twice, once via the SOAP API and once via the REST API. The differences between these two should make it clear where your gain, as the consumer/coder, is located.

About The Author

3 thoughts on “Understanding the VMware REST API interface”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top