What You Can Do With The Azure DevOps REST API

Azure category image

You can build customized dashboards in your own apps with the Azure DevOps REST API. Here is a detailed guide on how to do it.

If you are using Azure DevOps for your code, build pipelines, releases, or anything else, you can leverage a powerful REST API to query data. Other applications can use this data to build custom dashboards, for example. Here are some examples of use cases that can be accomplished via the API:

  • Trigger a release pipeline to deploy a new version of your code
  • See the log files of your most recent build pipeline runs that failed
  • Create work items in the backlog
  • Create, read, update, and delete wiki entries
  • Get a list of failing tests of the latest build pipeline run

The API is powerful. There’s almost nothing you can’t do!

Available endpoints

There are many endpoints available that you can query. To get an overview, visit the Microsoft documentation and scroll through the extensive list. Choose your endpoints, learn how to access them, and find out about any optional query parameters.

Incomplete list of categories that the Azure DevOps REST API supports in the preview version 7.1. Every category contains multiple endpoints to read and write data.
Incomplete list of categories that the Azure DevOps REST API supports in the preview version 7.1. Every category contains multiple endpoints to read and write data.

?

Hint

Fun fact: At the bottom of the page, there is a download link for a PDF file of the entire documentation, which currently consists of over 8,500 pages. That’s quite a massive documentation! ?

Authorization with a PAT

To ensure that nobody except authorized people access your resources, a Personal Access Token needs to be provided with every request against the API. During the creation of the PAT, you can define what operations are allowed when someone uses this token. You should treat it like a password and never share it with anyone. Here is how you create a token:

  1. Log into your Azure Devops account
  2. Click on your icon and select Personal Access Tokens
  3. Click the “New” button and assign the needed rights for that token
  4. Copy the token and store it on your computer

We can use Basic Authentication to authenticate our requests. To include the token in a request, the header field Authorization is required. The value of the header is BASIC, followed by the Base64 representation of the Personal Access Token. Here is a C# code example to add the header field and value:

public static async void GetProjects()
{
    try
    {
	var personalaccesstoken = "PAT_FROM_WEBSITE";

	using (HttpClient client = new HttpClient())
	{
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken))));

	    using (HttpResponseMessage response = await client.GetAsync(					"<https://dev.azure.com/{organization}/_apis/projects>"))
           {
	        response.EnsureSuccessStatusCode();
		string responseBody = await response.Content.ReadAsStringAsync();
		Console.WriteLine(responseBody);
	    }
	}
    }
    catch (Exception ex)
    {
 	Console.WriteLine(ex.ToString());
    }
}

With that, our requests are authorized to access the data we want. If this fails, make sure that your PAT has sufficients access rights for the resources you want. For further information about assembling requests and authorization click HERE.

Join my free Medium Newsletter!

Get an overview of my new Medium content with my monthly newsletter. Save time and pick what you like to read!

Handling responses

Query responses are delivered in JSON format, which is a good trade-off between simplicity and understandability for both machines and humans. However, transforming a JSON string into an object of your programming language can be cumbersome. Here is a tip to solve this problem: Quicktype.

Suppose you want to list all pipelines of a specific project. In that case, you can use this endpoint. To execute the desired GET query in the browser, fill the placeholders with the correct values. The browser will respond with a JSON object similar to this:

{
  "count": 4,
  "value": [
    {
      "_links": {
        "self": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/51?revision=2>"
        },
        "web": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_build/definition?definitionId=51>"
        }
      },
      "url": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/51?revision=2>",
      "id": 51,
      "revision": 2,
      "name": "Collect",
      "folder": "\\\\"
    },
    {
      "_links": {
        "self": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/50?revision=2>"
        },
        "web": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_build/definition?definitionId=50>"
        }
      },
      "url": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/50?revision=2>",
      "id": 50,
      "revision": 2,
      "name": "PR-Pipeline",
      "folder": "\\\\"
    },
    {
      "_links": {
        "self": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/53?revision=2>"
        },
        "web": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_build/definition?definitionId=53>"
        }
      },
      "url": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/53?revision=2>",
      "id": 53,
      "revision": 2,
      "name": "Prod",
      "folder": "\\\\"
    },
    {
      "_links": {
        "self": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/52?revision=2>"
        },
        "web": {
          "href": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_build/definition?definitionId=52>"
        }
      },
      "url": "<https://dev.azure.com/xmashallax/42b96a6f-7b74-4907-9d8f-685c9caa6023/_apis/pipelines/52?revision=2>",
      "id": 52,
      "revision": 2,
      "name": "Test",
      "folder": "\\\\"
    }
  ]
}

Now, head over to app.quicktype.io. Paste the JSON string into the editor, select your programming language, and set any additional settings if required. Quicktype will then generate a data class for you.

It’s not perfect by any means. However, even with its imperfections, using a tool like this will still be much faster than manually creating the class and mapping its properties. For Dart developers, I recommend using Dart Quicktype.

public class RunResult
{
    public long Count { get; set; }
    public List<Value> Value { get; set; }
}

public class Value
{
    [JsonPropertyName("_links")]
    public Links Links { get; set; }
    public TemplateParameters TemplateParameters { get; set; }
    public ValuePipeline Pipeline { get; set; }
    public string State { get; set; }
    public string Result { get; set; }
    public DateTimeOffset CreatedDate { get; set; }
    public DateTimeOffset FinishedDate { get; set; }
    public Uri Url { get; set; }
    public long Id { get; set; }
    public string Name { get; set; }
}

public class Links
{
    public PipelineWebClass Self { get; set; }
    public PipelineWebClass Web { get; set; }
    public PipelineWebClass PipelineWeb { get; set; }
    public PipelineWebClass Pipeline { get; set; }
}

public class PipelineWebClass
{
    public Uri Href { get; set; }
}

public class ValuePipeline
{
    public Uri Url { get; set; }
    public long Id { get; set; }
    public long Revision { get; set; }
    public string Name { get; set; }
    public string Folder { get; set; }
}

public class TemplateParameters
{
}

If you don’t need all properties in your result class, you can create another class that contains only a subset of the properties, or you can remove them from the generated class. However, be aware that removing properties may lead to runtime errors, depending on the serialization settings of your programming language. In some cases, every key-value pair of the JSON result must have a corresponding representation in a class.

Example endpoints

Now, it’s pretty straightforward. With the required data class, you can execute a request against the API and convert the returned JSON into an object of your programming language. This makes it easier to work with the data.

For inspiration, here are some endpoints that the API provides:

Here is a screenshot of my .NET MAUI app that uses the Azure DevOps REST API to display the status, date, build ID, and a direct link to the build overview page for each build result. This is a small dashboard that allows you to quickly see if something has failed.

Screenshot of my .NET MAUI app that uses the Azure Devops Rest API to show build results with status, date. build id, and a direct link the build overview page.
Screenshot of my .NET MAUI app that uses the Azure Devops Rest API to show build results with status, date. build id, and a direct link the build overview page.

It’s part of the workflow of my automated Medium newsletter. If you want to build your own, check out my article:

Conclusion

The Azure DevOps REST API has an easily understandable structure, is user-friendly, and offers a wide range of possibilities to interact with your projects. In my opinion, the documentation is outstanding and you should not have any trouble getting the data you need.

Related articles