쿼리스트링 복수값 전달하기 :: 마이구미
이 글은 쿼리스트링(querystring) 을 사용하는 사례 중 하나를 다뤄본다.
정확히는 하나의 필드에 여러개의 값을 넣는 경우에 대한 내용이다.
글의 예제들은 URLSearchParams API 와 qs 라는 모듈을 기반으로 작성되었다.
예제 코드 - https://codesandbox.io/s/multi-querystring-gopv63
URLSearchParams - https://developer.mozilla.org/ko/docs/Web/API/URLSearchParams
qs - https://github.com/ljharb/qs
쿼리스트링을 활용하는 대표 사례는 검색 필터 조건을 들 수 있다.
이미 URL 에 포함된 쿼리스트링의 값을 기반으로 검색 조건의 값들을 셋팅하여 사용자에게 더 나은 사용성을 제공한다.
"네이버 쇼핑"을 예로 들면, 위처럼 선택한 요소를 기준으로 URL 쿼리스트링의 값들이 셋팅된다.
이를 통해 새로고침하더라도, 원하는 검색 조건을 유지할 수 있게 된다.
URL 로는 어떻게 표현할 수 있을까?
brand=맛있닭&maxPrice=40000&minPrice=20000&delivery=오늘출발
많은 검색 조건을 활용하다보면, 하나의 필드에 여러개의 값을 제공해야할 경우가 생긴다.
네이버 쇼핑에서 이러한 경우에 포함되는 기능은 "브랜드" 이다.
하나의 필드에 여러개의 값들이 존재하게 된다.
이러한 경우에는 URL 로는 어떻게 표현할 수 있을까?
brand=하림 허닭 맛있닭&maxPrice=40000&minPrice=20000&delivery=오늘출발
하나의 필드에서 각각의 값들을 스페이스를 기준으로 분류하는 모습을 볼 수 있다.
위처럼 표현할 수도 있으나, 여러개의 값들을 표현하는 방식은 다양하게 존재한다.
1. foo[0]=1&foo[1]=2&foo[2]=3
2. foo[]=1&foo[]=2&foo[]=3
3. foo=1&foo=2&foo=3
4. foo=1,2,3
5. foo=1 2 3
그렇다면, 우리는 어떤 방식을 사용해야하는가? 표준 방식이 존재하는가?
질문의 답에 앞서, 우선 단일 필드로 표현하는가? 복수 필드로 표현하는가? 2가지로 분류해보자.
여기서 1,2,3 번이 복수 필드로 표현하는 방식이고, 4,5번이 단일 필드로 표현한다고 가정한다.
원활한 진행을 위해 단일 필드, 복수 필드라고 부르겠다.
단일 필드와 복수 필드의 차이점은 무엇인가?
우선 URL 측면에서는 크게 2가지를 말할 수 있다.
- URL 길이
- 시각적 요소
복수 필드는 값이 n 개라면, 필드도 n 개 존재해야하기때문에, 단일 필드에 비해 길이가 길어질 수 밖에 없다.
그리고 단일 필드가 조금 더 직관적일 수 있다.
만약 사내 어드민처럼 숙련된 사용자가 사용하는 서비스라면, URL 의 쿼리스트링을 적극적으로 활용할 수 있다.
URL 을 직접 수정하면서 서비스를 이용하는 사용자라면, 단일 필드 방식이 조금 더 편하게 수정할 수 있을 것이다.
코드 측면에서의 차이점은 무엇인가?
우선 쿼리스트링이 어떠한 형태이든 2가지 방식 모두 내부적으로는 배열로 관리될 것이다.
값의 추가, 삭제, 유효성 검증 등등을 위해서는 결국 배열로 관리해야 효율적이기 때문이다.
그렇다면 2가지 방식 모두 배열 형태로 변환하는 것에 대한 차이점이 있는지 확인해보자.
- 단일 필드의 경우에는 foo=1,2,3 이라는 문자열을 가져와서 각 요소의 분리 기준이 되는 콤마를 통해 배열 형태로 변환해줘야할 것 같다.
- 복수 필드의 경우에도 foo=1&foo=2&foo=3 를 배열 형태로 변환이 필요해보인다.
사실 2가지 방식 모두 URLSearchParams API 를 활용하든 qs 모듈을 사용하든 기본적으로 제공해주는 기능이다.
const paramsString = 'foo=1,2,3';
let searchParams = new URLSearchParams(paramsString);
searchParams.getAll('foo') // ['1', '2', '3']
const paramsString = 'foo=1&foo=2&foo=3';
let searchParams = new URLSearchParams(paramsString);
searchParams.getAll('foo') // ['1', '2', '3']
const query = qs.parse('foo=1&foo=2&foo=3', {
comma: true
});
query.foo // ['1', '2', '3']
const query = qs.parse('foo=1,2,3')
query.foo // ['1', '2', '3']
보다시피 코드 측면에서는 큰 차이가 없어보인다.
이미 쿼리스트링과 관련된 API 나 모듈에서는 모두 지원하고 있는 모습을 볼 수 있다.
그런 측면에서 보면, 표준 방식과 더 나은 방식이 무엇인지가 정해져있다고 보기 어렵다.
그렇다면, 아무 방식이나 쓰면 되는가?
어떠한 방식이든 큰 리스크가 존재하지 않는다.
그럼에도 고민을 해보고자 한다면, 서버 측면도 함께 고려하면 좋을 것이다.
만약 쿼리스트링의 값이 API 의 파라미터 역할도 가지고 있다면, 서버가 원하는 형태가 존재할 것이다.
서버의 프레임워크에 따라, 기본적으로 제공해주는 형태와 그렇지 않은 형태들이 존재한다.
foo=1&foo=2&foo=3 형태를 기본적으로 배열 형태로 받아줄 수 있는 반면, foo=1,2,3 과 같은 콤마 형태로 전달하게 되면 서버에서는 문자열을 잘라서 배열로 변환하는 작업이 필요할 수도 있다.
URL, 요청 파라미터 등 관련된 기능의 일관된 형태를 보장하고 싶다면, 서버에 맞추는 것도 좋은 방법이라고 본다.
하지만 URL 측면에서의 차이점에서 언급한대로, 콤마 형태를 보장해야하고, 서버는 복수 필드로 보내야하는 상황으로, 2가지 형태 모두 공존하는 상황이라면 그것도 상관없다.
표준 방식이 정해져있지 않을 뿐더러, 상황과 목적에 따라 다를 것이다.
괜한 고민거리일 수도 있으나, 이러한 고민도 있다? 정도로...