apiClient.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { API_BASE_URL } from '../utils/constants';
  2. interface ApiResponse<T = any> {
  3. data: T;
  4. status: number;
  5. }
  6. class ApiClient {
  7. private baseURL: string;
  8. constructor(baseURL: string) {
  9. this.baseURL = baseURL;
  10. }
  11. private getAuthHeaders(): Record<string, string> {
  12. // V2 API key auth (primary)
  13. const apiKey = localStorage.getItem('kb_api_key');
  14. const activeTenantId = localStorage.getItem('kb_active_tenant_id');
  15. // Legacy JWT token (fallback, kept for compatibility during transition)
  16. const token = localStorage.getItem('authToken') || localStorage.getItem('token');
  17. const language = localStorage.getItem('userLanguage') || 'ja';
  18. return {
  19. 'Content-Type': 'application/json',
  20. 'x-user-language': language,
  21. ...(apiKey && { 'x-api-key': apiKey }),
  22. ...(activeTenantId && { 'x-tenant-id': activeTenantId }),
  23. ...(token && { Authorization: `Bearer ${token}` }),
  24. };
  25. }
  26. // New API call method, returns { data, status }
  27. async get<T = any>(url: string): Promise<ApiResponse<T>> {
  28. const response = await fetch(`${this.baseURL}${url}`, {
  29. method: 'GET',
  30. headers: this.getAuthHeaders(),
  31. });
  32. if (!response.ok) {
  33. const errorData = await response.json();
  34. throw new Error(errorData.message || 'Request failed');
  35. }
  36. const data = await response.json();
  37. return { data, status: response.status };
  38. }
  39. async post<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
  40. const response = await fetch(`${this.baseURL}${url}`, {
  41. method: 'POST',
  42. headers: this.getAuthHeaders(),
  43. body: body ? JSON.stringify(body) : undefined,
  44. });
  45. if (!response.ok) {
  46. const errorData = await response.json();
  47. throw new Error(errorData.message || 'Request failed');
  48. }
  49. const data = await response.json();
  50. return { data, status: response.status };
  51. }
  52. async put<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
  53. const response = await fetch(`${this.baseURL}${url}`, {
  54. method: 'PUT',
  55. headers: this.getAuthHeaders(),
  56. body: body ? JSON.stringify(body) : undefined,
  57. });
  58. if (!response.ok) {
  59. const errorData = await response.json();
  60. throw new Error(errorData.message || 'Request failed');
  61. }
  62. const data = await response.json();
  63. return { data, status: response.status };
  64. }
  65. async delete<T = any>(url: string): Promise<ApiResponse<T>> {
  66. const response = await fetch(`${this.baseURL}${url}`, {
  67. method: 'DELETE',
  68. headers: this.getAuthHeaders(),
  69. });
  70. if (!response.ok) {
  71. const errorData = await response.json();
  72. throw new Error(errorData.message || 'Request failed');
  73. }
  74. const data = await response.json();
  75. return { data, status: response.status };
  76. }
  77. // Legacy compatibility method — returns raw Response for streaming and other special cases
  78. async request(path: string, options: RequestInit = {}): Promise<Response> {
  79. const apiKey = localStorage.getItem('kb_api_key');
  80. const activeTenantId = localStorage.getItem('kb_active_tenant_id');
  81. const token = localStorage.getItem('authToken');
  82. const headers = new Headers(options.headers);
  83. if (apiKey) headers.set('x-api-key', apiKey);
  84. if (activeTenantId) headers.set('x-tenant-id', activeTenantId);
  85. if (token) headers.set('Authorization', `Bearer ${token}`);
  86. const language = localStorage.getItem('userLanguage') || 'ja';
  87. headers.set('x-user-language', language);
  88. let url = path;
  89. if (!path.startsWith('http')) {
  90. const cleanPath = path.startsWith('/') ? path : `/${path}`;
  91. url = `${this.baseURL}${cleanPath}`;
  92. }
  93. const response = await fetch(url, {
  94. ...options,
  95. headers,
  96. });
  97. if (response.status === 401) {
  98. localStorage.removeItem('kb_api_key');
  99. localStorage.removeItem('authToken');
  100. window.location.href = '/login';
  101. throw new Error('Unauthorized');
  102. }
  103. return response;
  104. }
  105. }
  106. export const apiClient = new ApiClient(API_BASE_URL);