Info
- ํ์ฌ FE๋ง ๊ตฌํ๋์ด ์๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ ํ ์คํธ๊ฐ ํ์ํ ๊ฒฝ์ฐ, Mock ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํด์ผ ํจ.
- ํจ์จ์ ์ธ ํ ์คํธ๋ฅผ ์ํ ํ๊ฒฝ์ ๊ณ ๋ คํ๋ ์ค, MSW(MockServiceWorker)๋ฅผ ์๊ฒ ๋จ.
- ํ์ฌ Local ํ๊ฒฝ์์๋ MSW๋ฅผ ํตํด Mock ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋์ด ์์.
MSW (MockServiceWorker)
๋ธ๋ผ์ฐ์ ๋๋ Node.js ํ๊ฒฝ์์ API ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ ๊ฐ์ง ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ Mock ์๋ฒ๋ฅผ ์ค์ ํ ์ ์์.
- ๊ฐ์ API ์๋ต: ์ค์ ์๋ฒ๊ฐ ์์ด๋ API ํต์ ์ ํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๋์ ๊ฐ๋ฅ. (์ค์ API ํต์ ์์ค๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ.)
- ๊ฐ๋ฐ ํ ์คํธ ์ง์: FE ๊ฐ๋ฐ ์, ์ค์ ์๋ฒ๊ฐ ์์ด๋ ๋คํธ์ํฌ ๊ด๋ จ ๊ธฐ๋ฅ์ด๋ ์ ๋, ํตํฉ ํ ์คํธ ๊ฐ๋ฅ.
- BE ์๋น์ค ๋ก์ง๊ณผ ์ ์ฌํ๊ฒ ์ค์ ๊ฐ๋ฅ: ERROR ์ผ์ด์ค๋ SUCCESS ์ผ์ด์ค๋ค์ ์ค์ BE ์๋น์ค์ ํก์ฌํ๊ฒ ์ธํ ๊ฐ๋ฅ. (๊ธฐ์กด์ ์ ์ํ FE ์์ค๋ฅผ ํ์ฉํ ์ ์์.)
Install
npm install msw --save-dev
Setting
- dev ํ๊ฒฝ์ผ๋ก ์๋น์ค ์คํ ์, Axios instance ์์ฑ ์์ ์ baseURL: '' ๋ฅผ ํตํด MSW์ ์์ฒญ์ ๋ณด๋ด๋๋ก ์ค์ ๋จ.
Worker
- ๊ตฌํ๋ handler๋ก Worker๋ฅผ ์คํํ๋ ๊ตฌ๋๋ถ.
import { setupWorker } from 'msw/browser'
import handlers from './handlers'
export const worker = setupWorker(...handlers)Handlers
- handlers
- ๊ตฌํ๋ handler๋ค์ ๋ชจ์๋์ ๋จ์ํ List
- handler ์ถ๊ฐ ์, ํด๋น List์ ์ถ๊ฐ ํ์. (๋ฐ๋๋ก, ๋น์ฅ ์ฌ์ฉํ์ง ์๋ handler๋ List์์ ์ ๊ฑฐ)
import AuthHandlers from './handlers/AuthHandlers'
import HandlerInterceptor from './handlers/HandlerInterceptor'
import ScheduleHandlers from './handlers/ScheduleHandlers'
import HolidayHandlers from './handlers/HolidayHandlers'
const handlers = [HandlerInterceptor, ...AuthHandlers, ...ScheduleHandlers, ...HolidayHandlers]
export default handlers- handler
- ์ค์ request๋ฅผ ๋ฐ์ response๋ฅผ ์ํํ๋ function
- DB ์ํ๋ ๊ฐ๋จํ๊ฒ variable๋ก ๋ณด๊ด
- ์์ฑ ์์ : ์๋น์ค ์์ ์์
- ์ ๊ฑฐ ์์ : ์๋น์ค ์ข ๋ฃ ์์
- MSW์ http, HttpResponse ๋ฅผ ์ฌ์ฉํ์ฌ, request๋ฅผ ๋ฐ๊ณ response
- ์ค์ BE ๋ก์ง์ฒ๋ผ request์์ ๋ฐ์ parameter์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ response ๊ฐ๋ฅ
- ์๋ฌ ๋ฐ์์ด ํ์ํ ์์ ์ Error ๊ฐ์ฒด๋ฅผ response
- ์ฑ๊ณตํ ์์ ์ ์ผ์ด์ค์ ๋ฐ๋ผ ๋ถ๋ฆฌํ์ฌ ๊ฐ๊ธฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ response
import { http, HttpResponse } from 'msw'
import { ApiResponse } from '@utils/api/models/ApiResponse'
import { Schedule } from '@typings/Schedule'
import { apiCode } from '@utils/error/constant/ApiCode'
import { scheduleType } from '@typings/constants/ScheduleType'
import dateFormatUtil from '@utils/date/dateFormatUtil'
let schedules = [
new Schedule({
id: 1,
type: scheduleType.TIME,
startedAt: '2025/01/06 00:00',
endedAt: '2025/01/10 23:59',
title: 'schedule1',
contents: 'schedule1',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 2,
type: scheduleType.TIME,
startedAt: '2025/01/07 07:00',
endedAt: '2025/01/07 12:30',
title: 'schedule2',
contents: 'schedule2',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 3,
type: scheduleType.TIME,
startedAt: '2025/01/07 08:00',
endedAt: '2025/01/07 08:30',
title: 'schedule3',
contents: 'schedule3',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 4,
type: scheduleType.TIME,
startedAt: '2025/01/05 04:00',
endedAt: '2025/01/05 23:00',
title: 'schedule4',
contents: 'schedule4',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 5,
type: scheduleType.TIME,
startedAt: '2025/01/07 04:00',
endedAt: '2025/01/09 23:59',
title: 'schedule5',
contents: 'schedule5',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 6,
type: scheduleType.TIME,
isImportant: true,
startedAt: '2025/01/03 04:00',
endedAt: '2025/01/07 23:59',
title: 'schedule6',
contents: 'schedule6',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 7,
type: scheduleType.TIME,
startedAt: '2025/01/09 13:00',
endedAt: '2025/01/09 14:00',
title: 'schedule7',
contents: 'schedule7',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 8,
type: scheduleType.TIME,
startedAt: '2025/01/09 11:00',
endedAt: '2025/01/09 17:00',
title: 'schedule8',
contents: 'schedule8',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 9,
type: scheduleType.TIME,
startedAt: '2025/01/09 11:00',
endedAt: '2025/01/11 17:00',
title: 'schedule9',
contents: 'schedule9',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 10,
type: scheduleType.TIME,
startedAt: '2025/02/09 11:00',
endedAt: '2025/02/11 17:00',
title: 'schedule9',
contents: 'schedule9',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 11,
type: scheduleType.TASK,
startedAt: '2025/02/09 00:00',
endedAt: '2025/02/11 23:59',
title: 'task1',
contents: 'task1',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
new Schedule({
id: 12,
type: scheduleType.TASK,
isImportant: true,
startedAt: '2025/01/01 00:00',
endedAt: '2025/01/02 23:59',
title: 'task2',
contents: 'task2',
createdAt: '2025/01/06 15:00:00',
updatedAt: '2025/01/06 15:00:00',
}),
]
const ScheduleHandlers = [
http.get<
never,
| {
year?: number
month?: number
day?: number
}
| undefined,
null | ApiResponse<Schedule[]>
>('/schedule', ({ request }) => {
const { stringToDate } = dateFormatUtil
const date = new URL(request.url).searchParams
const year = Number(date.get('year'))
const month = Number(date.get('month'))
const day = Number(date.get('day'))
if (day) {
return HttpResponse.json(
new ApiResponse<Schedule[]>().build(
apiCode.SUCCESS,
schedules.filter(schedule => {
const targetDate = stringToDate(schedule.startedAt)
return (
targetDate.year() == year &&
targetDate.month() + 1 == month &&
targetDate.date() == day
)
}),
),
)
}
if (month) {
return HttpResponse.json(
new ApiResponse<Schedule[]>().build(
apiCode.SUCCESS,
schedules.filter(schedule => {
const targetDate = stringToDate(schedule.startedAt)
return targetDate.year() == year && targetDate.month() + 1 == month
}),
),
)
}
if (year) {
return HttpResponse.json(
new ApiResponse<Schedule[]>().build(
apiCode.SUCCESS,
schedules.filter(schedule => stringToDate(schedule.startedAt).year() == year),
),
)
}
return HttpResponse.json(new ApiResponse<Schedule[]>().build(apiCode.SUCCESS, schedules))
}),
http.post<never, Schedule, ApiResponse<number | null>>('/schedule', async ({ request }) => {
const schedule: Schedule = await request.json()
if (!schedule)
return HttpResponse.json(new ApiResponse<null>().build(apiCode.INVALID_REQUEST_PARAM, null))
const id = schedules.length + 1
schedule.id = id
schedules.push(schedule)
return HttpResponse.json(new ApiResponse<number>().build(apiCode.SUCCESS, id))
}),
http.delete<{ id: string }, null, null>('/schedule/:id', ({ params }) => {
const id = Number(params.id)
if (!id)
return HttpResponse.json(new ApiResponse<null>().build(apiCode.INVALID_REQUEST_PARAM, null))
schedules = schedules.filter(schedule => schedule.id != id)
return HttpResponse.json(new ApiResponse<number>().build(apiCode.SUCCESS, id))
}),
http.put<{ id: string }, Schedule, null>('/schedule/:id', async ({ params, request }) => {
const id = Number(params.id)
const schedule = await request.json()
if (!id || !schedule)
return HttpResponse.json(new ApiResponse<null>().build(apiCode.INVALID_REQUEST_PARAM, null))
schedules = schedules.map(stateSchedules =>
stateSchedules.id == id ? schedule : stateSchedules,
)
return HttpResponse.json(new ApiResponse<null>().build(apiCode.SUCCESS, null))
}),
]
export default ScheduleHandlers