React Native에서는 서버와 통신하기 위해 Axios 라이브러리를 사용한다.
토큰 저장 방식은 react-native-keychain을 사용했다.
API_URL은 env에 저장해두고 꺼내온다.
const instance = axios.create({
baseURL: API_URL,
withCredentials: true,
timeout: 2000,
});
사용자 지정 config를 넣어 Axios Instance를 생성할 수 있다.
instance.defaults.headers['Set-Cookie'] = `refresh_token=${refreshToken}`;
refreshToken을 header에 입력한다.
instance.interceptors.request.use(
async config => {
config.headers['Content-Type'] = 'application/json';
config.headers['Authorization'] = `Bearer ${accessToken}`;
return config;
},
(err: unknown) => {
Promise.reject(err);
},
);
request 요청을 보낼 때, 기본으로 넣을 accessToken을 설정한다.
header를 Axios 인스턴스 생성 시점에 입력할 수도 있지만, 나는 interceptor 단계에서 처리해줬다.
instance.interceptors.response.use(
async response => {
const { config } = response;
const originalRequest = config;
if (response.status === 401) { // 401: Unauthorized
// 토큰 만료 혹은 로그인 정보 없음
removeAccessToken();
return await instance
.post('/users/reissue-token', { // 토큰 재발급
loginId: loginId,
refreshToken: refreshToken,
})
.then(async res => { // accessToken과 refreshToken 저장
setAccessToken(res.data.result.accessToken);
setRefreshToken(res.data.result.refreshToken);
// 헤더에 새로운 accessToken 입력
originalRequest.headers.Authorization = `${res.data.result.accessToken}`;
return axios(originalRequest);
});
}
// 로그인 정보가 있는 경우 (일반 요청)
return response.data;
},
(err: unknown) => {
Promise.reject(err);
},
);
response에서 일괄적으로 401 토큰이 유효하지 않은 Unauthorized 에러가 발생한다면, accessToken을 삭제하고, refreshToken으로 재발급을 요청해 새로운 accessToken을 발급받는다.
const instance = createInstance(); // 위에서 생성한 인스턴스를 불러오기
const defaultRequest = async (path: string, body: (url: string) => any) => {
try {
const response = body(path);
return response;
} catch (err) {
console.error(err);
}
};
기본 request 모듈을 만든다.
path: URL path
body: 입력할 data 또는 params
const post = async (path: string, data: any) => {
return await defaultRequest(path, async url => {
const response = (await instance).post(url, data);
return response;
});
};
const get = async (path: string, params: any) => {
return await defaultRequest(path, async url => {
const response = (await instance).get(url, {
params: params,
});
return response;
});
};
const patch = async (path: string, data: any) => {
return await defaultRequest(path, async url => {
const response = (await instance).patch(url, data);
return response;
});
};
const request = Request(); // 위에서 정의한 Request 모듈을 불러온다.
const duplicateCheck = async () => {
const response = await request.post('/users/loginId', {
loginId: form.loginId,
});
if (response.isSuccess) { // 서버에서 isSuccess라는 응답을 준다.
setCheck({ ...check, loginId: true });
}
}