Skip to content

Commit bdae98f

Browse files
Refactors APIC plugins (#758)
1 parent be8598c commit bdae98f

File tree

8 files changed

+849
-799
lines changed

8 files changed

+849
-799
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Diagnostics.Tracing;
5+
using System.Net.Http.Json;
6+
using System.Text;
7+
using System.Text.Json;
8+
using Azure.Core;
9+
using Azure.Core.Diagnostics;
10+
using Azure.Identity;
11+
using Microsoft.DevProxy.Abstractions;
12+
using Microsoft.Extensions.Logging;
13+
14+
namespace Microsoft.DevProxy.Plugins.RequestLogs.ApiCenter;
15+
16+
internal class ApiCenterClientConfiguration
17+
{
18+
public string SubscriptionId { get; set; } = "";
19+
public string ResourceGroupName { get; set; } = "";
20+
public string ServiceName { get; set; } = "";
21+
public string WorkspaceName { get; set; } = "default";
22+
}
23+
24+
internal class ApiCenterClient
25+
{
26+
private readonly ApiCenterClientConfiguration _configuration;
27+
private readonly ILogger _logger;
28+
private readonly TokenCredential _credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions()
29+
{
30+
ExcludeInteractiveBrowserCredential = true,
31+
// fails on Ubuntu
32+
ExcludeSharedTokenCacheCredential = true
33+
});
34+
private readonly HttpClient _httpClient;
35+
private readonly AuthenticationDelegatingHandler _authenticationHandler;
36+
private readonly string[] _scopes = ["https://management.azure.com/.default"];
37+
38+
internal ApiCenterClient(ApiCenterClientConfiguration configuration, ILogger logger)
39+
{
40+
if (configuration is null)
41+
{
42+
throw new ArgumentNullException(nameof(configuration));
43+
}
44+
45+
if (string.IsNullOrEmpty(configuration.SubscriptionId))
46+
{
47+
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.SubscriptionId)} in the configuration.");
48+
}
49+
if (string.IsNullOrEmpty(configuration.ResourceGroupName))
50+
{
51+
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.ResourceGroupName)} in the configuration.");
52+
}
53+
if (string.IsNullOrEmpty(configuration.ServiceName))
54+
{
55+
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.ServiceName)} in the configuration.");
56+
}
57+
if (string.IsNullOrEmpty(configuration.WorkspaceName))
58+
{
59+
throw new ArgumentException($"Specify {nameof(ApiCenterClientConfiguration.WorkspaceName)} in the configuration.");
60+
}
61+
62+
// load configuration from env vars
63+
if (configuration.SubscriptionId.StartsWith('@'))
64+
{
65+
configuration.SubscriptionId = Environment.GetEnvironmentVariable(configuration.SubscriptionId[1..]) ?? configuration.SubscriptionId;
66+
}
67+
if (configuration.ResourceGroupName.StartsWith('@'))
68+
{
69+
configuration.ResourceGroupName = Environment.GetEnvironmentVariable(configuration.ResourceGroupName[1..]) ?? configuration.ResourceGroupName;
70+
}
71+
if (configuration.ServiceName.StartsWith('@'))
72+
{
73+
configuration.ServiceName = Environment.GetEnvironmentVariable(configuration.ServiceName[1..]) ?? configuration.ServiceName;
74+
}
75+
if (configuration.WorkspaceName.StartsWith('@'))
76+
{
77+
configuration.WorkspaceName = Environment.GetEnvironmentVariable(configuration.WorkspaceName[1..]) ?? configuration.WorkspaceName;
78+
}
79+
80+
_configuration = configuration;
81+
_logger = logger;
82+
83+
_authenticationHandler = new AuthenticationDelegatingHandler(_credential, _scopes)
84+
{
85+
InnerHandler = new HttpClientHandler()
86+
};
87+
_httpClient = new HttpClient(_authenticationHandler);
88+
89+
if (_logger.IsEnabled(LogLevel.Debug) == true)
90+
{
91+
_ = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose);
92+
}
93+
}
94+
95+
internal Task<string?> GetAccessToken(CancellationToken cancellationToken)
96+
{
97+
return _authenticationHandler.GetAccessToken(cancellationToken);
98+
}
99+
100+
internal async Task<Api[]?> GetApis()
101+
{
102+
_logger.LogInformation("Loading APIs from API Center...");
103+
104+
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");
105+
var collection = JsonSerializer.Deserialize<Collection<Api>>(res, ProxyUtils.JsonSerializerOptions);
106+
if (collection is null || collection.Value is null)
107+
{
108+
return null;
109+
}
110+
else
111+
{
112+
return collection.Value;
113+
}
114+
}
115+
116+
internal async Task<Api?> PutApi(Api api, string apiName)
117+
{
118+
var content = new StringContent(JsonSerializer.Serialize(api, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
119+
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);
120+
121+
var resContent = await res.Content.ReadAsStringAsync();
122+
_logger.LogDebug(resContent);
123+
124+
if (res.IsSuccessStatusCode)
125+
{
126+
return JsonSerializer.Deserialize<Api>(resContent, ProxyUtils.JsonSerializerOptions);
127+
}
128+
else
129+
{
130+
return null;
131+
}
132+
}
133+
134+
internal async Task<ApiDeployment[]?> GetDeployments(string apiId)
135+
{
136+
_logger.LogDebug("Loading API deployments for {apiName}...", apiId);
137+
138+
var res = await _httpClient.GetStringAsync($"https://management.azure.com{apiId}/deployments?api-version=2024-03-01");
139+
var collection = JsonSerializer.Deserialize<Collection<ApiDeployment>>(res, ProxyUtils.JsonSerializerOptions);
140+
if (collection is null || collection.Value is null)
141+
{
142+
return null;
143+
}
144+
else
145+
{
146+
return collection.Value;
147+
}
148+
}
149+
150+
internal async Task<ApiVersion[]?> GetVersions(string apiId)
151+
{
152+
_logger.LogDebug("Loading API versions for {apiName}...", apiId);
153+
154+
var res = await _httpClient.GetStringAsync($"https://management.azure.com{apiId}/versions?api-version=2024-03-01");
155+
var collection = JsonSerializer.Deserialize<Collection<ApiVersion>>(res, ProxyUtils.JsonSerializerOptions);
156+
if (collection is null || collection.Value is null)
157+
{
158+
return null;
159+
}
160+
else
161+
{
162+
return collection.Value;
163+
}
164+
}
165+
166+
internal async Task<ApiVersion?> PutVersion(ApiVersion apiVersion, string apiId, string apiName)
167+
{
168+
var content = new StringContent(JsonSerializer.Serialize(apiVersion, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
169+
var res = await _httpClient.PutAsync($"https://management.azure.com{apiId}/versions/{apiName}?api-version=2024-03-01", content);
170+
171+
var resContent = await res.Content.ReadAsStringAsync();
172+
_logger.LogDebug(resContent);
173+
174+
if (res.IsSuccessStatusCode)
175+
{
176+
return JsonSerializer.Deserialize<ApiVersion>(resContent, ProxyUtils.JsonSerializerOptions);
177+
}
178+
else
179+
{
180+
return null;
181+
}
182+
}
183+
184+
internal async Task<ApiDefinition[]?> GetDefinitions(string versionId)
185+
{
186+
_logger.LogDebug("Loading API definitions for version {id}...", versionId);
187+
188+
var res = await _httpClient.GetStringAsync($"https://management.azure.com{versionId}/definitions?api-version=2024-03-01");
189+
var collection = JsonSerializer.Deserialize<Collection<ApiDefinition>>(res, ProxyUtils.JsonSerializerOptions);
190+
if (collection is null || collection.Value is null)
191+
{
192+
return null;
193+
}
194+
else
195+
{
196+
return collection.Value;
197+
}
198+
}
199+
200+
internal async Task<ApiDefinition?> GetDefinition(string definitionId)
201+
{
202+
_logger.LogDebug("Loading API definition {id}...", definitionId);
203+
204+
var res = await _httpClient.GetStringAsync($"https://management.azure.com{definitionId}?api-version=2024-03-01");
205+
return JsonSerializer.Deserialize<ApiDefinition>(res, ProxyUtils.JsonSerializerOptions);
206+
}
207+
208+
internal async Task<ApiDefinition?> PutDefinition(ApiDefinition apiDefinition, string apiVersionId, string definitionName)
209+
{
210+
var content = new StringContent(JsonSerializer.Serialize(apiDefinition, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
211+
var res = await _httpClient.PutAsync($"https://management.azure.com{apiVersionId}/definitions/{definitionName}?api-version=2024-03-01", content);
212+
213+
var resContent = await res.Content.ReadAsStringAsync();
214+
_logger.LogDebug(resContent);
215+
216+
if (res.IsSuccessStatusCode)
217+
{
218+
return JsonSerializer.Deserialize<ApiDefinition>(resContent, ProxyUtils.JsonSerializerOptions);
219+
}
220+
else
221+
{
222+
return null;
223+
}
224+
}
225+
226+
internal async Task<HttpResponseMessage> PostImportSpecification(ApiSpecImport apiSpecImport, string definitionId)
227+
{
228+
var content = new StringContent(JsonSerializer.Serialize(apiSpecImport, ProxyUtils.JsonSerializerOptions), Encoding.UTF8, "application/json");
229+
return await _httpClient.PostAsync($"https://management.azure.com{definitionId}/importSpecification?api-version=2024-03-01", content);
230+
}
231+
232+
internal async Task<ApiSpecExportResult?> PostExportSpecification(string definitionId)
233+
{
234+
var definitionRes = await _httpClient.PostAsync($"https://management.azure.com{definitionId}/exportSpecification?api-version=2024-03-01", null);
235+
return await definitionRes.Content.ReadFromJsonAsync<ApiSpecExportResult>();
236+
}
237+
}

0 commit comments

Comments
 (0)