Azure API Management

Inside scoop from the API Management team

Managing Versions and Revisions using the HTTP API

The new Versions and Revisions feature was designed to fit as seamlessly as possible into our existing management API.

From a high level perspective, working with a current Revision is identical to the way working with an API has always been. Working with a different Version of an API, is just like working with a different API. Each Version has its own apiId identifier. Working with a non-current revision just requires a little magic. Instead of just using the apiId of the current revision, there is an extra suffix ;rev=n where n is the revision number.

If you are accessing the API via ARM you will use this base URL:

https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.ApiManagement/service/{serviceName}/

and you will need a bearer token from ARM in your Authorization header. Using ArmClient is the easiest way to get a token for testing.

However, if you are using the classic service Management API, your base URL will be:

https://{serviceName}.management.azure-api.net/

You can get the required Authorization header from the Azure Portal for the API Management instance under Security->Management API.

The advantage of the ARM API is you can give non-admin access to the API, and there is an audit trail of operations. The only extra complication is the API response data is embedded in the standard ARM payload envelope. All of the scenarios described here do work via both APIs, but some are only illustrated for one API.

List of APIs and versions

When making a request for a list of APIs you will see current revisions of all versioned and non-versioned APIs. Non-current revisions do not show in this list.

GET {{baseUrl}}/apis?api-version=2017-01-01 HTTP/1.1
Authorization: {{authValue}}

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "value": [
        {
      "id": "/subscriptions/6b7f02d9-1f17-43e0-a02c-24e99753d14a/resourceGroups/Api-Default-East-US/providers/Microsoft.ApiManagement/service/conference/apis/5942d3b49ea6ed985e913bc4",
      "type": "Microsoft.ApiManagement/service/apis",
      "name": "5942d3b49ea6ed985e913bc4",
      "properties": {
        "displayName": "Big Conference API-v2",
        "apiRevision": "1",
        "description": "Sample hypermedia API running in an API App on App Service.",
        "path": "bigconf",
        "protocols": [
          "https"
        ],
        "authenticationSettings": null,
        "subscriptionKeyParameterNames": null,
        "isCurrent": true,
        "apiVersion": "v2",
        "apiVersionSet": {
          "id": "/subscriptions/6b7f02d9-1f17-43e0-a02c-24e99753d14a/resourceGroups/Api-Default-East-US/providers/Microsoft.ApiManagement/service/conference/api-version-sets/5e02bd74-4323-4531-b889-85ab4b51563e",
          "name": "Big Conference API",
          "description": null,
          "versioningScheme": "Segment",
          "versionQueryName": null,
          "versionHeaderName": null
        }
      }
    },
  ],
  ...
}

The apiVersion property will be empty for non-versioned APIs and original versions. i.e. The API that existed before it became versioned.

The apiRevision property will identify the revision number of the API and will be defaulted to 1 for all existing APIs. In this list the isCurrent property will always be true and in all cases is a read-only property.

The apiVersionSet object indicates which version set an API belongs to. Api Version sets define the versioning rules for all APIs in the version set.

Accessing a current revision

Interacting with a current revision works just as it has in the past:

GET {{baseUrl}}/apis/{{apiId}}?api-version=2017-03-01 HTTP/1.1
Authorization: {{authValue}}

Accessing a non-current revision

To access a non-current revision it is necessary to modify the apiId slightly by adding a revision suffix,

GET {{baseUrl}}/apis/5942d3b49ea6ed985e913bc4;rev=2?api-version=2017-03-01 HTTP/1.1
Authorization: {{authValue}}

This will enable accessing any non-current revision that is still marked as online. The API definition has a new boolean property isOnline.

Creating a new Revision

A revision can be created just like any other API. The only difference is the revision suffix added to the apiId. The first revision created for any apiId will be considered the current revision.

PUT {{classicBaseUrl}}/apis/myApiId;rev=1?api-version=2017-03-01
Authorization: {{authValue}}
Content-Type: application/json

{
  "name" : "My Api",
  "path" : "api",
  "serviceUrl" : "http://example.org",
  "protocols" : ["https"]
}

The rev parameter is represented as a matrix parameter to highlight the that a revision is just another API definition but that there is a relationship between the set of revisions with the same ApiId. A Revision is not a concept that is distinct from that of an API. It is simply an API with a special identifier.

Using PUT without a rev suffix will create a new API as revision 1, if it does not already exist.

Creating a Revision based on another

The easiest way to create an API Revision is based off an existing API revision. To do this, instead of passing the normal API contract payload, we send a special payload, which in the classic API is indicated with a new media type named application/vnd.ms-azure-apim.revisioninfo+json.

PUT {{classicBaseUrl}}/apis/myapiId;rev=2?api-version=2017-03-01
Authorization: {{authValue}}
Content-Type: application/vnd.ms-azure-apim.revisioninfo+json

{
      "sourceApiId":"/apis/myapiId",
      "apiRevisionDescription":"My new revision" 
}

Note that the target URL points to the new revision to be created and the sourceApiId is the path of the source Api Revision following the base path. In this case we are creating a revision of the current API.

In the Azure portal, the user interface ensures that the revisions are a linear sequence. i.e. adding a new revision creates a revision n+1 based on revision n. However, that is not constrained via the API. Be wary of straying from the linear path or you may find yourself losing updates.

Due to the way this operation works it likely will not be supported on Azure Deployment Templates. We are considering how best to support revisions in deployment templates. Stay tuned.

