Примеры REST API для Azure DevOps

Сервисы Azure DevOps | Azure DevOps Server | Azure DevOps Server 2022

В этой статье приведены практические примеры REST API для служб Azure DevOps. В этих примерах демонстрируются распространенные операции, такие как извлечение проектов, управление рабочими элементами и использование шаблонов безопасной проверки подлинности с Microsoft Entra ID.

Это важно

Рассмотрите возможность использования более безопасных токенов Microsoft Entra вместо более рискованных персональных токенов доступа. Дополнительные сведения см. в разделе "Сокращение использования PAT". Просмотрите рекомендации по проверке подлинности , чтобы выбрать правильный механизм проверки подлинности для ваших потребностей.

Обзор проверки подлинности

Azure DevOps REST API поддерживают несколько методов проверки подлинности:

  • Microsoft Entra ID — рекомендуется для рабочих приложений (используемых в этих примерах).
  • Личные маркеры доступа (PATs) — простая проверка подлинности для сценариев и тестирования
  • Служебные принципалы и управляемые удостоверения — для автоматизированных сценариев

Подсказка

Вы можете использовать ИИ, чтобы помочь с этой задачей позже в этой статье или ознакомиться с включение помощи ИИ в Azure DevOps MCP Server, чтобы начать работу.

проверка подлинности Microsoft Entra ID

Для проверки подлинности идентификатора Microsoft Entra зарегистрируйте приложение и получите маркер доступа. Вот как пройти проверку подлинности с помощью библиотеки проверки подлинности Майкрософт (MSAL):

Сначала установите необходимый пакет NuGet:

<PackageReference Include="Microsoft.Identity.Client" Version="4.67.2" />
using Microsoft.Identity.Client;
using System.Net.Http.Headers;

public async Task<string> GetAccessTokenAsync()
{
    var app = PublicClientApplicationBuilder
        .Create("{your-client-id}")
        .WithAuthority("https://login.microsoftonline.com/{your-tenant-id}")
        .WithRedirectUri("http://localhost")
        .Build();

    var scopes = new[] { "https://app.vssps.visualstudio.com/.default" };
    
    try
    {
        var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
        return result.AccessToken;
    }
    catch (MsalException ex)
    {
        Console.WriteLine($"Authentication failed: {ex.Message}");
        throw;
    }
}

Примеры REST API

Список проектов (GET)

Получить все проекты в вашей организации:

Пример C#

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

public async Task<string> GetProjectsAsync(string organization)
{
    using var client = new HttpClient();
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    
    // Set base address and headers
    client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
    // Add authentication header
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
    
    try
    {
        var response = await client.GetAsync("_apis/projects?api-version=7.2");
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"Request failed: {ex.Message}");
        throw;
    }
}

Пример с PowerShell

# Install the Az.Accounts module if not already installed
# Install-Module -Name Az.Accounts -Force

# Sign in (interactive prompt) or use Connect-AzAccount -Identity for managed identity
Connect-AzAccount -TenantId "your-tenant-id"

$organization = "your-organization"

# Get access token for Azure DevOps
$token = Get-AzAccessToken -ResourceUrl "https://app.vssps.visualstudio.com/"

$headers = @{
    'Authorization' = "Bearer $($token.Token)"
    'Accept' = 'application/json'
}

$uri = "https://dev.azure.com/$organization/_apis/projects?api-version=7.2"

try {
    $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
    Write-Host "Retrieved $($response.count) projects"
    $response.value | ForEach-Object { Write-Host "- $($_.name)" }
}
catch {
    Write-Error "Failed to retrieve projects: $($_.Exception.Message)"
}

Создание рабочего элемента (POST)

Создайте новый рабочий элемент в проекте:

Пример C#

using System.Text;
using Newtonsoft.Json;

public async Task<string> CreateWorkItemAsync(string organization, string project)
{
    using var client = new HttpClient();
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    
    // Set base address and headers
    client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
    
    var patchOperations = new[]
    {
        new { op = "add", path = "/fields/System.Title", value = "Sample work item" },
        new { op = "add", path = "/fields/System.Description", value = "Created via REST API with Microsoft Entra ID" },
        new { op = "add", path = "/fields/System.Tags", value = "api; sample; entra-id" }
    };
    
    var json = JsonConvert.SerializeObject(patchOperations);
    var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
    
    try
    {
        var response = await client.PostAsync($"{project}/_apis/wit/workitems/$Task?api-version=7.2", content);
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"Request failed: {ex.Message}");
        throw;
    }
}

