Invoke-RestMethod is a PowerShell cmdlet that provides the ability to send requests from the command line to a REST API.
Invoke-RestMethod
can be used to make web requests to any server, but is specifically intended to work with REST APIs that use JSON as their data representations.
Note
The Invoke-WebRequest cmdlet is a more generalized tool for working with other formats like XML or HTML.
Throughout this class, we have used Postman as a way for making requests to a RESTful API. Postman offers a GUI that is a very pleasant interface to work with. However, a GUI is not always the best interface for a given job.
A benefit of making requests from a CLI is that you can combine as many requests as necessary into a single script. This creates the ability to automate interactions with a RESTful API.
Invoke-RestMethod
¶Similarly to Postman, Invoke-RestMethod
allows you to fully configure each HTTP request including setting the:
The JSON responses received by an Invoke-RestMethod
call are automatically converted from a JSON-formatted string to a PSCustomObject. The fields of the JSON response are then accessible as properties of this object using dot notation.
Tip
These response objects can be used directly within a PowerShell session, in a script, or can be saved to a JSON file.
Open-Notify is a publicly available REST API that returns information about astronauts in space.
The Open-Notify API contains live data that is continuously updated. Let’s explore this API by making a simple GET
request for its Astros
resource using Invoke-RestMethod
.
The Astros
resource has the following shape:
{
message: integer,
number: integer,
people: Person[]
}
The people
field is an array of Person
resources with the following shape:
{
name: string,
craft: string
}
Let’s make a GET
request for the Astros
resource. If you don’t specify the request method it will default to GET
.
Invoke-RestMethod
will convert the JSON response to a PSCustomObject
. By default, these custom objects are printed in the terminal in a table presentation:
> Invoke-RestMethod -URI "http://api.open-notify.org/astros.json"
message number people
------- ------ ------
success 5 {@{craft=ISS; name=Chris Cassidy}, @{craft=ISS; name=Anatoly Iv…
Using the grouping operator, we can access the people
array property of the custom object in the following way:
> (Invoke-RestMethod -URI "http://api.open-notify.org/astros.json").people
craft name
----- ----
ISS Chris Cassidy
ISS Anatoly Ivanishin
ISS Ivan Vagner
ISS Doug Hurley
ISS Bob Behnken
Note
The grouping operator will cause the Invoke-RestMethod
to be executed first. The resulting custom object can then have its properties accessed using dot notation on the closing parenthesis: )
.
Because we are working with objects, we can filter the response down further by piping the people
array object to the Select-Object
cmdlet:
> $uri = "http://api.open-notify.org/astros.json"
> (Invoke-RestMethod -URI $uri).people | Select-Object -Property name
name
----
Chris Cassidy
Anatoly Ivanishin
Ivan Vagner
Doug Hurley
Bob Behnken
Storing the result in a variable becomes useful, so that we don’t have to keep making the same request to access its data:
> $webRequest = Invoke-RestMethod -URI "http://api.open-notify.org/astros.json"
We can then work with the data through the variable. For example, we can access the people
field:
> $webRequest.people
craft name
----- ----
ISS Chris Cassidy
ISS Anatoly Ivanishin
ISS Ivan Vagner
ISS Doug Hurley
ISS Bob Behnken
We can also access the nested name
field of one of the astronauts by chaining property and array access:
> $webRequest.people[0].name
Chris Cassidy
We can even use our variable to control how the people
array is sorted by piping it to the Sort-Object
cmdlet:
> $webRequest.people | Sort-Object -Property name
craft name
----- ----
ISS Anatoly Ivanishin
ISS Bob Behnken
ISS Chris Cassidy
ISS Doug Hurley
ISS Ivan Vagner
We can combine these steps in a longer pipe that:
people
array fieldPerson
element by their nested name
field> $webRequest.people | Sort-Object -Property name | ConvertTo-Csv
"craft","name"
"ISS","Anatoly Ivanishin"
"ISS","Bob Behnken"
"ISS","Chris Cassidy"
"ISS","Doug Hurley"
"ISS","Ivan Vagner"
In many cases it is beneficial to save transformed responses to a file for later use. Rather than just printing the converted results we can use the Export-Csv
cmdlet to write to a file:
> $webRequest.people | Sort-Object -Property name | Export-Csv "people.csv"
You can then use the Get-Content
cmdlet to view the CSV contents as strings:
> Get-Content people.csv
"craft","name"
"ISS","Anatoly Ivanishin"
"ISS","Bob Behnken"
"ISS","Chris Cassidy"
"ISS","Doug Hurley"
"ISS","Ivan Vagner"
If we wanted to save in a JSON format we would need to add an additional step in our pipeline to convert the custom object back to a JSON string.
We use the ConvertTo-Json
cmdlet to accomplish this serialization from an object back to a JSON string:
> $webRequest.people | Sort-Object -Property name | ConvertTo-Json | Set-Content "people.json"
Note
We can also split up this pipeline to make it more readable:
> # split for readability
> $SortedPeople = $webRequest.people | Sort-Object -Property name
> $SortedPeople | ConvertTo-Json | Set-Content "people.json"
This approach is invaluable for practicing with data transformations. Whereas a variable in our PowerShell terminal will disappear after closing, a file can be reused indefinitely and shared with others.
You can then load the JSON contents as a string using Get-Content
:
> Get-Content "people.json"
[
{
"craft": "ISS",
"name": "Anatoly Ivanishin"
},
{
"craft": "ISS",
"name": "Bob Behnken"
},
{
"craft": "ISS",
"name": "Chris Cassidy"
},
{
"craft": "ISS",
"name": "Doug Hurley"
},
{
"craft": "ISS",
"name": "Ivan Vagner"
}
]
However, in order to work with the JSON contents as custom objects we need to convert it back (deserialize) using the ConvertFrom-Json
cmdlet. This will enable dot-notation access of fields like in the original Invoke-RestMethod
output:
> Get-Content "people.json" | ConvertFrom-Json
craft name
----- ----
ISS Anatoly Ivanishin
ISS Bob Behnken
ISS Chris Cassidy
ISS Doug Hurley
ISS Ivan Vagner
The Invoke-RestMethod
cmdlet is a powerful tool for working with APIs. When combined with our knowledge of PowerShell, we have many options for interacting with a REST API and transforming the data we receive.
CodingEventsAPI
Examples¶Let’s test this out with our Coding Events API. To keep things simple, let’s use the 1-sqlite
branch so we don’t need to worry about setting up a database, a secrets manager, or AADB2C.
Run this branch to start the Coding Events API on your local machine.
GET
Example¶To get a collection of coding events you could use:
> Invoke-RestMethod -Uri "http://localhost:5000/api/events"
To get an individual coding event entity you could use:
> $CodingEventId = 1
> Invoke-RestMethod -Uri "http://localhost:5000/api/events/$CodingEventId"
DELETE
Example¶To delete an existing coding event entity you could use:
> $CodingEventId = 1
> $uri = "http://localhost:5000/api/events/$CodingEventId"
> Invoke-RestMethod -Method "Delete" -Uri $uri
POST
Example¶To create a new coding event we need to use two additional options:
-Method
: to set the POST
HTTP method-Body
: to define the body of the POST
requestTo provide the body of the request you can use a HashTable object or a here-string.
The HashTable
object is simple to create:
> $body = @{
Title = "Halloween Hackathon!"
Description = "A gathering of nerdy ghouls..."
Date = "2020-10-30"
}
Note
The HashTable
object does not have any commas and uses the =
assignment operator for defining each key-value entry.
However, before it can be used in the request it must be converted to JSON with an appropriate Content-Type
header.
We can use:
ConvertTo-Json
: in a grouped expression to serialize the HashTable
as a JSON string-ContentType
option: to automatically set the Content-Type
header of application/json
> $uri = "http://localhost:5000/api/events"
> Invoke-RestMethod -Method "Post" -Uri $uri -Body ($body | ConvertTo-Json) -ContentType "application/json"
You can also load the body from a JSON file. This allows you to use existing files or a GUI editor to create the JSON body in a more intuitive way.
Let’s assume we have a file ~\coding-event.json
with the following contents:
> Get-Content ~\coding-event.json
{
"Title": "test title is long",
"Description": "test description goes here",
"Date": "2020-10-31"
}
We could use this file as the contents of the request body using a grouped expression:
> Invoke-RestMethod -Method Post -Uri $uri -Body (Get-Content ~\coding-event.json) -ContentType "application/json"
Tip
You can use any of these -Body
defining approaches for creating and adding bodies to PUT
and PATCH
requests as well. When used on a GET
request the body will be converted to query string parameters in the URI.
Invoke-RestMethod
, like Postman, has many additional options we can use to further configure requests.
You can look over the documentation of Invoke-RestMethod to get an understanding of its capabilities.
You can work with any RESTful APIs using the Invoke-RestMethod
cmdlet. To continue practicing you can work with any publicly available APIs like the GitHub Developer API.