Skip to content

Refactors APIC plugins #758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 237 additions & 0 deletions dev-proxy-plugins/ApiCenter/ApiCenterClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Diagnostics.Tracing;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Azure.Core;
using Azure.Core.Diagnostics;
using Azure.Identity;
using Microsoft.DevProxy.Abstractions;
using Microsoft.Extensions.Logging;

namespace Microsoft.DevProxy.Plugins.RequestLogs.ApiCenter;

internal class ApiCenterClientConfiguration
{
public string SubscriptionId { get; set; } = "";
public string ResourceGroupName { get; set; } = "";
public string ServiceName { get; set; } = "";
public string WorkspaceName { get; set; } = "default";
}

internal class ApiCenterClient
{
private readonly ApiCenterClientConfiguration _configuration;
private readonly ILogger _logger;
private readonly TokenCredential _credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions()
{
ExcludeInteractiveBrowserCredential = true,
// fails on Ubuntu
ExcludeSharedTokenCacheCredential = true
});
private readonly HttpClient _httpClient;
private readonly AuthenticationDelegatingHandler _authenticationHandler;
private readonly string[] _scopes = ["https://management.azure.com/.default"];

internal ApiCenterClient(ApiCenterClientConfiguration configuration, ILogger logger)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}

if (string.IsNullOrEmpty(configuration.SubscriptionId))
{
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.SubscriptionId)} in the configuration.");
}
if (string.IsNullOrEmpty(configuration.ResourceGroupName))
{
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.ResourceGroupName)} in the configuration.");
}
if (string.IsNullOrEmpty(configuration.ServiceName))
{
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.ServiceName)} in the configuration.");
}
if (string.IsNullOrEmpty(configuration.WorkspaceName))
{
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.WorkspaceName)} in the configuration.");
}

// load configuration from env vars
if (configuration.SubscriptionId.StartsWith('@'))
{
configuration.SubscriptionId = Environment.GetEnvironmentVariable(configuration.SubscriptionId[1..]) ?? configuration.SubscriptionId;
}
if (configuration.ResourceGroupName.StartsWith('@'))
{
configuration.ResourceGroupName = Environment.GetEnvironmentVariable(configuration.ResourceGroupName[1..]) ?? configuration.ResourceGroupName;
}
if (configuration.ServiceName.StartsWith('@'))
{
configuration.ServiceName = Environment.GetEnvironmentVariable(configuration.ServiceName[1..]) ?? configuration.ServiceName;
}
if (configuration.WorkspaceName.StartsWith('@'))
{
configuration.WorkspaceName = Environment.GetEnvironmentVariable(configuration.WorkspaceName[1..]) ?? configuration.WorkspaceName;
}

_configuration = configuration;
_logger = logger;

_authenticationHandler = new AuthenticationDelegatingHandler(_credential, _scopes)
{
InnerHandler = new HttpClientHandler()
};
_httpClient = new HttpClient(_authenticationHandler);

if (_logger.IsEnabled(LogLevel.Debug) == true)
{
_ = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose);
}
}

internal Task<string?> GetAccessToken(CancellationToken cancellationToken)
{
return _authenticationHandler.GetAccessToken(cancellationToken);
}

internal async Task<Api[]?> GetApis()
{
_logger.LogInformation("Loading APIs from API Center...");

var res = await _httpClient.GetStringAsync($"https://management.azure.com/subscriptions/{_configuration.SubscriptionId}/resourceGroups/{_configuration.ResourceGroupName}/providers/Microsoft.ApiCenter/services/{_configuration.ServiceName}/workspaces/{_configuration.WorkspaceName}/apis?api-version=2024-03-01");
var collection = JsonSerializer.Deserialize<Collection<Api>>(res, ProxyUtils.JsonSerializerOptions);
if (collection is null || collection.Value is null)
{
return null;
}
else
{
return collection.Value;
}
}

