api-management

What is Azure API Management

Microsoft Azure API Management is a service that helps protect your mission critical systems with authentication, rate limiting, quotas and caching to ease load under pressure. Rest easy knowing that only the partners, developers and applications you’ve authorized have access to your APIs and that those groups are acting in accordance with your policies. Find out more on Azure.com

REST APIs

Like many services on Azure, API Management provides us with a comprehensive REST API. This API allows us to manage Users, Groups, Products and Subscriptions.

Working on a multi-region solution, I was really happy to see these APIs. One of the recurring challenges I face everyday, is to replicate my efforts across multiple deployments sprawled over many Azure regions. Now the only way to do this effectively is to automating everything!

As of August 2014 API Management is still in public preview and is going through constant evolution. New features make their way to production and pieces fall together. The newly released REST APIs are just that, a piece that was missing. Wanting to reduce my workload I decided to create a PowerShell Module to help automate some of my repetitive tasks.

Note: The API does not allow you to define APIs, Representations. The Developer Portal CMS is not accessible through these APIs. Although these are things I would love to interact with through the REST API, I’m hopeful that something will come along.

Before we start, there are a couple things we need to do. First we need to activate the Management APIs on our API Management service. Then we need to generate an access token. I opted for the manual process which you can follow on the Azure API Management REST API Authentication page.

Then in our PowerShell ISE set both the REST API URL and the Access Token to global variable and we’re good to go.

Set-Variable -Name authorizatoin -Value 'SharedAccessSignature uid=5{id}&ex={date-time}&sn={signature}'
Set-Variable -Name serviceUrl -Value 'https://{service}.management.azure-api.net'

The first thing I tried was to Add a User. Then I needed a way to validate this first action, so I decided to List Users. And finally, I needed a way to clean up after my test so I Removed the User I created.

#This is the ID I will use to Add and Remove the User
$userID = [guid]::NewGuid()

Add-User -ID $userID -FirstName 'alexandre' -LastName 'brisebois' -Email 'alexandre@test.com' -Password 'test' -State active -Note 'test account will be delete'

#Listing Users so that I can validate that it was added
$users = Get-Users
$users.value | Format-Table -AutoSize

Remove-User -id $('/users/'+$userID)

#Listing Users so that I can validate that it was removed
$users = Get-Users
$users.value | Format-Table -AutoSize

The next step in my adventure was to traverse the graph from each resource group. I started by traversing the User graph.

# Getting a list of all Users
$users = Get-Users

foreach($u in $users.value)
{
    # Getting a User by ID
    $user = Get-User -id $u.id
    $user | Format-List

    # Getting the Groups to which a User belogs
    $groups = Get-UserGroupList -id $user.id
    $groups.value | Format-Table -AutoSize

    # Getting the Users Subscriptions
    $subscriptions = Get-UserSubscriptionList -id $user.id
    $subscriptions | Format-Table -AutoSize
}

Traversing the Groups was very similar and allows us to drill down to list Users per group.

# Getting a list of all the Groups
$groups = Get-Groups

foreach($g in $groups.value)
{
  # Getting a Group by ID
  $group = Get-Group -id $g.id

  # Getting a Group's User list
  $users = Get-Groupusers -id $group.id

  foreach($u in $users.value)
  {
    $u | Format-List
  }
}

Traversing Products came just as naturally

# Getting a list of Products
$products = Get-Products

foreach($p in $products.Value)
{
  # Getting a Product by ID
  Get-Product -id $p.id | Format-List

  # Getting a list of APIs that belong to a Product
  $apiList = Get-ProductApiList -id $p.id

  foreach($a in $apiList.Value)
  {
    # Getting an API by ID
    $api = Get-API -id $a.id 

    $api | Format-List
  }
}

REST API Wrapper PowerShell Module

function Add-Version
{
  param
  (
    [System.String]
    $url
  )

  $version ='2014-02-14'

  return $($url+'?api-version='+$version)
}

function Invoke-ApiManagementResource
{
  param
  (
    [System.String]
    $MethodUrl,

    [System.String]
    $Authorization,

    [System.String]
    $Body,

    [System.String]
    $ContentType

  )

  $dict = @{}
  $dict.Add('Authorization',$authorization)

  $response = Invoke-RestMethod -Method 'POST' -Uri $(Add-Version -url $MethodUrl) -Headers $dict -ContentType $ContentType -Body $body

  return $response
}

function Remove-ApiManagementResource
{
  param
  (
    [System.String]
    $MethodUrl,

    [System.String]
    $Authorization,

    [System.String]
    $Body,

    [System.String]
    $ETag,

    [System.String]
    $ContentType

  )

  $dict = @{}
  $dict.Add('Authorization',$authorization)
  $dict.Add('If-Match',$ETag)

  $response = Invoke-RestMethod -Method 'DELETE' -Uri $(Add-Version -url $MethodUrl) -Headers $dict -ContentType $ContentType
  return $response
}

function Update-ApiManagementResource
{
  param
  (
    [System.String]
    $MethodUrl,

    [System.String]
    $Authorization,

    [System.String]
    $Body,

    [System.String]
    $ContentType

  )

  $dict = @{}
  $dict.Add('Authorization',$authorization)

  $response = Invoke-RestMethod -Method 'PUT' -Uri $(Add-Version -url $MethodUrl) -Headers $dict -ContentType $ContentType -Body $body

  return $response
}

