f8679cafcb
TaxBaik CI/CD / build-and-deploy (push) Failing after 41s
1️⃣ HttpClient 서비스 추가 - IApiClient 인터페이스 구현 - GET, POST, PUT, DELETE 메서드 - JWT 토큰 자동 관리 - /taxbaik/api 경로 자동 처리 2️⃣ Razor Pages 리팩토링 - Pages/Index.cshtml.cs: API /api/blog 호출 - Pages/Blog/Index.cshtml.cs: API /api/blog, /api/category 호출 - Pages/Contact.cshtml.cs: API /api/inquiry 호출 - Service 의존성 제거 3️⃣ Blazor Components 리팩토링 - Login.razor: API /api/auth/login 호출로 변경 - BlogList.razor: API /api/blog/admin/all 호출로 변경 - Service 의존성 제거 아키텍처: View (Razor Pages + Blazor) ↓ HttpClient Controllers (REST API) ↓ Services (비즈니스 로직) ↓ Repository (DB) 테스트 결과: ✅ 홈페이지: 200 OK ✅ 블로그 페이지: 200 OK ✅ 문의 페이지: 200 OK ✅ 로그인 페이지: 200 OK ✅ API 엔드포인트 모두 작동 장점: • UI 리뉴얼 시 API 변경 불필요 • 모바일앱, 데스크톱 클라이언트 추가 가능 • 비즈니스 로직과 UI 완전 독립 • 테스트 가능한 구조 완성 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
102 lines
2.9 KiB
C#
102 lines
2.9 KiB
C#
namespace TaxBaik.Web.Services;
|
|
|
|
using System.Text.Json;
|
|
|
|
public interface IApiClient
|
|
{
|
|
Task<T?> GetAsync<T>(string endpoint);
|
|
Task<T?> PostAsync<T>(string endpoint, object data);
|
|
Task<T?> PutAsync<T>(string endpoint, object data);
|
|
Task DeleteAsync(string endpoint);
|
|
Task SetAuthToken(string? token);
|
|
}
|
|
|
|
public class ApiClient : IApiClient
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private string? _authToken;
|
|
|
|
public ApiClient(HttpClient httpClient)
|
|
{
|
|
_httpClient = httpClient;
|
|
}
|
|
|
|
public async Task SetAuthToken(string? token)
|
|
{
|
|
_authToken = token;
|
|
if (token != null)
|
|
_httpClient.DefaultRequestHeaders.Authorization = new("Bearer", token);
|
|
else
|
|
_httpClient.DefaultRequestHeaders.Authorization = null;
|
|
}
|
|
|
|
public async Task<T?> GetAsync<T>(string endpoint)
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync($"/taxbaik/api/{endpoint}");
|
|
if (!response.IsSuccessStatusCode)
|
|
return default;
|
|
|
|
var content = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<T>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
}
|
|
catch
|
|
{
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public async Task<T?> PostAsync<T>(string endpoint, object data)
|
|
{
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(data);
|
|
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
|
|
var response = await _httpClient.PostAsync($"/taxbaik/api/{endpoint}", content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return default;
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<T>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
}
|
|
catch
|
|
{
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public async Task<T?> PutAsync<T>(string endpoint, object data)
|
|
{
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(data);
|
|
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
|
|
var response = await _httpClient.PutAsync($"/taxbaik/api/{endpoint}", content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return default;
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<T>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
}
|
|
catch
|
|
{
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public async Task DeleteAsync(string endpoint)
|
|
{
|
|
try
|
|
{
|
|
await _httpClient.DeleteAsync($"/taxbaik/api/{endpoint}");
|
|
}
|
|
catch
|
|
{
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|