2017-09-27

New PowerShell Core Feature: Invoke-RestMethod -ResponseHeadersVariable

2017092701
Pictured: The new -ResponseHeadersVariable parameter in action

Intro

I wanted to share with you another new feature added to the PowerShell Core Invoke-RestMethod Cmdlet: The -ResponseHeadersVariable parameter.

This feature will be available starting with PowerShell Core v6.0.0-beta.8 and is available now in the nightly builds or if you build it yourself from master.


The Problem

I have been a big fan of Invoke-RestMethod for accessing API's that return XML or JSON as it very conveniently handles the type evaluation and object serialization. When using it, a JSON endpoint "feels" like it it is returning a native PowerShell object. It is a lightweight cmdlet that is decently performant and simplistically powerful.

I have had one gripe with Invoke-RestMethod over the years: there was no way to inspect the Response Header along with the response object.

Many API's provide data in the Response Header that can be comical, informative, important, or critical. An example of critical Response Header values returned by an API are Reddit's X-Ratelimit-Used, X-Ratelimit-Remaining, and X-Ratelimit-Reset headers. Reddit uses these response headers to inform you of where your bot stands with regard to their limits of requests to the API per minute. Abuse of their API can lead to bot and account bans. Any good bot monitors these Response Header fields and initiate a cool down before Reddit begins returning rate limit errors. My PSRAW module includes automated rate limit handling so the bot maker doesn't need to worry about it.

In Windows PowerShell 5.1 and earlier, to accomplish any task with an API that required monitoring the Response Header one had to fall back to the Invoke-WebRequest Cmdlet. This meant one also had to do their own content detection and object serialization. Invoke-RestMethod simply included no way to view the Response Header, but Invoke-WebRequest returns a WebResponseObject which includes a Headers property that contains a dictionary where the keys are the Response Header field names and the values are their respective field values.


The Solution

After moving the logic for Headers property from the internal WebResponseObject code to a shared code space and some slight performance optimization (#4853), I added the -ResponseHeadersVariable parameter to the Invoke-RestMethod cmdlet (#4888).

This parameter behaves similar to the -SessionVariable parameter in that it accepts a string which is then used as the name of a variable created in the calling scope. In other words, if you supply the string 'Headers' to the -ResponseHeadersVariable parameter, it will create a $Headers variable. That variable will be the same dictionary you would see on the Headers property from the object returned from Invoke-WebRequest.


Shut Up and Show Me Some Code!

With pleasure, dear reader, I bring you the following example you can try at home (or work… or on your Raspberry Pi):

$uri = 'https://httpbin.org/get'
$Headers = $null
$WebRequestResult = Invoke-WebRequest -Uri $uri
$RestMethodResult = Invoke-RestMethod -Uri $uri -ResponseHeadersVariable 'Headers'

$WebRequestResult.Headers.Server[0] -eq $Headers.Server[0]
'Response Content-Type was {0}' -f $Headers['Content-Type'][0]

Result:

20170927012PNG

Note that setting $Headers to $null is only to demonstrate that the variable is empty before being populated by Invoke-RestMethod and is not necessary.

-ResponseHeadersVariable is really long, Isn't there something shorter?

Yes, there is! For you console users (do not use this in production code) I have also added the -RHV parameter alias.

$result = irm -RHV Headers https://httpbin.org/get
$Headers.Date

Result:

2017092701203


Conclusion

I hope others find this feature useful. If you end up using it please let me know!

Join the conversation on Reddit!