이번 포스트에서는 axios 관련 객체에 대해서 좀 더 살펴보자.
axios 관련 객체
axios instance
제공된 axios 객체 를 이용하면 zero base에서 모든 설정을 해줘야 한다. 만약 우리 프로젝트에서는 "요청하는 서버(url)가 한정 되고 최대한 응답을 기다리는 시간을 1초만 준다"라고 가정해보자. 요청마다 이런 설정을 반복해야 한다면 매우 귀찮은 일이 될 것이다.
axios는 create 라는 함수를 이용하면 공통설정이 완료된 새로운 Axios 인스턴스 를 만들 수 있다.
이를 위해 src/plugins/axios.js 파일을 만들고 아래와 같이 작성해보자.
import axios from "axios"
const aiPlaceHolder = axios.create({
baseURL:"https://jsonplaceholder.typicode.com",
timeout:1000
});
export {aiPlaceHolder};
이제 기존의 코드는 아래와 같이 바뀔 수 있다.
import {aiPlaceholder} from '@/plugins/axios.js'
const get = (e) => {
aiPlaceholder({
url: "/posts/1",
})
.then((response) => {
if (response.status == 200) {
console.log(response.data);
}
})
.catch((e) => {
console.log(`${e.name}(${e.code}): ${e.message})`);
});
};
이제 url 부분을 작성할 때 baseURL에 붙일 내용만 작성해주면 된다.
interceptor
interceptor는 axios 요청이 발송되기 전, 응답을 처리하기 전 에 요청 또는 응답을 가로채서 무언가 부가적인 작업을 수행 할 수 있게 도와준다.
전역 객체에 interceptor 적용
먼저 전역의 axios 객체에 interceptor를 적용해보자. 이를 위해 axios.interceptors를 사용한다. 코드는 간단하니 바로 살펴보자. 아래의 코드는 /src/plugins/axios.js의 일부이다.
axios.interceptors.request.use((config) => {
console.log("[요청 발신]: ", config)
return config;
}, (error) => {
console.log("[요청 실패]: ", error)
return Promise.reject(error)
});
axios.interceptors.response.use(response => {
console.log("[응답 수신]: ", response)
return response;
}, error => {
console.log("[오류 수신]: ", error)
return Promise.reject(error);
});
axios.interceptors가 가지는 response와 request 는 모두 use 함수를 갖는데 각각 요청 전달과 응답 수신이 성공했을 때, 실패했을 때의 콜백을 파라미터로 갖는다. 비동기로 호출되기 때문에 각 상황에서의 반환 타입을 신경써야 한다.
위의 예는 요청 전달 전/응답 수신 후 상황에 대한 로깅을 작성한 부분이다. 이제 interceptor에서 요청과 응답에 대한 로깅이 이뤄지기 때문에 axios 호출 시마다 로깅할 필요가 없어졌다.
custom axios 객체의 interceptor
위에서 적용한 인터셉터는 전역 객체에 설정 한 것이기 때문에 axios instance에는 적용되지 않는다. 필요하다면 따로 적용해줘야 한다.
여기서는 요청이 처리되는 동안 indicator를 표시하는 기능을 interceptor로 구현해보자.
기본적인 코드는 전역 객체의 interceptor와 동일한데 여기서의 핵심은 ing라는 속성을 ref로 추가 했고 작업이 시작하면 ing를 true로 성공/실패로 종료되면 false로 변경해주었다.
데이터의 공유를 위해 provide/inject를 떠올릴 수 있는데 이는 setup() 내부에서와 router의 routing guard에서 사용 가능하다.
import axios from "axios";
import { ref } from "vue";
const aiPlaceholder = axios.create({
baseURL: "https://jsonplaceholder.typicode.com",
timeout: 1000 * 5,
});
aiPlaceholder.ing = ref(false); // 화면에서 사용하기 위해서 반응형 값 설정
aiPlaceholder.interceptors.request.use(
(config) => {
aiPlaceholder.ing.value = true;
console.log("[요청 발신]: ", config);
return config;
},
(error) => {
console.log("[요청 실패]: ", error);
return Promise.reject(error);
}
);
aiPlaceholder.interceptors.response.use(
(response) => {
aiPlaceholder.ing.value = false;
console.log("[응답 수신]: ", response);
return response;
},
(error) => {
console.log("[오류 수신]: ", error);
aiPlaceholder.ing.value = false;
return Promise.reject(error);
}
);
export { aiPlaceholder };
indicator 적용 확인
이제 axios가 시작하고 종료될 때 ing 속성값이 변하기 때문에 이를 화면상에서 이용하면 된다.
<template>
<div><button @click="get">get</button> <button @click="post">post</button></div>
<div id="overlay" v-if="aiPlaceholder.ing.value">아.. 쫌</div>
</template>
<script setup>
import { aiPlaceholder, } from "@/plugins/axios.js";
const get = () => {
aiPlaceholder({
url: "/posts/1",
// method: "get",
})
.then((response) => {
// 상태 코드에 따른 동작 처리
if (response.status == 200) {
console.log(response.data);
}
})
.catch((e) => {
console.log(`${e.name}(${e.code}): ${e.message})`);
});
};
const post = async () => {
try {
const response = await aiPlaceholder.post("https://jsonplaceholder.typicode.com/posts", {
title: "foo",
body: "bar",
userId: 1,
});
if (response.status == 201) {
console.log(response.status, response.data);
}
} catch (e) {
console.log(`${e.name}(${e.code}): ${e.message})`);
}
};
</script>
<style scoped>
#overlay {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
z-index: 99;
background: rgba(55, 255, 0, 0.5);
}
</style>
참고로 위 코드에서 aiPlaceholder의 ing 를 <template>영역에서 사용할 때 .value를 사용 하는데 이 부분이 좀 특이하다. 반응형 객체의 값을 <template>에서 사용할 때는 자동으로 unwrapping 해주는데 무슨일일까? 문제는 ing가 일반 객체인 aiPlaceholder의 값 이라는 점이다. 반응형 데이터가 최상위 객체가 아닐 경우는 명시적으로 value를 추가 해줘야 한다.
https://goodteacher.tistory.com/531
[vue 3] 03. 반응성(Reactivity)
반응성이란 데이터가 변경되었을 때 이를 감지하고 이에 반응하여 부가적인 동작을 수행하기 위한 성질이다. 예를 들어 위와 같이 excel 수식을 작성한 후 A를 20으로 변경하면 이에 반응하여 Sum
goodteacher.tistory.com
만약 javascript 단에서 aiPlaceholder의 값 변경에 따른 동작을 처리하려면 watch를 활용해보자.
const dialog = ref(null);
watch(() => aiPlaceholder.ing.value, (nv) => {
if (nv) {
dialog.value?.showModal();
console.log("상태 변화 감지", true, dialog.value)
} else {
dialog.value?.close();
console.log("상태 변화 감지", false, dialog.value)
}
},
{
immediate: true
}
)
<dialog ref="dialog">
<!-- <VueSpinner size="100" color="red"></VueSpinner> -->
잠시만요
</dialog>