Пример с PowerShell

# Sign in (interactive prompt) or use Connect-AzAccount -Identity for managed identity
Connect-AzAccount -TenantId "your-tenant-id"

$organization = "your-organization"
$project = "your-project"

# Get access token for Azure DevOps
$token = Get-AzAccessToken -ResourceUrl "https://app.vssps.visualstudio.com/"

$headers = @{
    'Authorization' = "Bearer $($token.Token)"
    'Content-Type' = 'application/json-patch+json'
}

$body = @(
    @{
        op = "add"
        path = "/fields/System.Title"
        value = "Sample work item"
    },
    @{
        op = "add"
        path = "/fields/System.Description"
        value = "Created via REST API with Microsoft Entra ID"
    },
    @{
        op = "add"
        path = "/fields/System.Tags"
        value = "api; sample; entra-id"
    }
) | ConvertTo-Json

$uri = "https://dev.azure.com/$organization/$project/_apis/wit/workitems/`$Task?api-version=7.2"

try {
    $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $body
    Write-Host "Work item created with ID: $($response.id)"
}
catch {
    Write-Error "Failed to create work item: $($_.Exception.Message)"
}

Обновление рабочего элемента (PATCH)

Обновите состояние существующего рабочего элемента:

Пример C#

using System.Text;
using Newtonsoft.Json;

public async Task<string> UpdateWorkItemAsync(string organization, string project, int workItemId)
{
    using var client = new HttpClient();
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    
    // Set base address and headers
    client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
    
    var patchOperations = new[]
    {
        new
        {
            op = "add",
            path = "/fields/System.State",
            value = "In Progress"
        },
        new
        {
            op = "add",
            path = "/fields/System.AssignedTo",
            value = "user@example.com"
        }
    };
    
    var json = JsonConvert.SerializeObject(patchOperations);
    var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
    
    try
    {
        var response = await client.PatchAsync($"{project}/_apis/wit/workitems/{workItemId}?api-version=7.2", content);
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"Request failed: {ex.Message}");
        throw;
    }
}

Пример с PowerShell

# Sign in (interactive prompt) or use Connect-AzAccount -Identity for managed identity
Connect-AzAccount -TenantId "your-tenant-id"

$organization = "your-organization"
$project = "your-project"
$workItemId = 123  # Replace with actual work item ID

# Get access token for Azure DevOps
$token = Get-AzAccessToken -ResourceUrl "https://app.vssps.visualstudio.com/"

$headers = @{
    'Authorization' = "Bearer $($token.Token)"
    'Content-Type' = 'application/json-patch+json'
}

$body = @(
    @{
        op = "add"
        path = "/fields/System.State"
        value = "In Progress"
    },
    @{
        op = "add"
        path = "/fields/System.AssignedTo"
        value = "user@example.com"
    }
) | ConvertTo-Json

$uri = "https://dev.azure.com/$organization/$project/_apis/wit/workitems/$workItemId?api-version=7.2"

try {
    $response = Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $body
    Write-Host "Work item $workItemId updated successfully"
}
catch {
    Write-Error "Failed to update work item: $($_.Exception.Message)"
}

Удаление рабочего элемента (DELETE)

Удалите рабочий элемент из проекта:

Пример C#

public async Task<bool> DeleteWorkItemAsync(string organization, string project, int workItemId)
{
    using var client = new HttpClient();
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    
    // Set base address and headers
    client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
    
    try
    {
        var response = await client.DeleteAsync($"{project}/_apis/wit/workitems/{workItemId}?api-version=7.2");
        response.EnsureSuccessStatusCode();
        
        Console.WriteLine($"Work item {workItemId} deleted successfully");
        return true;
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"Request failed: {ex.Message}");
        throw;
    }
}

клиентские библиотеки .NET

Для приложений .NET используйте клиентские библиотеки Azure DevOps .NET для повышения безопасности типов и упрощения разработки.

Установка

Добавьте эти пакеты NuGet в проект:

<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.232.1" />
<PackageReference Include="Microsoft.VisualStudio.Services.Client" Version="19.232.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.2" />

Получите проекты с использованием .NET-клиента

using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.Identity.Client;