However, the response does conform to an ARM payload.

{
  "id": "/subscriptions/6b7f02d9-1f17-43e0-a02c-24e99753d14a/resourceGroups/Api-Default-East-US/providers/Microsoft.ApiManagement/service/conference/apis/55bae80192ff5c0314040001;rev=2",
  "type": "Microsoft.ApiManagement/service/apis",
  "name": "55bae80192ff5c0314040001;rev=2",
  "properties": {
    "displayName": "Echo API",
    "apiRevision": "2",
    "description": null,
    "serviceUrl": "http://echoapi.cloudapp.net/api",
    "path": "echo",
    "protocols": [
      "https"
    ],
    "authenticationSettings": {
      "oAuth2": null,
      "openid": null
    },
    "subscriptionKeyParameterNames": {
      "header": "Ocp-Apim-Subscription-Key",
      "query": "subscription-key"
    },
    "apiRevisionDescription": "My new revision"
  }
}

Creating Version from a revision

When changes need to be made to an API that a customer needs to opt into, a new Version of the API should be created.

New API versions have a different apiId but are associated to ApiVersionSet that is common to all versions of the API and contains the metadata to define the versioning scheme. Just as Revisions are specially identified API resources, so are Versions.

Creating a new API Version from an existing API Revision is very similar to creating a revision based on another revision. The major difference is the inclusion of the apiVersionSet object. If the apiVersionSet includes a valid id property, the API will added to an existing apiVersionSet. Otherwise a new apiVersionSet is created.

PUT {{classicBaseUrl}}/apis/{newApiId}
Content-Type: application/vnd.ms-azure-apim.revisioninfo+json

{
    "sourceApiId" : "/apis/{existingApiId[rev]}",
    "apiVersionName" : "v2",
    "apiVersionDescription" : "Description",
    "apiVersionSet" : {
        "versioningScheme" : "Segment"
    }
}

The apiVersionName is a required property and the versioningScheme must be one of Segment, Header or Query. If Header or Query versioning is selected then a headerParameterName or queryParameterName must be provided.

If Segment versioning scheme is used, then when calling your API exposed by Azure API Management the apiVersionName must appear in the segment following the Api suffix and prior to the Operation UrlTemplate.

Create a Versioned API from scratch

It is possible to create a new API definition that pre-defines what the versioning strategy is going to be. All that is required is to include the apiVersionSet in the API definition representation

PUT {{classicBaseUrl}}/apis/{{apiId}}?api-version=2017-03-01
Authorization: {{authValue}}
Content-Type: application/json

{
  "name" : "My Api",
  "path" : "api",
  "serviceUrl" : "http://example.org",
  "protocols" : ["https"]
  "apiVersionName" : "v1",
  "apiVersionDescription" : "Initial Version",
  "apiVersionSet" : {
      "versioningScheme" : "Segment"
  }
}

List of Revisions

To get a view of the set of revisions for a particular apiId you can make a request as follows.

GET https://{{baseUrl}}/apis/{{apiId}}/revisions?api-version=2017-03-01 HTTP/1.1
Authorization: {{authValue}}

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "value": [
    {
      "apiId": "/apis/echo-api;rev=2",
      "apiRevision": "2",
      "createdDateTime": "2017-05-30T18:32:06.463",
      "updatedDateTime": "2017-05-30T18:32:06.463",
      "description": "its a test",
      "privateUrl": "/api;rev=2/",
      "isOnline": true,
      "isCurrent": false
    },
    {
      "apiId": "/apis/echo-api;rev=1",
      "apiRevision": "1",
      "createdDateTime": "2017-05-30T00:21:33.037",
      "updatedDateTime": "2017-05-30T00:21:33.037",
      "description": null,
      "privateUrl": null,
      "isOnline": true,
      "isCurrent": true
    }
  ],
  "count": 2,
  "nextLink": null
}

The returned representation is simply a read-only summary view of information about the revisions.

Delete all the Revisions

Despite having said that the .../revisions resource is read-only it can be used to quickly delete all the revisions associated to an apiId.

DELETE {{baseUrl}}/apis/{{apiId}}/revisions?api-version=2017-03-01 HTTP/1.1
If-match: *
Authorization: {{authValue}}

Create a Release of a Revision

At any one time, there is only one revision for each API that is marked as the current revision. The Api representation contains an isCurrent flag to indicate if the revision is current. This is a read-only attribute. In order to change which Revision is current, you must create a release resource. The request payload should identify the API revision that is to become current.

PUT {{classicBaseUrl}}/apis/{{apiId}}/releases/{{releaseId}}?api-version=2017-03-01 HTTP/1.1
Authorization: {{authValue}}
Content-Type: application/json

{
  "apiId" : "/apis/echo-api;rev=2",
  "notes" : "Let's release it"
}

The notes included here will be displayed in the release notes on the developer portal. It is an optional property. To rollback a release revision, simply create a new release that targets the previous revision and it will become current once again.

Get Release notes for an API

You can retrieve the set of release notes for an API with the following request:

GET {{baseUrl}}/apis/{{apiId}}/releases?api-version=2017-03-01 HTTP/1.1
Authorization: {{authValue}}

Summary

Our implementation of Versions and Revisions is currently in preview and so these APIs are subject to change based on your feedback. So, let us know what you think. What do you like? What don’t you like? Which parts could use clarifying? Are we missing APIs? Give it try and let us know.