internal async Task<Api?> PutApi(Api api, string apiName)
{
var content = new StringContent(JsonSerializer.Serialize(api, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
var res = await _httpClient.PutAsync($"https://management.azure.com/subscriptions/{_configuration.SubscriptionId}/resourceGroups/{_configuration.ResourceGroupName}/providers/Microsoft.ApiCenter/services/{_configuration.ServiceName}/workspaces/{_configuration.WorkspaceName}/apis/{apiName}?api-version=2024-03-01", content);

var resContent = await res.Content.ReadAsStringAsync();
_logger.LogDebug(resContent);

if (res.IsSuccessStatusCode)
{
return JsonSerializer.Deserialize<Api>(resContent, ProxyUtils.JsonSerializerOptions);
}
else
{
return null;
}
}

internal async Task<ApiDeployment[]?> GetDeployments(string apiId)
{
_logger.LogDebug("Loading API deployments for {apiName}...", apiId);

var res = await _httpClient.GetStringAsync($"https://management.azure.com{apiId}/deployments?api-version=2024-03-01");
var collection = JsonSerializer.Deserialize<Collection<ApiDeployment>>(res, ProxyUtils.JsonSerializerOptions);
if (collection is null || collection.Value is null)
{
return null;
}
else
{
return collection.Value;
}
}

internal async Task<ApiVersion[]?> GetVersions(string apiId)
{
_logger.LogDebug("Loading API versions for {apiName}...", apiId);

var res = await _httpClient.GetStringAsync($"https://management.azure.com{apiId}/versions?api-version=2024-03-01");
var collection = JsonSerializer.Deserialize<Collection<ApiVersion>>(res, ProxyUtils.JsonSerializerOptions);
if (collection is null || collection.Value is null)
{
return null;
}
else
{
return collection.Value;
}
}

internal async Task<ApiVersion?> PutVersion(ApiVersion apiVersion, string apiId, string apiName)
{
var content = new StringContent(JsonSerializer.Serialize(apiVersion, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
var res = await _httpClient.PutAsync($"https://management.azure.com{apiId}/versions/{apiName}?api-version=2024-03-01", content);

var resContent = await res.Content.ReadAsStringAsync();
_logger.LogDebug(resContent);

if (res.IsSuccessStatusCode)
{
return JsonSerializer.Deserialize<ApiVersion>(resContent, ProxyUtils.JsonSerializerOptions);
}
else
{
return null;
}
}

internal async Task<ApiDefinition[]?> GetDefinitions(string versionId)
{
_logger.LogDebug("Loading API definitions for version {id}...", versionId);

var res = await _httpClient.GetStringAsync($"https://management.azure.com{versionId}/definitions?api-version=2024-03-01");
var collection = JsonSerializer.Deserialize<Collection<ApiDefinition>>(res, ProxyUtils.JsonSerializerOptions);
if (collection is null || collection.Value is null)
{
return null;
}
else
{
return collection.Value;
}
}

internal async Task<ApiDefinition?> GetDefinition(string definitionId)
{
_logger.LogDebug("Loading API definition {id}...", definitionId);

var res = await _httpClient.GetStringAsync($"https://management.azure.com{definitionId}?api-version=2024-03-01");
return JsonSerializer.Deserialize<ApiDefinition>(res, ProxyUtils.JsonSerializerOptions);
}

internal async Task<ApiDefinition?> PutDefinition(ApiDefinition apiDefinition, string apiVersionId, string definitionName)
{
var content = new StringContent(JsonSerializer.Serialize(apiDefinition, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
var res = await _httpClient.PutAsync($"https://management.azure.com{apiVersionId}/definitions/{definitionName}?api-version=2024-03-01", content);

var resContent = await res.Content.ReadAsStringAsync();
_logger.LogDebug(resContent);

if (res.IsSuccessStatusCode)
{
return JsonSerializer.Deserialize<ApiDefinition>(resContent, ProxyUtils.JsonSerializerOptions);
}
else
{
return null;
}
}

internal async Task<HttpResponseMessage> PostImportSpecification(ApiSpecImport apiSpecImport, string definitionId)
{
var content = new StringContent(JsonSerializer.Serialize(apiSpecImport, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
return await _httpClient.PostAsync($"https://management.azure.com{definitionId}/importSpecification?api-version=2024-03-01", content);
}

internal async Task<ApiSpecExportResult?> PostExportSpecification(string definitionId)
{
var definitionRes = await _httpClient.PostAsync($"https://management.azure.com{definitionId}/exportSpecification?api-version=2024-03-01", null);
return await definitionRes.Content.ReadFromJsonAsync<ApiSpecExportResult>();
}
}
Loading