Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/backend/Shared/Providers/KrxOpenApiAdapter.cs
T

38 lines
2.5 KiB
C#

using System.Net;
using System.Net.Http.Headers;
namespace Kbx.Shared.Providers;
public sealed class KrxOpenApiAdapter(HttpClient http, IKbxProviderSecretStore secrets) : IKbxExternalProviderAdapter
{
public string ProviderId => "provider.krx.openapi";
public async Task<KbxProviderResult<string>> InvokeApprovedServiceAsync(KrxApprovedServiceRequest request, CancellationToken ct)
{
if (!request.ServiceUri.IsAbsoluteUri || request.ServiceUri.Scheme != Uri.UriSchemeHttps || !request.ServiceUri.Host.EndsWith(".krx.co.kr", StringComparison.OrdinalIgnoreCase))
return new(KbxProviderResultKind.PermanentFailure, Code:"KRX_SERVICE_URL_NOT_APPROVED", Message:"KRX 승인 서비스의 HTTPS URL만 사용할 수 있습니다.");
if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Post)
return new(KbxProviderResultKind.PermanentFailure, Code:"KRX_METHOD_NOT_ALLOWED", Message:"조회성 GET/POST만 허용됩니다.");
var key = await secrets.GetRequiredAsync("ExternalProviders:Krx:AuthKey", ct);
var uri = AppendQuery(request.ServiceUri, request.Query);
using var message = new HttpRequestMessage(request.Method, uri);
message.Headers.TryAddWithoutValidation("AUTH_KEY", key);
if (request.Method == HttpMethod.Post && request.Body is not null)
message.Content = new StringContent(request.Body, System.Text.Encoding.UTF8, "application/json");
using var response = await http.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, ct);
var body = await response.Content.ReadAsStringAsync(ct);
if (response.IsSuccessStatusCode) return new(KbxProviderResultKind.Success, body, HttpStatus:(int)response.StatusCode);
var transient = response.StatusCode is HttpStatusCode.RequestTimeout or (HttpStatusCode)429 || (int)response.StatusCode >= 500;
return new(transient ? KbxProviderResultKind.TransientFailure : KbxProviderResultKind.PermanentFailure, Code:$"HTTP_{(int)response.StatusCode}", Message:"KRX OPEN API 호출이 실패했습니다.", HttpStatus:(int)response.StatusCode);
}
private static Uri AppendQuery(Uri uri, IReadOnlyDictionary<string,string?> query)
{
if (query.Count == 0) return uri;
var parts = query.Where(x => x.Value is not null).Select(x => $"{Uri.EscapeDataString(x.Key)}={Uri.EscapeDataString(x.Value!)}");
var builder = new UriBuilder(uri) { Query = string.Join("&", parts) };
return builder.Uri;
}
}