MSW 동적 경로가 정적 경로를 가로채는 문제 해결하기

2025. 10. 17. 03:54·Frontend

MSW에서 request handler를 작성할 때 경로 매칭과 관련하여 주의해야 할 점을 공유합니다.


문제 및 원인

MSW request handler를 작성할 때 정확한 경로로 핸들러를 작성해도 오류가 발생할 때가 있습니다. 다음과 같이 구현했다고 해봅시다.

const handlers = [
  http.get('/posts/:id', postResolver),
  http.get('/posts/latest', latestPostsResolver),
];

fetch('/posts/latest');

 

여기서 /posts/latest로 요청을 보냈을 때 /posts/latest를 다루고 있는 핸들러에 매칭될 것이라고 일반적으로 예상할 것입니다.

 

하지만 예상과 달리 /posts/:id를 다루는 핸들러에 매칭되는데요. 이유는 MSW가 요청을 처리할 때 핸들러를 앞에서부터 순서대로 검토하고 요청과 일치하는 첫 번째 핸들러를 실행하기 때문입니다. 즉 /posts/latest의 latest가 path parameter인 id로써 인식하여 /posts/latest와 /posts/:id의 경로가 서로 일치한다고 이해하기 때문입니다.

 

해결 방안

핸들러 순서 조정하기

동일한 문제를 겪고 해결책을 찾는 이슈를 확인해보니, 핸들러의 순서를 조정하는 것을 권장하고 있습니다.

export const handlers = [
  http.get('/posts/latest', latestPostsResolver), // 동적 경로보다 앞에 두기
  http.get('/posts/:id', postResolver),
];

fetch('/posts/latest');

 

MSW에서 권장하는 방식대로 해결했는데도 뭔가 야매로 한 것 같고 찜찜한 느낌이 듭니다.

 

새로운 핸들러를 추가할 때, 조심하지 않는다면 똑같은 문제를 다시 겪게 될 게 뻔하니까요. 뿐만 아니라 핸들러 개수가 많아지거나 핸들러 내부에 있는 코드의 양이 클수록 순서를 조정하기 더욱 어려울 것입니다.

 

이건 논외지만... 저는 핸들러를 작성할 때에도 사용 흐름에 맞춰서 작성하는데요(ex. 조회-등록-수정-삭제). (이렇게 할 필요는 없지만 읽을 때 흐름이 보여서 기분이 좋습니다.) 핸들러 순서를 조정해서 이런 흐름이 깨지면 동작에는 전혀 지장이 없지만 기분이 아쉽긴 하겠습니다. ㅋㅋ

 

개선된 방식으로 핸들러 순서 조정하기

순서를 조정하되, 핸들러 하나하나가 아닌 핸들러 묶음을 조정하는 방식을 사용한다면 어떨까요?

const staticRouteHandlers = [
  http.get('/posts/latest', latestPostsResolver),
];

const dynamicRouteHandlers = [
  http.get('/posts/:id', postResolver),
];

export const handlers = [
  ...staticRouteHandlers,
  ...dynamicRouteHandlers,
];

 

정적 경로를 다루는 핸들러와 동적 경로를 다루는 핸들러를 서로 분리하고, 정적/동적 경로를 다루는 핸들러끼리 묶어서 정적 경로 핸들러 묶음을 동적 경로 핸들러 묶음보다 앞에 배치하는 방식입니다. 이렇게 하면 최초에 한 번만 순서를 조정하면 되기 때문에, 이 문제를 겪은 적이 없는 다른 동료가 새로운 핸들러를 추가하더라도 문제를 겪지 않을 것입니다.

 

경로를 정규표현식으로 작성하기

마지막 방법은 정규표현식을 사용하여 동적 경로를 좀 더 자세하게 작성하는 것입니다.

const handlers = [
  http.get('/posts/:id([0-9]+)', postResolver), // id에 숫자 값만 허용
  http.get('/posts/latest', latestPostsResolver),
];

fetch('/posts/latest');

 

id에 숫자 값만 올 수 있도록 정규표현식을 작성한 예시입니다. 이렇게 하면 순서를 바꾸지 않아도 정확한 경로를 매칭할 수 있습니다.


