diff --git a/README.md b/README.md index f26d1261..5a822263 100644 --- a/README.md +++ b/README.md @@ -158,11 +158,15 @@ https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/bbf1724458dd76 ⭐️⭐️⭐️⭐️⭐️ -### 브라우저의 Cache Storage에 queryString을 저장하고, +### Cache Storage를 사용하여 캐싱 기능을 제공하였습니다. -### API 호출전에 Cache Storage에 queryString이 존재하면 해당 데이터 리턴 하도록 사용 +### Cache Storage에는 queryString을 키값(name)으로 데이터와 etag를 저장합니다. -### Cache Storage에 없을경우 API 호출 진행 +### API 호출시 Cache Storage에 queryString 값이 존재하면 etag를 header에 포함하여 호출 진행하며, + +### response status === 200 이면 받은 response.data를 표출하고, etag와 data 값을 Cache Storage에 저장합니다. + +### response status === 304 이면 Cache Storage에서 data 값을 가져와서 표출합니다. ⭐️⭐️⭐️⭐️⭐️ @@ -170,7 +174,9 @@ https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/bbf1724458dd76 cache

-https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/bbf1724458dd765687641bed9246447632d70bc6/src/apis/ClinicalService.ts#L4-L31 +https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/85669cb51623fb669b11bec7ae4ff0bd339553c2/src/apis/ClinicalService.ts#L5-L51 + + # @@ -228,7 +234,9 @@ https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/bbf1724458dd76 # ### **7️⃣ Assignment** + > (추가 기능) + - isLoading 대신 Suspense 구현 https://github.com/Wanted-07-team-9/pre-onboarding-7th-3-1-9/blob/7b4fb302901a98f2222b5b1f38117d2102005542/src/pages/Main/AutoComplete/index.tsx#L12-L14 diff --git a/src/apis/ClinicalService.ts b/src/apis/ClinicalService.ts index 2102b982..dfa119c7 100644 --- a/src/apis/ClinicalService.ts +++ b/src/apis/ClinicalService.ts @@ -8,42 +8,19 @@ export const getSick = async (param: string): Promise => { if (param === '') return []; if ('caches' in window) { - const payload = { - sickNm_like: param, - }; - const queryStr = new URLSearchParams(payload).toString(); - const cacheStorage = await caches.open(URL_SICK); - const cachedResponse = await cacheStorage.match(queryStr); - const cached = await cachedResponse?.json(); - const config = { - headers: { - 'If-None-Match': (cached ? cached.etag : "") + params: { + sickNm_like: param, }, - params: payload, }; - try { const response = await instance.get(`/${URL_SICK}`, config); - - const customData = { - etag: response.headers.etag, - data: response.data - } - - cacheStorage.put(queryStr, new Response(JSON.stringify(customData))); - return response.data; - } - catch(error) { + } catch (error) { const err = error as AxiosError; - if(axios.isAxiosError(err)) { + if (axios.isAxiosError(err)) { console.error(err); } - - if(err.status === 304) { - return cached.data; - } } } diff --git a/src/apis/axiosInstance.ts b/src/apis/axiosInstance.ts index b3c8a41e..7299d0f7 100644 --- a/src/apis/axiosInstance.ts +++ b/src/apis/axiosInstance.ts @@ -1,4 +1,5 @@ -import axios from 'axios'; +import axios, { AxiosError } from 'axios'; +import { getCacheStorage, getRequestHeaders, setCacheStorage } from 'utils/cacheStorage'; const instance = axios.create({ baseURL: '/api', @@ -6,7 +7,10 @@ const instance = axios.create({ }); instance.interceptors.request.use( - config => { + async config => { + const headers = await getRequestHeaders(config); + config.headers = headers; + console.info('calling api'); return config; }, @@ -15,10 +19,17 @@ instance.interceptors.request.use( } ); instance.interceptors.response.use( - response => { + async response => { + await setCacheStorage(response); return response; }, - error => { + async error => { + if (error instanceof AxiosError) { + if (error.response?.status === 304) { + const cached = await getCacheStorage(error); + return cached; + } + } return Promise.reject(error.response); } ); diff --git a/src/hooks/useGetSickItem.ts b/src/hooks/useGetSickItem.ts index 77af0a97..484e2923 100644 --- a/src/hooks/useGetSickItem.ts +++ b/src/hooks/useGetSickItem.ts @@ -1,6 +1,6 @@ import { IResultItems } from '@types'; import { getSick } from 'apis/ClinicalService'; -import { wrapPromise } from 'apis/wrapPromise'; +import { wrapPromise } from 'utils/wrapPromise'; import { useEffect, useMemo, useState } from 'react'; import { useAppDispatch } from 'redux/hooks'; diff --git a/src/utils/cacheStorage.ts b/src/utils/cacheStorage.ts new file mode 100644 index 00000000..13172979 --- /dev/null +++ b/src/utils/cacheStorage.ts @@ -0,0 +1,36 @@ +import { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'; + +export const getRequestHeaders = async (config: AxiosRequestConfig) => { + const queryStr = new URLSearchParams(config.params).toString(); + const cacheStorage = await caches.open(config.url ? config.url : ''); + + const cachedResponse = await cacheStorage.match(queryStr); + const cached = await cachedResponse?.json(); + + return { + 'If-None-Match': cached ? `${cached.etag}` : '', + }; +}; + +export const setCacheStorage = async (response: AxiosResponse) => { + const customData = { + etag: response.headers.etag, + data: response.data, + }; + + const queryStr = new URLSearchParams(response.config.params).toString(); + const cacheStorage = await caches.open(response.config.url ? response.config.url : ''); + cacheStorage.put(queryStr, new Response(JSON.stringify(customData))); +}; + +export const getCacheStorage = async (error: AxiosError) => { + if (error.config) { + const queryStr = new URLSearchParams(error.config.params).toString(); + const cacheStorage = await caches.open(error.config.url ? error.config.url : ''); + const cachedResponse = await cacheStorage.match(queryStr); + const cached = await cachedResponse?.json(); + return cached; + } + + return { data: [] }; +}; diff --git a/src/apis/wrapPromise.ts b/src/utils/wrapPromise.ts similarity index 100% rename from src/apis/wrapPromise.ts rename to src/utils/wrapPromise.ts