9.8. Making API Requests Using Invoke-RestMethod

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.

9.8.1. Command-Line REST

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.

9.8.2. Invoke-RestMethod

Similarly to Postman, Invoke-RestMethod allows you to fully configure each HTTP request including setting the:

  • URI
  • Method
  • Headers
  • Body

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.

9.8.3. Open-Notify Examples

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.

9.8.3.1. Astronaut Resource Shapes

The Astros resource has the following shape:

the Astros resource shape
{
   message: integer,
   number: integer,
   people: Person[]
}

The people field is an array of Person resources with the following shape:

Person Resource shape
{
   name: string,
   craft: string
}

9.8.3.2. Making a Request

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…

9.8.3.3. Grouping to Access Fields of the JSON Response

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: ).

9.8.3.4. Piping to Access Nested Fields

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

9.8.3.5. Storing Response Objects in a Reusable Variable

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

9.8.3.6. Sorting Response Data

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

9.8.3.7. Converting to Other Formats

We can combine these steps in a longer pipe that:

  1. Accesses the people array field
  2. Sorts each Person element by their nested name field
  3. Converts the sorted array into a CSV format
> $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"

9.8.3.8. Saving and Loading as CSV Files

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"

9.8.3.9. Saving and loading as JSON files

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:

Windows/PowerShell
> $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:

Windows/PowerShell
> # 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:

Windows/PowerShell
> 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:

Windows/PowerShell
> 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.

9.8.4. 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.

9.8.4.1. 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"

9.8.4.2. 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

9.8.4.3. 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 request

To 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
  • The -ContentType option: to automatically set the Content-Type header of application/json
Windows/PowerShell
> $uri = "http://localhost:5000/api/events"
> Invoke-RestMethod -Method "Post" -Uri $uri -Body ($body | ConvertTo-Json) -ContentType "application/json"

9.8.4.3.1. Using a JSON File

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:

Windows/PowerShell
> 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:

Windows/PowerShell
> 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.

9.8.5. Continue Learning

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.