단점은 어떤 경로인지 한 눈에 파악하기 어렵다는 것입니다. 또 path parameter로 문자열을 받게 설계한 경우 여전히 기존과 문제를 낼 수 있다는 한계가 있습니다.

 

❓typescript를 사용해 path parameter에 타입을 지정하면 안 되나요?
타입 정보는 런타임에서 모두 제거되기 때문에 근본적으로 이 문제를 해결하지 못합니다. 또한 path parameter의 타입은 string | readonly string[] | undefined 으로 고정되어 있기 때문에 다른 타입을 받도록 지정하기 어렵습니다.

 

 


느낀 점

위에서 언급한 이슈를 보면, RequestHandler.predicate()라는 메서드를 통해 경로 일치를 제어하고 있다고 하는데요. 이 메서드는 MSW 내부용 메서드로 핸들러가 요청과 일치하는지 true/false로 판단하는 역할을 하는 것 같습니다(정확히 찾아보진 않았으니 주의!). 그리고 MSW 개발자는 현재의 매칭 검토 방식이 매우 예측 가능하기 때문에 앞으로도 변경하지 않고 싶다고 말하네요.

 

MSW의 근본적인 동작으로 인한 문제이기 때문에 어떤 방법을 사용해도 명쾌하게 해결할 수는 없지만... 뭐라도 해야겠죠...

 

놀랍게도 이전에 동일한 문제를 겪은 적이 있는데요(한 1년 전쯤에). 같은 문제를 다시 마주했음에도 MSW 문제라는 것을 단번에 알아내지 못했습니다. 어쩔 수 없다고 생각하는 게, 오류를 뱉는 문제들은 오류를 통해서 무엇이 문제인지 알 수가 있지만, 이 문제같은 경우에는 일단 작동은 하니까 문제가 발생하는 지점을 찾기가 어려울 수밖에 없는 것 같습니다. 요청에 대한 응답이 오긴 하는데 전혀 다른 응답이 오고 뭐가 문제인지는 모르겠고 말이에요.

처음에는 API 쪽을 집중적으로 살펴봤는데 아무리 봐도 이상이 없어서 기능 구현을 잘못 했거나 어딘가에 더미 데이터가 남아 있는 것은 아닌지 의심했습니다. 그러다가 MSW 핸들러 문제라는 걸 깨달았어요. 너무 아까운 내 시간...ㅠ

 

다음에 또 MSW 핸들러 순서로 인한 문제가 생긴다면 알아챌 수 있을지는 모르겠으나 이 글을 남김으로써 머리에 깊게 각인하고 알아차렸으면 좋겠다는 바람입니다. 이 글을 보시는 분들도...🍀

저작자표시 비영리 변경금지 (새창열림)

'Frontend' 카테고리의 다른 글

html script type="module" 시 CORS 에러 원인 분석 및 해결 방안  (0) 2025.05.22
CSR/SSR 개념, 장단점, CSR 등장 배경  (0) 2023.09.12
'Frontend' 카테고리의 다른 글
  • html script type="module" 시 CORS 에러 원인 분석 및 해결 방안
  • CSR/SSR 개념, 장단점, CSR 등장 배경
톱치
톱치
나를 위한 기록을 합니다
  • 톱치
    기록
    톱치
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • 홈
    • 방명록
    • 글쓰기
    • 전체보기 (51)
      • Articles (0)
      • Frontend (3)
        • JS, TS (16)
        • HTML, CSS (5)
        • React (6)
        • Dart (3)
      • Backend (6)
      • Others (3)
      • Algorithm (5)
      • 회고 (4)
  • 링크

    • GitHub
  • 태그

    우아한테크코스
    token
    login
    node.js
    회고
    js
    object
    css
    programmers
    BFS
    javascript
    Node
    TypeScript
    todolist
    Redux
    React
    ts
    프리코스
    BCrypt
    dart
  • hELLO· Designed By정상우.v4.10.3
톱치
MSW 동적 경로가 정적 경로를 가로채는 문제 해결하기
상단으로

티스토리툴바