function Get-ApiManagementResourceMetadata
{
  param
  (
    [System.String]
    $MethodUrl,

    [System.String]
    $Authorization,

    [System.String]
    $ContentType

  )

  $dict = @{}
  $dict.Add('Authorization',$authorization)

  $response = Invoke-WebRequest -Method 'HEAD' -Uri $(Add-Version -url $MethodUrl) -Headers $dict -ContentType $ContentType

  return $response
}

function Get-ApiManagementResource
{
  param
  (
    [System.String]
    $MethodUrl,

    [System.String]
    $Authorization,

    [System.String]
    $ContentType

  )

  $dict = @{}
  $dict.Add('Authorization',$authorization)

  $response = Invoke-RestMethod -Method 'GET' -Uri $(Add-Version -url $MethodUrl) -Headers $dict -ContentType $ContentType

  return $response
}

function Get-Products
{
    return Get-ApiManagementResource -MethodUrl $($serviceUrl+'/products') -Authorization $authorizatoin -ContentType $contentType
}

function Get-Product
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType
}

function Get-API
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType
}

function Get-ProductApiList
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id+'/apis') -Authorization $authorizatoin -ContentType $contentType
}

function Get-ProductMetadata
{
   param
   (
     [System.String]
     $id
   )

    $response = Get-ApiManagementResourceMetadata -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType

    return $response.Headers.'ETag'
}

function Get-Users
{
    return Get-ApiManagementResource -MethodUrl $($serviceUrl+'/users') -Authorization $authorizatoin -ContentType $contentType
}

function Get-User
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType
}

function Get-UserMetadata
{
   param
   (
     [System.String]
     $id
   )

    $response = Get-ApiManagementResourceMetadata -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType

    return $response.Headers.'ETag'
}

function Remove-User
{
   param
   (
     [System.String]
     $id
   )

    $etag = Get-UserMetadata  -id $id
    return Remove-ApiManagementResource -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType -ETag $etag
}

function Add-User
{
   param
   (
     [System.String]
     $ID,

     [System.String]
     $FirstName,

     [System.String]
     $LastName,

     [System.String]
     $Email,

     [System.String]
     $Password,

     [System.String]
     [ValidateSet('active','blocked')]
     $State,

     [System.String]
     $Note = ''
   )

    $body = @{}
    $body.Add('firstName',$FirstName)
    $body.Add('lastName',$LastName)
    $body.Add('email',$Email)
    $body.Add('note',$Note)
    $body.Add('password',$Password)
    $body.Add('state',$State)

    return Update-ApiManagementResource -MethodUrl $($serviceUrl+'/users/'+$ID) -Authorization $authorizatoin -Body $(ConvertTo-Json $body) -ContentType $contentType
}

function Get-UserGroupList
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id+'/groups') -Authorization $authorizatoin -ContentType $contentType
}

function Get-UserSubscriptionList
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id+'/subscriptions') -Authorization $authorizatoin -ContentType $contentType
}

function Get-Groups
{
    return Get-ApiManagementResource -MethodUrl $($serviceUrl+'/groups') -Authorization $authorizatoin -ContentType $contentType
}

function Get-Group
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id) -Authorization $authorizatoin -ContentType $contentType
}

function Get-GroupUsers
{
   param
   (
     [System.String]
     $id
   )

    return Get-ApiManagementResource -MethodUrl $($serviceUrl+''+$id+'/users') -Authorization $authorizatoin -ContentType $contentType
}

function Get-Subscriptions
{
    return Get-ApiManagementResource -MethodUrl $($serviceUrl+'/subscriptions') -Authorization $authorizatoin -ContentType $contentType
}

Set-Variable -Name contentType -Value 'application/json'

Export-ModuleMember 'Add-Version'
Export-ModuleMember 'Get-ApiManagementResource'
Export-ModuleMember 'Get-ApiManagementResourceMetadata'
Export-ModuleMember 'Remove-ApiManagementResource'
Export-ModuleMember 'Update-ApiManagementResource'
Export-ModuleMember 'Invoke-ApiManagementResource'
Export-ModuleMember 'Get-Subscriptions'
Export-ModuleMember 'Add-User'
Export-ModuleMember 'Remove-User'
Export-ModuleMember 'Get-Users'
Export-ModuleMember 'Get-User'
Export-ModuleMember 'Get-UserGroupList'
Export-ModuleMember 'Get-UserSubscriptionList'
Export-ModuleMember 'Get-Products'
Export-ModuleMember 'Get-Product'
Export-ModuleMember 'Get-ProductMetadata'
Export-ModuleMember 'Get-ProductApiList'
Export-ModuleMember 'Get-Groups'
Export-ModuleMember 'Get-Group'
Export-ModuleMember 'Get-GroupUsers'
Export-ModuleMember 'Get-API'

Release Note

This is my preliminary attempt at using the API Management REST APIs for Automation. This script is a great starting point for those who wish to follow the same path. The code is available on GitHub https://github.com/brisebois/Brisebois.Azure.PowerShell

My first impression of these APIs is that it’s discoverable, well documented and easy to use from PowerShell.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s