/** * API 통신 유틸리티 */ class API { constructor() { this.baseURL = 'http://localhost:24102/api'; this.token = localStorage.getItem('access_token'); } // 토큰 설정 setToken(token) { this.token = token; if (token) { localStorage.setItem('access_token', token); } else { localStorage.removeItem('access_token'); } } // 기본 요청 헤더 getHeaders() { const headers = { 'Content-Type': 'application/json', }; if (this.token) { headers['Authorization'] = `Bearer ${this.token}`; } return headers; } // GET 요청 async get(endpoint, params = {}) { const url = new URL(`${this.baseURL}${endpoint}`, window.location.origin); Object.keys(params).forEach(key => { if (params[key] !== null && params[key] !== undefined) { url.searchParams.append(key, params[key]); } }); const response = await fetch(url, { method: 'GET', headers: this.getHeaders(), }); return this.handleResponse(response); } // POST 요청 async post(endpoint, data = {}) { const response = await fetch(`${this.baseURL}${endpoint}`, { method: 'POST', headers: this.getHeaders(), body: JSON.stringify(data), }); return this.handleResponse(response); } // PUT 요청 async put(endpoint, data = {}) { const response = await fetch(`${this.baseURL}${endpoint}`, { method: 'PUT', headers: this.getHeaders(), body: JSON.stringify(data), }); return this.handleResponse(response); } // DELETE 요청 async delete(endpoint) { const response = await fetch(`${this.baseURL}${endpoint}`, { method: 'DELETE', headers: this.getHeaders(), }); return this.handleResponse(response); } // 파일 업로드 async uploadFile(endpoint, formData) { const headers = {}; if (this.token) { headers['Authorization'] = `Bearer ${this.token}`; } const response = await fetch(`${this.baseURL}${endpoint}`, { method: 'POST', headers: headers, body: formData, }); return this.handleResponse(response); } // 응답 처리 async handleResponse(response) { if (response.status === 401) { // 토큰 만료 또는 인증 실패 this.setToken(null); window.location.reload(); throw new Error('인증이 필요합니다'); } if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || `HTTP ${response.status}`); } const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { return await response.json(); } return await response.text(); } // 인증 관련 API async login(email, password) { return await this.post('/auth/login', { email, password }); } async logout() { try { await this.post('/auth/logout'); } finally { this.setToken(null); } } async getCurrentUser() { return await this.get('/auth/me'); } async refreshToken(refreshToken) { return await this.post('/auth/refresh', { refresh_token: refreshToken }); } // 문서 관련 API async getDocuments(params = {}) { return await this.get('/documents/', params); } async getDocument(documentId) { return await this.get(`/documents/${documentId}`); } async uploadDocument(formData) { return await this.uploadFile('/documents/', formData); } async deleteDocument(documentId) { return await this.delete(`/documents/${documentId}`); } async getTags() { return await this.get('/documents/tags/'); } async createTag(tagData) { return await this.post('/documents/tags/', tagData); } // 하이라이트 관련 API async createHighlight(highlightData) { return await this.post('/highlights/', highlightData); } async getDocumentHighlights(documentId) { return await this.get(`/highlights/document/${documentId}`); } async updateHighlight(highlightId, data) { return await this.put(`/highlights/${highlightId}`, data); } async deleteHighlight(highlightId) { return await this.delete(`/highlights/${highlightId}`); } // 메모 관련 API async createNote(noteData) { return await this.post('/notes/', noteData); } async getNotes(params = {}) { return await this.get('/notes/', params); } async getDocumentNotes(documentId) { return await this.get(`/notes/document/${documentId}`); } async updateNote(noteId, data) { return await this.put(`/notes/${noteId}`, data); } async deleteNote(noteId) { return await this.delete(`/notes/${noteId}`); } async getPopularNoteTags() { return await this.get('/notes/tags/popular'); } // 책갈피 관련 API async createBookmark(bookmarkData) { return await this.post('/bookmarks/', bookmarkData); } async getBookmarks(params = {}) { return await this.get('/bookmarks/', params); } async getDocumentBookmarks(documentId) { return await this.get(`/bookmarks/document/${documentId}`); } async updateBookmark(bookmarkId, data) { return await this.put(`/bookmarks/${bookmarkId}`, data); } async deleteBookmark(bookmarkId) { return await this.delete(`/bookmarks/${bookmarkId}`); } // 검색 관련 API async search(params = {}) { return await this.get('/search/', params); } async getSearchSuggestions(query) { return await this.get('/search/suggestions', { q: query }); } // 사용자 관리 API async getUsers() { return await this.get('/users/'); } async createUser(userData) { return await this.post('/auth/create-user', userData); } async updateUser(userId, userData) { return await this.put(`/users/${userId}`, userData); } async deleteUser(userId) { return await this.delete(`/users/${userId}`); } async updateProfile(profileData) { return await this.put('/users/profile', profileData); } async changePassword(passwordData) { return await this.put('/auth/change-password', passwordData); } } // 전역 API 인스턴스 window.api = new API();