| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import { API_BASE_URL } from '../utils/constants';
- interface ApiResponse<T = any> {
- data: T;
- status: number;
- }
- class ApiClient {
- private baseURL: string;
- constructor(baseURL: string) {
- this.baseURL = baseURL;
- }
- private getAuthHeaders(): Record<string, string> {
- // V2 API key auth (primary)
- const apiKey = localStorage.getItem('kb_api_key');
- const activeTenantId = localStorage.getItem('kb_active_tenant_id');
- // Legacy JWT token (fallback, kept for compatibility during transition)
- const token = localStorage.getItem('authToken') || localStorage.getItem('token');
- const language = localStorage.getItem('userLanguage') || 'ja';
- return {
- 'Content-Type': 'application/json',
- 'x-user-language': language,
- ...(apiKey && { 'x-api-key': apiKey }),
- ...(activeTenantId && { 'x-tenant-id': activeTenantId }),
- ...(token && { Authorization: `Bearer ${token}` }),
- };
- }
- private async handleResponse<T>(response: Response): Promise<ApiResponse<T>> {
- const text = await response.text();
- let data: any;
- try {
- data = text ? JSON.parse(text) : null;
- } catch (e) {
- data = null;
- }
- if (!response.ok) {
- throw new Error(data?.message || text || 'Request failed');
- }
- return { data: data as T, status: response.status };
- }
- // 新しい API 呼び出し方法、{ data, status } を返す
- async get<T = any>(url: string): Promise<ApiResponse<T>> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'GET',
- headers: this.getAuthHeaders(),
- });
- return this.handleResponse<T>(response);
- }
- async post<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'POST',
- headers: this.getAuthHeaders(),
- body: body ? JSON.stringify(body) : undefined,
- });
- return this.handleResponse<T>(response);
- }
- async put<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'PUT',
- headers: this.getAuthHeaders(),
- body: body ? JSON.stringify(body) : undefined,
- });
- return this.handleResponse<T>(response);
- }
- async patch<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'PATCH',
- headers: this.getAuthHeaders(),
- body: body ? JSON.stringify(body) : undefined,
- });
- return this.handleResponse<T>(response);
- }
- async delete<T = any>(url: string): Promise<ApiResponse<T>> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'DELETE',
- headers: this.getAuthHeaders(),
- });
- return this.handleResponse<T>(response);
- }
-
- // New methods for special formats
- async getBlob(url: string): Promise<Blob> {
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'GET',
- headers: this.getAuthHeaders(),
- });
- if (!response.ok) {
- throw new Error('Request failed');
- }
- return await response.blob();
- }
- async postMultipart<T = any>(url: string, formData: FormData): Promise<ApiResponse<T>> {
- const headers = this.getAuthHeaders();
- // Remove Content-Type to let the browser set it with the correct boundary
- delete headers['Content-Type'];
- const response = await fetch(`${this.baseURL}${url}`, {
- method: 'POST',
- headers,
- body: formData,
- });
- return this.handleResponse<T>(response);
- }
-
- // Legacy compatibility method — returns raw Response for streaming and other special cases
- async request(path: string, options: RequestInit = {}): Promise<Response> {
- const apiKey = localStorage.getItem('kb_api_key');
- const activeTenantId = localStorage.getItem('kb_active_tenant_id');
- const token = localStorage.getItem('authToken');
- const headers = new Headers(options.headers);
- if (apiKey) headers.set('x-api-key', apiKey);
- if (activeTenantId) headers.set('x-tenant-id', activeTenantId);
- if (token) headers.set('Authorization', `Bearer ${token}`);
- const language = localStorage.getItem('userLanguage') || 'ja';
- headers.set('x-user-language', language);
- let url = path;
- if (!path.startsWith('http')) {
- const cleanPath = path.startsWith('/') ? path : `/${path}`;
- url = `${this.baseURL}${cleanPath}`;
- }
- const response = await fetch(url, {
- ...options,
- headers,
- });
- if (response.status === 401) {
- localStorage.removeItem('kb_api_key');
- localStorage.removeItem('authToken');
- window.location.href = '/login';
- throw new Error('Unauthorized');
- }
- return response;
- }
- }
- export const apiClient = new ApiClient(API_BASE_URL);
|