public async Task<IEnumerable<TeamProjectReference>> GetProjectsAsync(string organizationUrl)
{
    var uri = new Uri(organizationUrl);
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    var credentials = new VssOAuthAccessTokenCredential(entraIdAccessToken);
    
    using var connection = new VssConnection(uri, credentials);
    using var projectClient = connection.GetClient<ProjectHttpClient>();
    
    try
    {
        var projects = await projectClient.GetProjects();
        return projects;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error retrieving projects: {ex.Message}");
        throw;
    }
}

Создание рабочего элемента с помощью клиента .NET

using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Microsoft.Identity.Client;

public async Task<WorkItem> CreateWorkItemAsync(string organizationUrl, string project)
{
    var uri = new Uri(organizationUrl);
    
    // Get Microsoft Entra ID access token
    var entraIdAccessToken = await GetAccessTokenAsync();
    var credentials = new VssOAuthAccessTokenCredential(entraIdAccessToken);
    
    using var connection = new VssConnection(uri, credentials);
    using var witClient = connection.GetClient<WorkItemTrackingHttpClient>();
    
    var patchDocument = new JsonPatchDocument
    {
        new JsonPatchOperation
        {
            Operation = Operation.Add,
            Path = "/fields/System.Title",
            Value = "Sample work item created via .NET client with Microsoft Entra ID"
        },
        new JsonPatchOperation
        {
            Operation = Operation.Add,
            Path = "/fields/System.Description", 
            Value = "This work item was created using the Azure DevOps .NET client library with Microsoft Entra ID authentication"
        }
    };
    
    try
    {
        var workItem = await witClient.CreateWorkItemAsync(patchDocument, project, "Task");
        return workItem;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error creating work item: {ex.Message}");
        throw;
    }
}

Обработка ошибок

Всегда реализуйте правильную обработку ошибок в приложениях:

try
{
    var response = await client.GetAsync(requestUri);
    response.EnsureSuccessStatusCode();
    var content = await response.Content.ReadAsStringAsync();
    // Process successful response
}
catch (HttpRequestException ex)
{
    // Handle HTTP-related errors
    Console.WriteLine($"HTTP Error: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
    // Handle timeout
    Console.WriteLine("Request timed out");
}
catch (Exception ex)
{
    // Handle other errors
    Console.WriteLine($"Unexpected error: {ex.Message}");
}

Лучшие практики

  • Используйте идентификатор Microsoft Entra: используйте проверку подлинности идентификатора Microsoft Entra через PATs для рабочих приложений.
  • Использование HTTPS: всегда используйте безопасные подключения для вызовов API.
  • Ограничения скорости обработки: реализуйте логику повторных попыток с экспоненциальным обратным выходом.
  • Кэширование ответов: хранение часто запрашиваемых данных для уменьшения вызовов API.
  • Используйте определенные версии API: привяжите к конкретным версиям, чтобы избежать критических изменений.
  • Проверка входных данных: всегда проверяйте входные данные пользователей перед вызовами API.
  • Регистрируйте соответствующим образом: регистрируйте взаимодействия с API для отладки, но никогда не регистрируйте учетные данные.
  • Управление маркерами. Реализуйте правильную логику кэширования и обновления маркеров для маркеров идентификатора Microsoft Entra.

Создание кода REST API с помощью ИИ

При подключении сервера Azure DevOps MCP к агенту ИИ в режиме агента можно использовать запросы на естественном языке для создания кода REST API для Azure DevOps.

задачи Пример запроса
Список проектов Show me how to list all projects in my Azure DevOps organization using the REST API with Microsoft Entra ID authentication in C#
Создание рабочего элемента Write a REST API call to create a bug in Azure DevOps with proper authentication headers and JSON-patch body
Получение репозиториев Git Create a C# HttpClient example that retrieves Git repositories from Azure DevOps using a Bearer token from MSAL
Обновление полей рабочего элемента Show me how to update work item fields using the Azure DevOps REST API PATCH method with proper content type headers
Запрос с помощью WIQL Write a REST API call to execute a WIQL query against Azure DevOps and deserialize the response
Управление разбивкой на страницы Show me how to handle continuation tokens when listing Azure DevOps resources with the REST API in C#

Замечание

Режим агента и сервер MCP используют естественный язык, чтобы настроить эти запросы или задать дальнейшие вопросы, чтобы уточнить результаты.