๋ฐ์ด๋๋ฆฌ ํ์ ์ ํ์ผ ์๋ต ๋ชจํนํ๊ธฐ
์ง๊ธ ์ฌ๋ด ํ๋ก์ ํธ๋ ๋ฐฑ์๋ api์ ํ๋ฐํธ ๊ฐ๋ฐ์ ๋์์ ๋ณํ์ ์ผ๋ก ์งํํ๊ณ ์๋ค. ๋ฐ๋ผ์ ์๋ฒ๋จ API๊ฐ ์์ฑ๋๊ณ ๋ฐฐํฌ๋๊ธฐ ์ด์ ์๋ msw๋ผ๋ ์๋ฒ API ๋ชจํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ, ์ค์ ๋ฐฑ์๋ api ์์ด๋ ํ๋ฐํธ๋จ์์ mock ์๋ฒ๋ฅผ ๊ตฌํํด์ ๊ฐ์ง๋ก ๋คํธ์ํฌ ํต์ ์ ํ ์ ์๋ค.
json ํ์์ผ๋ก ํต์ ์ ์ฃผ๊ณ ๋ฐ๋ ๊ฑด ๊ณต์๋ฌธ์์๋ ์ ๋์์์ด์ Mocking์ ํ์๋๋ฐ, ์ด๋ฒ์ ๋ฐ์ด๋๋ฆฌ ํ์ ์ ์ด๋ฏธ์ง ํ์ผ์ get ํด์ค๋ ๋ถ๋ถ์์ ๋ชฉ์๋ฒ๋ฅผ ๊ตฌํํ๋๋ฐ ํฐ ๋๊ด์ด ์์๋ค.
์๋ต ์์
ํ๋ฐํธ์์ ์ด๋ฏธ์ง ํ์ผ์ get ํด์ฌ๋ ์๋ฒ์์ ์ฃผ๋ ์๋ต์ ์๋์ ๊ฐ๋ค.
๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ
์ฆ, ์๋ฒ์์๋ ์ด ๋ฉํฐ๋ฏธ๋์ด ๋ฐ์ดํฐ๋ฅผ 0๊ณผ 1 ๊ฐ๋ง ์กด์ฌํ๋ ์ด์ง ๋ฐ์ดํฐ๋ก ์๋ตํด์ฃผ๋ ๊ฒ์ด๋ค.
HTTP/1.1 200 OK
Content-Type: image/jpeg;charset=UTF-8
Accept-Ranges: bytes
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
์๋
์ผ๋ฐ์ ์ธ json ํ์์ ๋ฐ์ดํฐ๋ ์ง์ mock data๋ฅผ ๋ฃ์ด๋๊ณ , ์ด ๋ชฉ๋ฐ์ดํฐ๋ฅผ ์๋ต์ผ๋ก ์ฃผ๋๊น..
const todoList = [
{ id: 'bzte_tfG3k2mh3o-Vf-zX', content: 'book a hotel'},
{ id: 'rAFHp_GrutBJzt_5r1Gej', content: 'issue a travel card'},
...
]
์ด์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด๋ฏธ์งํ์ผ๋ ์๋ฒ์ ์๋๊ฒ ์ฒ๋ผ ๊ฐ์ง๋ก ํํํ๋ ค๋ฉด...?
๋ด ๋ก์ปฌ ์ปดํจํฐ์ ์๋ ์ด๋ฏธ์ง ํ์ผ์ src > assets ํด๋ ์์ ๋ฃ์ด๋๊ณ , ๋ชจํน ์ฝ๋๋ฅผ ์ฐ๋ handler ํ์ผ์์ ์ด๋ฏธ์ง ํ์ผ์ import ํด์์ ๋ฐ์ด๋๋ฆฌ ํ์ ์ผ๋ก ์๋ต์ ํด์ค๋ค.
๋ผ๋ ํ๋ก์ธ์ค ์ด๊ฒ ์ง?๋ผ๊ณ ์๊ฐํ๊ณ ์ค์ ์ด๋ฏธ์ง ํ์ผ์ ๋ฐ์ด๋๋ฆฌ ํ์ ์ผ๋ก ๋ณํํด๋ณด๋ ค๊ณ ํ์ผ๋.. ์ฝ๊ฒ ๋์ง ์์๋ค.
๋ฐ๋ผ์ ์๋์ ํ๋ก์ธ์ค๋ก mock ์ด๋ฏธ์ง ํ์ผ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์๊ณ , ๋ฐ์ด๋๋ฆฌ ํ์ ์ผ๋ก ์๋ต์ ์ฃผ๋๋ก ๋ชจํนํ์๋ค.
- ๋ก์ปฌ pc์ ์ ์ฅ๋์ด์๋ ์ด๋ฏธ์ง๊ฐ ์๋ base64 ํ์์ ํ์ผ์ ๊ฐ์ ธ์ค๊ธฐ
- base64 ํ์ผ ๊ฐ์ ธ์ค๋ ๋ฒ
- ๊ตฌ๊ธ๋ง์ผ๋ก ์ฐพ์ ์๋ฌด ์ด๋ฏธ์ง ๋งํฌ๋ฅผ base64 ์ธ์ฝ๋ฉ ์ฌ์ดํธ๋ฅผ ์ด์ฉํด์ base64๋ก ๋ณํํด์ค๋ค.
- base64๋?
- 0๊ณผ 1๋ก ์ด๋ค์ง ๋ฐ์ด๋๋ฆฌ ํ์์ผ๋ก ์ธ์ฝ๋ฉ ๋์ด์๋ ๋ฐ์ดํฐ๋ฅผ ํ ์คํธ ํ์์ผ๋ก ๋ณํํ ๊ฒ
- base64 ํ์ผ ๊ฐ์ ธ์ค๋ ๋ฒ
- ํ
์คํธํ์์ base64 ๋ฐ์ดํฐ๋ฅผ Binary ๋ฐ์ดํฐ๋ก ๋ณํํ๊ธฐ
- js์ ๋ด์ฅ ํจ์์ธ atob()๋ฅผ ์ฌ์ฉํด์ ์ด์ง๋ฐ์ดํฐ๋ก ๋ณํ์ํจ๋ค.
- atob(encodedData) ํจ์๋ Base64 (en-US) ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด ๋ฐ์ดํฐ๋ฅผ ๋์ฝ๋ฉํ๋ค.
- ์๋ฐ์คํฌ๋ฆฝํธ์์ Binary ๋ฐ์ดํฐ๋ฅผ ์ง์ ๋ค๋ฃฐ ์ ์๋๋ก ArrayBuffer ๊ฐ์ฒด ๋ง๋ค์ด์ฃผ๊ธฐ
- ArrayBuffer๋?
- ๋ฐ์ดํธ๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด
- Js์์ ์์๋ฐ์ดํฐ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ
- new ArrayBuffer(16) //16๋ฐ์ดํธ ํฌ๊ธฐ์ ๋ฒํผ๋ฅผ ์์ฑ
- ์ฐ์์ผ๋ก ๊ณ ์ ๋ ํฌ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ(16๋ฐ์ดํธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ)์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ
- ์ด๊ธฐ๊ฐ์ 0์ผ๋ก ์ฑ์์ ธ์์
- ArrayBuffer๋?
- ArrayBuffer์ ์ ์ฅ๋ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผํ ์ ์๋ ๊ฐ์ฒด์ธ Unit8Array๋ฅผ ์์ฑ
- ArrayBuffer๋ ๋ฐ์ดํธ๋ก๋ง ๊ตฌ์ฑ๋ ๋ฐฐ์ด๋ก "๋ฐ์ดํธ ๋ฐฐ์ด"์ด๋ผ๊ณ ๋ ๋ถ๋ฆ
- ArrayBuffer์ ๋ด๊ธด ์ ๋ณด๋ฅผ ์ง์ ์์ ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅ
- ๋ฐ๋ผ์ ArrayBufferView ๊ฐ์ฒด๋ฅผ ํตํด ๋ฒํผ๋ฅผ ํน์ ํ์์ผ๋ก ๋ํ๋์ผ๋ก์จ ๋ฒํผ์ ๋ด์ฉ์ ์ฝ๊ณ ์ฐ๊ธฐ๊ฐ ๊ฐ๋ฅ
- ArrayBufferView
- TypedArray, DataView 2์ข ๋ฅ์ ๊ฐ์ฒด๊ฐ ์์
- TypedArray (ํ์ํ ๋ฐฐ์ด)
- Unit8Array, Uint16Array, Float32Array ๋ฑ์ด ์์
- Unit8Array
- 8๋นํธ = 1๋ฐ์ดํธ๋ก ๊ฐ ๋ฐ์ดํธ ๋ณ๋ก ์ ๊ทผ ๊ฐ๋ฅํ view ๊ฐ์ฒด
- ArrayBufferView
- ArrayBuffer -> Blob(Binary Large Object) ํ์์ผ๋ก ๋ฐ๊พธ๊ธฐ
- Blob?
- ์ด๋ฏธ์ง, ์ค๋์ค, ๋น๋์ค ๊ฐ์ ๋ฉํฐ๋ฏธ๋์ด ํ์ผ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด ํํ๋ก ์ ์ฅํ ๊ฒ
- base64๊ฐ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํ ์คํธ๋ก ์ ์ฅํ๋ค๋ฉด Blob์ ๊ฐ์ฒด ํ์์ผ๋ก ์ ์ฅํ๋ค.
- ๋ง๋ ArrayBuffer๋ฅผ ์ธ์๋ก ๋ฃ์ด์ฃผ์ด new Blob(ArrayBuffer) ๊ฐ์ฒด๋ฅผ ๋ง๋ฌ
- Blob?
msw handler ์ ์ฒด ์ฝ๋
const base64mockImg =
'data:image/jpeg;base64,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';
const mockImg = atob(base64mockImg.split(',')[1]); // data:image/jpeg;base64 ๋ผ์ด๋ด์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ก ๋์ฝ๋ฉ
export const siteHandler = [
//์ฌ์ง ํ์ผ ๋ค์ด๋ก๋
rest.get(`photos/:photoId/download`, (req, res, ctx) => {
const arrayBuffer = new ArrayBuffer(mockImg.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < mockImg.length; i++) {
view[i] = mockImg.charCodeAt(i) & 0xff;
}
return res(
ctx.status(200),
ctx.set('Content-Type', 'image/jpeg'),
ctx.body(new Blob([arrayBuffer])),
);
}),
];
mock ์ด๋ฏธ์ง๋ฅผ ์๋ต์ผ๋ก ์ฃผ๊ธฐ์ํด ์ ํ๋ก์ธ์ค๋๋ก ์ฐจ๋ก๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ์๋ต ๋ฐ๋์ arrayBuffer๋ฅผ ๋ด์ Blob ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ฉด, ์ฑ๊ณต์ ์ผ๋ก response๊ฐ ๋ค์ด์จ๋ค.
response body์ ๋ด๊ฒจ์ค๋ ๋ชจ์ต ์ฝ์๋ก ํ์ธ
์ปดํฌ๋ํธ ์ฝ๋
export const downloadSiteImageFile = async (photoId: string) => {
try {
const { data }: { data: Blob } = await axios.get(
`http://localhost:5173/photos/${photoId}/download`,
{ responseType: 'blob' },
);
return data;
} catch (err) {
console.log(err);
}
};
export const PhotoCard = () => {
const [imgUrlFromBlob, setImgUrlFromBlob] = useState<string>();
useEffect(() => {
if (photoData.id) {
downloadSiteImageFile(photoData.id)
.then((res) => {
console.log(res, 'axios res');
if (res) {
const urlFromBlob = URL.createObjectURL(res);
setImgUrlFromBlob(urlFromBlob);
}
})
.catch((err) => console.log(err));
}
return () => {
if (imgUrlFromBlob) {
URL.revokeObjectURL(imgUrlFromBlob);
} //๋ธ๋ผ์ฐ์ ์ ๋ฉ๋ชจ๋ฆฌ๊ด๋ฆฌ๋ฅผ ์ํด URL ๊ฐ์ฒด ํด์
};
}, []);
return (
<CardMedia
sx={{
width: 160,
height: 160,
border: 'solid 1px',
}}
image={imgUrlFromBlob}>
</CardMedia>
);
}
์ค์ Blob ๊ฐ์ฒด๋ฅผ ํ๋ฐํธ ํ๋ฉด์ ๋ํ๋ด๊ธฐ ์ํด์ ์ด๋ฏธ์ง tag์ URL.createObjectURL ์ ์ฌ์ฉํด์ url ์ ์์ฑํ๋ค.
์ปดํฌ๋ํธ ์ฝ๋์์ ์ฌ์ง ํ์ผ ๋ค์ด๋ก๋ํด์จ ์๋ต response๋ฅผ ์ฐ์ด๋ณด๋ฉด Blob ๊ฐ์ฒด๊ฐ ์ ๋ค์ด์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Reference
https://www.daleseo.com/mock-service-worker/
https://mswjs.io/docs/recipes/binary-response-type