qcast-front/src/hooks/useAxios.js

233 lines
6.8 KiB
JavaScript

import axios, { Axios } from 'axios'
import { v4 as uuidv4 } from 'uuid'
const AxiosType = {
INTERNAL: 'Internal',
EXTERNAL: 'External',
}
// WRITE 요청 식별용. 호출자가 option.headers['X-Idempotency-Key'] 를 직접 지정하면 그대로 사용.
const WRITE_METHODS = ['post', 'put', 'patch']
/**
* axios 인스턴스 생성 후 반환
* @param {String} lang
* @returns http request instance - get, post, put, patch, delete (promise 접수사가 붙은 함수는 promise 반환)
*/
export function useAxios(lang = '') {
const getInstances = (url) => {
/**
* url이 http로 시작하면 외부 서버로 판단
*/
let type = AxiosType.INTERNAL
url.startsWith('http') ? (type = AxiosType.EXTERNAL) : ''
/**
* 내부 서버로 요청 시 lang 헤더 추가
*/
let headerValue = {
Accept: 'application/json',
}
url.startsWith('https') ? '' : (headerValue['lang'] = lang)
const instance = axios.create({
baseURL: type === AxiosType.INTERNAL ? process.env.NEXT_PUBLIC_API_SERVER_PATH : '',
headers: headerValue,
})
// WRITE 메서드에 X-Idempotency-Key 자동 부착 (override 가능)
instance.interceptors.request.use((config) => {
const method = (config.method || '').toLowerCase()
if (WRITE_METHODS.includes(method)) {
config.headers = config.headers || {}
if (!config.headers['X-Idempotency-Key']) {
config.headers['X-Idempotency-Key'] = uuidv4()
}
}
return config
})
return instance
}
// request 추가 로직
axios.interceptors.request.use((config) => {
return config
})
// response 추가 로직
axios.interceptors.response.use(
(response) => {
// 500 에러 로깅
if (response.status === 500) {
console.error('🚨 500 Error Response:', {
url: response.config.url,
method: response.config.method,
status: response.status,
statusText: response.statusText,
timestamp: new Date().toISOString(),
requestData: response.config.data,
responseData: response.data
})
}
return response
},
(error) => {
// 500 에러 및 기타 에러 로깅
if (error.response?.status === 500) {
console.error('🚨 500 Error Caught:', {
url: error.config?.url,
method: error.config?.method,
status: error.response?.status,
statusText: error.response?.statusText,
timestamp: new Date().toISOString(),
requestData: error.config?.data,
errorMessage: error.message,
errorStack: error.stack
})
} else {
console.error('🚨 API Error:', {
url: error.config?.url,
method: error.config?.method,
status: error.response?.status,
statusText: error.response?.statusText,
timestamp: new Date().toISOString(),
errorMessage: error.message
})
}
return Promise.reject(error)
}
)
const get = async ({ url, option = {} }) => {
return await getInstances(url)
.get(url, option)
.then((res) => res.data)
.catch((error) => {
// 500 에러는 재시도되므로 로깅을 줄임
const status = error?.response?.status
if (status === 500) {
console.warn('🔄 Server Error (500): Will retry...', url)
} else {
console.error('🚨 GET Error:', {
url,
method: 'GET',
timestamp: new Date().toISOString(),
errorMessage: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
config: error.config
})
}
throw error
})
}
const promiseGet = async ({ url, option = {} }) => {
return await getInstances(url).get(url, option)
}
const post = async ({ url, data, option = {} }) => {
return await getInstances(url)
.post(url, data, option)
.then((res) => res.data)
.catch((error) => {
console.error('🚨 POST Error:', {
url,
method: 'POST',
timestamp: new Date().toISOString(),
errorMessage: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
requestData: data,
config: error.config
})
throw error
})
}
const promisePost = async ({ url, data, option = {} }) => {
return await getInstances(url).post(url, data, option)
}
const put = async ({ url, data, option = {} }) => {
return await getInstances(url)
.put(url, data, option)
.then((res) => res.data)
.catch((error) => {
console.error('🚨 PUT Error:', {
url,
method: 'PUT',
timestamp: new Date().toISOString(),
errorMessage: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
requestData: data,
config: error.config
})
throw error
})
}
const promisePut = async ({ url, data, option = {} }) => {
return await getInstances(url).put(url, data, option)
}
const patch = async ({ url, data, option = {} }) => {
return await getInstances(url)
.patch(url, data, option)
.then((res) => res.data)
.catch((error) => {
console.error('🚨 PATCH Error:', {
url,
method: 'PATCH',
timestamp: new Date().toISOString(),
errorMessage: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
requestData: data,
config: error.config
})
throw error
})
}
const promisePatch = async ({ url, data, option = {} }) => {
return await getInstances(url).patch(url, data, option)
}
const del = async ({ url, option = {} }) => {
return await getInstances(url)
.delete(url, option)
.then((res) => res.data)
.catch((error) => {
console.error('🚨 DELETE Error:', {
url,
method: 'DELETE',
timestamp: new Date().toISOString(),
errorMessage: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
config: error.config
})
throw error
})
}
const promiseDel = async ({ url, option = {} }) => {
return await getInstances(url).delete(url, option)
}
const getFetcher = async (url) => {
const res = await get({ url })
return res
}
const postFetcher = async (url, arg, option = {}) => {
const res = await post({ url, data: arg, option })
return res
}
return { get, promiseGet, post, promisePost, put, promisePut, patch, promisePatch, del, promiseDel, getFetcher, postFetcher }
}