|
|
|
|
|
import { APP_CONFIG, getLoginUrl } from './app' |
|
|
|
|
|
|
|
|
export const API_PREFIX = APP_CONFIG.apiPrefix |
|
|
|
|
|
|
|
|
export function createApiUrl(path) { |
|
|
|
|
|
if (!path.startsWith('/')) { |
|
|
path = '/' + path |
|
|
} |
|
|
return API_PREFIX + path |
|
|
} |
|
|
|
|
|
|
|
|
export function getRequestConfig(token) { |
|
|
const config = { |
|
|
headers: { |
|
|
'Content-Type': 'application/json' |
|
|
} |
|
|
} |
|
|
|
|
|
if (token) { |
|
|
config.headers['Authorization'] = `Bearer ${token}` |
|
|
} |
|
|
|
|
|
return config |
|
|
} |
|
|
|
|
|
|
|
|
class ApiClient { |
|
|
constructor() { |
|
|
this.baseURL = API_PREFIX |
|
|
} |
|
|
|
|
|
|
|
|
getAuthToken() { |
|
|
const authToken = localStorage.getItem('authToken') |
|
|
return authToken || null |
|
|
} |
|
|
|
|
|
|
|
|
buildConfig(options = {}) { |
|
|
const config = { |
|
|
headers: { |
|
|
'Content-Type': 'application/json', |
|
|
...options.headers |
|
|
}, |
|
|
...options |
|
|
} |
|
|
|
|
|
|
|
|
const token = this.getAuthToken() |
|
|
if (token) { |
|
|
config.headers['Authorization'] = `Bearer ${token}` |
|
|
} |
|
|
|
|
|
return config |
|
|
} |
|
|
|
|
|
|
|
|
async handleResponse(response) { |
|
|
|
|
|
if (response.status === 401) { |
|
|
|
|
|
const currentPath = window.location.pathname + window.location.hash |
|
|
const isLoginPage = currentPath.includes('/login') || currentPath.endsWith('/') |
|
|
|
|
|
if (!isLoginPage) { |
|
|
localStorage.removeItem('authToken') |
|
|
|
|
|
window.location.href = getLoginUrl() |
|
|
} |
|
|
throw new Error('Unauthorized') |
|
|
} |
|
|
|
|
|
|
|
|
const contentType = response.headers.get('content-type') |
|
|
if (contentType && contentType.includes('application/json')) { |
|
|
const data = await response.json() |
|
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
|
|
|
const error = new Error(data.message || `HTTP ${response.status}`) |
|
|
|
|
|
error.response = { |
|
|
status: response.status, |
|
|
data: data |
|
|
} |
|
|
|
|
|
error.message = data.message || error.message |
|
|
throw error |
|
|
} |
|
|
|
|
|
return data |
|
|
} |
|
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`) |
|
|
} |
|
|
|
|
|
return response |
|
|
} |
|
|
|
|
|
|
|
|
async get(url, options = {}) { |
|
|
|
|
|
let fullUrl = createApiUrl(url) |
|
|
if (options.params) { |
|
|
const params = new URLSearchParams(options.params) |
|
|
fullUrl += '?' + params.toString() |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { params, ...configOptions } = options |
|
|
const config = this.buildConfig({ |
|
|
...configOptions, |
|
|
method: 'GET' |
|
|
}) |
|
|
|
|
|
try { |
|
|
const response = await fetch(fullUrl, config) |
|
|
return await this.handleResponse(response) |
|
|
} catch (error) { |
|
|
console.error('API GET Error:', error) |
|
|
throw error |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async post(url, data = null, options = {}) { |
|
|
const fullUrl = createApiUrl(url) |
|
|
const config = this.buildConfig({ |
|
|
...options, |
|
|
method: 'POST', |
|
|
body: data ? JSON.stringify(data) : undefined |
|
|
}) |
|
|
|
|
|
try { |
|
|
const response = await fetch(fullUrl, config) |
|
|
return await this.handleResponse(response) |
|
|
} catch (error) { |
|
|
console.error('API POST Error:', error) |
|
|
throw error |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async put(url, data = null, options = {}) { |
|
|
const fullUrl = createApiUrl(url) |
|
|
const config = this.buildConfig({ |
|
|
...options, |
|
|
method: 'PUT', |
|
|
body: data ? JSON.stringify(data) : undefined |
|
|
}) |
|
|
|
|
|
try { |
|
|
const response = await fetch(fullUrl, config) |
|
|
return await this.handleResponse(response) |
|
|
} catch (error) { |
|
|
console.error('API PUT Error:', error) |
|
|
throw error |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async patch(url, data = null, options = {}) { |
|
|
const fullUrl = createApiUrl(url) |
|
|
const config = this.buildConfig({ |
|
|
...options, |
|
|
method: 'PATCH', |
|
|
body: data ? JSON.stringify(data) : undefined |
|
|
}) |
|
|
|
|
|
try { |
|
|
const response = await fetch(fullUrl, config) |
|
|
return await this.handleResponse(response) |
|
|
} catch (error) { |
|
|
console.error('API PATCH Error:', error) |
|
|
throw error |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async delete(url, options = {}) { |
|
|
const fullUrl = createApiUrl(url) |
|
|
const { data, ...restOptions } = options |
|
|
|
|
|
const config = this.buildConfig({ |
|
|
...restOptions, |
|
|
method: 'DELETE', |
|
|
body: data ? JSON.stringify(data) : undefined |
|
|
}) |
|
|
|
|
|
try { |
|
|
const response = await fetch(fullUrl, config) |
|
|
return await this.handleResponse(response) |
|
|
} catch (error) { |
|
|
console.error('API DELETE Error:', error) |
|
|
throw error |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export const apiClient = new ApiClient() |
|
|
|