Files
taxbaik/TaxBaik.Web/Services/ApiClient.cs
T
kjh2064 f8679cafcb
TaxBaik CI/CD / build-and-deploy (push) Failing after 41s
refactor: UI를 API 기반으로 리팩토링 - 비즈니스 로직과 View 완전 분리
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>
2026-06-26 22:56:41 +09:00

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
}
}
}