Frudy
6k
2020-10-07 20:22:22
13
840

검색페이지를 이렇게 구현하는건 어떻게 생각하세요?


정말 흔하디흔한,

리스트를 테이블에 보여주고 검색폼 붙어있는 사이트에요.



1년간 겪었던, 또는 봐왔던 구현 방법은,

https://cafe.naver.com/marineraise?type=title&searchText=%EB%A7%88%EB%A6%B0


이런 url이 있으면.


GET /url?location.search

url 뒤에 붙어있는 search부분을 그대~로 GET API에 넣어서 리스트를 불러왔었어요.


하지만 지금 다시 생각해보니, 주소창은 사용자가 입력을 할 수 있다는거에요.

https://cafe.naver.com/marineraise?unknownKey=whatthefuck

이런식으로요.


그래서 문득 돌이켜보니, 이런생각이 들었어요.


(기존)

웹페이지주소 : https://cafe.naver.com/marineraise?type=title&searchText=%EB%A7%88%EB%A6%B0&unknownKey=whatthefuck

API : GET https://cafe.naver.com/marineraise?type=title&searchText=%EB%A7%88%EB%A6%B0&unknownKey=whatthefuck


(제 생각)

웹페이지주소 : https://cafe.naver.com/marineraise?type=title&searchText=%EB%A7%88%EB%A6%B0&unknownKey=whatthefuck

API : GET https://cafe.naver.com/marineraise?type=title&searchText=%EB%A7%88%EB%A6%B0


유효하지않은 key가 queryString에 있는지 체크를 해서 API를 호출할 때는 제외해보면 어떨까 싶었어요.


제외하던 안하던, 서버에서는 어차피 queryString중에 필요한것만 추출해서 응답을 하기때문에,

제외하고 안하고에 따라 응답의 차이가 전-혀 없어요.


제외해봐도 얻을 수 있는 이득이 단 하나도없다는거에요.


비슷한 예시로,

로그인시 이메일 유효성검증을 프론트에서 먼저 하는 이유중 하나는,


유효하지도않은 이메일을 서버로 보낼바엔 클라이언트사이드에서 먼저 체크하면

서버의 부담이 줄어들어서 하는건데,


이 문제의 경우에는, 서버입장에서..

필요한 queryString이 있는지가 중요하지

불필요한 queryString이 있는지는 하나도 안중요하더라구요.


그래서 결론은 남들처럼 "url의 search부분을 그대~로 GET API에 실어서 요청하는게 낫다"

라고 내렸는데


혹시 제가 생각하지못한 부분이 있나요?

0
  • 댓글 13

  • 돈까스
    4k
    2020-10-08 02:30:21 작성 2020-10-08 02:36:21 수정됨

    우선은 역할 관점에서 보셔야 합니다.

    API를 만들어내고 호출하는 것이 클라이언트의 역할이라고 하면 거기에서 검증을 해서 보내줘야 하고,

    API를 처리하는 서버가 API를 만들어내고, 검증하는 역할을 가진다면 클라이언트는 그냥 그대로 전달하는게 맞습니다.


    API를 호출하기 위해 필요한 요청 파라미터 항목들을 클라이언트가 알고 호출해야 하는 상황이라고 하면,

    url에서 파싱을 해서 API 호출 URL을 만들때 불필요한 요청 파라미터 필드는 제외하는 것이 맞습니다.


    queryString에 포함된 불필요한 요청 파라미터들을 제외해도 얻을 수 있는 이득이 없다고 하셨는데요.

    음. 그건 마치 죽어있는 코드들, 사용하지 않은 메소드, 주석을 그대로 남겨놓는 것과 같아요.

    그걸 없앤다고 해도 프로그램이 실행하는데 아무런 영향이 없는 것은 사실입니다만,

    나중에 코드를 유지보수하고 변경하는데 사용하지 않는 코드들이 부담이 주게 됩니다.


    말씀하신 사례에서도 동일합니다.

    명시적으로 API를 호출하기 전에, 파라미터를 파싱해서 API 쪽에 다시 URL을 만들어 호출하도록 작성하면,

    그 코드를 보자마자 이 파라미터들만 필요하구나 하는 것을 바로 알수 있습니다.

    하지만 그렇게 하지 않고 그냥 queryString을 그대로 전달하고 있다고 하면 그 지점에서 전달되는 것들이 뭐가 있는지를 추적해봐야하고,

    거기에서 필요하지 않은 파라미터들이 섞여서 전달되고 있을 때, 그게 이 API호출에서 의미가 있는 것인지 아닌지를  API명세서를 보든지, API 구현을 보든지 하는 식으로 다시 확인해야 하게 됩니다.

    API가 단순하고 파라미터 개수가 적으면 모르겠으나 API가 복잡하고 파라미터들이 많다면, 어떤 변경에 대해 영향도를 평가하는 것이 굉장히 부담스러워질 수가 있어요.


    아무튼 지금 당장 편하기 위해서 그냥 넘어가는 것들이 기술 부채로 남게 됩니다.

    사용하지 않는 죽은 코드는 삭제하는 것이 맞구요,

    사용하지 않는 파라미터도 전달하지 마세요.


    저는 모든 API에서 공유하는 거대한 Request 객체를 사용하는 스타일도 싫어하고,

    클라이언트가 만들어낸 parameterMap을 map 형태 그대로 컨트롤러에서 sql까지 바이패스 하는 스타일도 싫어합니다. :)

    불필요한 것은 다 걷어내고, 모든 것을 가급적 명확하게 작성하는 것이 좋습니다.

  • Frudy
    6k
    2020-10-08 07:34:00

    음 정말 뛰어나시네요.

    근거가 좋네요. 바로 납득되는 근거에요.


    좋은회사가면 이런 노하우 옆에서 얻고싶어요.


    생각의폭이 좁아서 답변자님 만큼 생각을 못하니까요.


    이런건 으디서배우는지 ㅋㅋㅠㅠㅠ


    좋은답변 정말 감사드리구요.

    좋은하루보내세요.

  • 유리세계
    3k
    2020-10-08 09:27:29

    Url 이 거슬리신다면

    POST를 쓰면 되지 않을까요?

  • Frudy
    6k
    2020-10-08 12:46:12

    음 정확히는 모르겠지만,

    SQL과 HTTP METHOD는

    GET = select

    POST = insert

    UPDATE = update

    DELETE = delete


    이런관계가있으니

    꼭 지키라는 얘기를 어디서 들었어요.


    그래서 리스트가져오는건

    select밖에 없어서 GET으로만 쓰려구했었어요.

  • 웹개발자 화이팅
    189
    2020-10-08 13:22:36

    돈까스님께 한 수 배워갑니다.

  • 돈까스
    4k
    2020-10-08 15:19:20

    제 경험에는 단순한 CRUD가 아닌 검색 API들은... 그렇게까지 GET으로만 완벽하게 구현가능하지는 않은 것 같습니다.


    검색이 단순히 PK나 FK, 하나 필드로만 가져온다면 괜찮은데요,

    검색하기 위해서 사용하는 파라미터가 굉장히 긴 경우도 있고,

    검색을 위해 단순한 쿼리스트링이 아닌 복잡한 객체나 배열등을 던져야 하는 경우도 있고,

    그런 경우에 json으로 바꾼뒤에 url 인코딩을 하거나, 어떤 식으로 url에서 사용가능하게 인코딩을 해서 던지기도 하지만,

    그냥 적당히 현실과 타협해서 검색을 위한 데이터를 json 으로 만들어 POST로 서버에 전달하는게 나은 것 같습니다.


    혹시 이런 경우에 좋은 아이디어가 있으면 알려주세요.


  • Frudy
    6k
    2020-10-08 19:59:17 작성 2020-10-08 20:00:42 수정됨

    그리구요 


    API를 만들어내고 호출하는 것이 클라이언트의 역할이라고 하면 거기에서 검증을 해서 보내줘야 하고,

    API를 처리하는 서버가 API를 만들어내고, 검증하는 역할을 가진다면 클라이언트는 그냥 그대로 전달하는게 맞습니다.

    ㅡㅡ

    이게 무슨말인지 모르겠어요.

    예시나 혹은 관련링크를 얻을수있을까요?


    첫줄부터 읽어보면..

    API를 만드는건 개발자...아니에요?


    API호출하는게 클라이언트역할??

    역할이라기보다 그냥... 호출하는쪽이 클라이언트고

    호출되서 응답을 주는쪽이 서버라고 배웠어요.


    API를 검증하는 역할을 가진다면...?

    ? API를 검증하는게 무슨뜻인지 모르겠어요.


    서버는 항상 클라이언트로부터 받은 요청이 유효한지 검사해야한다고 배웠는데

    이걸 API를 검증한다라고 하나요?


    그 밑에는 이해가되요.

  • kiete1
    459
    2020-10-08 21:47:58

    프론트엔드, 백엔드 양쪽 다 요청 데이터를 최대한 걸러주는 게 생산성, 보안성 측면에서 이득이죠

  • Frudy
    6k
    2020-10-08 22:22:49

    프론트엔드, 백엔드 양쪽 다 요청 데이터를 최대한 걸러주는 게 생산성, 보안성 측면에서 이득이죠


    생산성은 돈까스님 예시 덕분에 이해를 했지만

    보안성 측면은 잘 예상이 안되네요.


    혹시 부연설명이나 링크 또는 예시를 달아주실 수 있나요?

  • 돈까스
    4k
    2020-10-08 22:58:01 작성 2020-10-08 23:06:39 수정됨

    API를 만들어내고 호출하는 것이 클라이언트의 역할이라고 하면 거기에서 검증을 해서 보내줘야 하고,

    API를 처리하는 서버가 API를 만들어내고, 검증하는 역할을 가진다면 클라이언트는 그냥 그대로 전달하는게 맞습니다.

    ㅡㅡ

    이게 무슨말인지 모르겠어요.


    음 그 내용은 새벽에 졸려서 대충 썼나봐요.

    API를 처리하는 서버가 API를 만들어낸다는 것은 지금보니 이상한 말이긴 하네요.


    역할을 3개로 나눠서 생각하면서 썼는데 명확하게 구분해서 쓰지 않아서 그렇게 된 것 같습니다.

    클라이언트(javascript 환경), 웹서버, API 서버 이렇게 세 역할이 나눠져 있는 것을 가정한 상태에서 글을 쓴 것이고요.

    졸린 상태로 너무 한번에 줄여서 간단하게 말하려다 보니 비문이 됐네요.


    첫줄부터 읽어보면..

    API를 만드는건 개발자...아니에요?

    -> API를 만든다는 것은 API 호출을 하는 request 를 생성해서 호출하는 것을 말하려고 했던 건데요.

    그 역할을 누가 담당하는지에 대해서 말하려고 했습니다.

    개발자의 역할을 나눠서 생각해보면 클라이언트 개발자, 웹서버 개발자, API 서버 개발자로 나눌 수 있구요.


    API 호출을 어떻게 할지를 명세서를 통해서 하는 방법도 있습니다만,

    API 서버 개발자가 클라이언트 모듈을 만들어서 클라이언트 개발자에게 전달하는 방법도 있죠.

    아예 명시적으로

       SearchAPI.getData(title, searchText) 

    이렇게 사용하도록 SearchAPI 라는 라이브러리를 제공해주는 겁니다.

    그럼 클라이언트 개발자는 API 명세서를 굳이 보면서 url을 만들어서 호출할 필요가 없습니다.


    개발자가 동일한 사람이면 이런 일이 불필요하게 느껴질수도 있습니다만,

    이런 식으로 만들게 되면 나중에 API 명세를 변경하는 것이 쉬워집니다.


    API호출하는게 클라이언트역할??

    역할이라기보다 그냥... 호출하는쪽이 클라이언트고

    호출되서 응답을 주는쪽이 서버라고 배웠어요.

    -> 제가 명확하기 쓰지 못했네요.

    API 요청을 명세에 맞게 만들어내서 호출하는 것이 클라이언트의 역할이라고 썼어야 보다 정확한 표현이었을 것 같습니다.


    API를 검증하는 역할을 가진다면...?

    ? API를 검증하는게 무슨뜻인지 모르겠어요.

    -> API 요청을 명세에 맞게 정확히 만들어서 호출했는지 검증하는 역할이 누구에게 있느냐를 말한것입니다.

    위에서 말한 것처럼 직겁 HTTP Request를 만들어서 클라이언트가 요청한다면 그건 클라이언트 쪽의 책임이 되는 것이고, API 서버에게 제공한 라이브러리를 이용한다면 API 서버 파트에서 담당해야 하는 역할이 됩니다.


    서버는 항상 클라이언트로부터 받은 요청이 유효한지 검사해야한다고 배웠는데

    이걸 API를 검증한다라고 하나요?

    -> 음. 틀린 말씀은 아닌데 검증 없이 garbage in, garbage out 철학을 적용하는 경우도 있죠.

    검증없이 쓰레기 값이 오면 그냥 처리해서 쓰레기 결과를 돌려주는 것입니다.

    예를 들자면 searchText가 empty string이어도 그냥 like 검색에 전달해서 매칭되는지 보는거죠...

    이런 동작에 대한 정의는 명세서에서 어떻게 정하는지 나름일 것이고요,


    API 서버 측에서 고민없이 그런식으로 만들었다고 하면,

    API 파라미터에 대한 검증 책임을 클라이언트 파트에 전가하는 것과 같은 이야기입니다.

    클라이언트 파트조차 고민하지 않았다고 하면, 그건 완전히 사용자 책임으로 넘기는 것이고요.

    그렇게 되면 서비스 사용자가 입력을 잘 하도록 교육을 시켜야겠죠. :)

    (검색창에 빈 문자열은 넣지 말아주세요. 데이터 조회는 1년만 하세요. %문자 조심해서 넣어주세요...)

    사내에서만 사용하는 서비스는 그렇게 만들기도 합니다만... 뭐...


    보안성 측면은...

    음 뭐, 파라미터를 검증하지 않고 그대로 전달하다보면,

    정상적인 sql mapper나 orm을 사용했다고 하면 거의 당할일은 없겠지만 sql injection을 당할수도 있고,

    불필요한 데이터를 많이 전달해서 문제가 생기도록 하는 공격을 당할수도 있겠죠.


  • Frudy
    6k
    2020-10-08 23:44:45 작성 2020-10-08 23:48:36 수정됨

    개발자가 동일한 사람이면 이런 일이 불필요하게 느껴질수도 있습니다만,

    이런 식으로 만들게 되면 나중에 API 명세를 변경하는 것이 쉬워집니다.

    //

    저도 이부분에 의견이있어요.


    개발자가 동일한 사람이어도 뭔가 규칙을 안정해놓으면

    분명 내가 만든건대 내가 햇갈릴때가 분명히 있더라구요.


    그래서 저는 저 혼자 개발할때도 마치 누구랑같이 만드는것처럼 하려고 노력을 기울이고있어요.


    ㅡㅡㅡ


    이렇게 사용하도록 SearchAPI 라는 라이브러리를 제공해주는 겁니다.

    그럼 클라이언트 개발자는 API 명세서를 굳이 보면서 url을 만들어서 호출할 필요가 없습니다.

    //

    오우..이런건 첨보네요.

    저는 항상 스웨거같은 API 설명서 보고 그거에 맞춰서 호출하고 성공처리하고 에러처리했는데..


    아무튼,


    API 서버에게 제공한 라이브러리를 이용한다면 API 서버 파트에서 담당해야 하는 역할이 됩니다.

    //

    이 케이스에 대해 말씀해주신 햇갈렸던 내용은 전부 이해됬습니다.


    조금 생소한건,

    "API 요청을 명세에 맞게 만들어내서"


    요청을 만든다 라고 표현을 하시는데,

    저는 항상 요청을 한다 라는 표현을 썼었어요.


    물론 request객체를 전달하기 때문에 요청을 만든다는 말이 더 정확한말이겠네요.


    ㅡㅡㅡ


    음 뭐, 파라미터를 검증하지 않고 그대로 전달하다보면,

    정상적인 sql mapper나 orm을 사용했다고 하면 거의 당할일은 없겠지만 sql injection을 당할수도 있고,

    불필요한 데이터를 많이 전달해서 문제가 생기도록 하는 공격을 당할수도 있겠죠.


    네 확실히 그렇네요.

    location.search의 search부분을 그대로 전달하게될경우....

    아직 잘 모르겠지만 sql문 만들 때 불필요한걸 알아서 없애주는게 있나보네요?

    만약 불필요한걸 안없애주는걸 쓴다.. 그런데 search부분이 굉장히 길다...? 공격지점이 충분히 되겠네요.


    where절로 뒤에 쭉 조건이 수만개가 들어가는 상상을 잠시 해보았으나 어우...

    극혐이네요. FE개발자로써 꼭 제거하고 요청보내겠습니다..


    ㅡㅡㅡ


    추가로, 저는 초보라서 뛰어난 개발자분이 설명하면 저게 무슨말인지 이해를 못하는경우가 많았어요.

    그럼에도 불구하고 돈까스님의 답변은 정말 잘 이해가 되요.

    글 잘쓰는 개발자가 개발도 잘한다는데~~ 돈까스님 덕분에 많이배워갑니다.


    정말 이런 질문글에 이렇게 정성스럽게 답변 달아주셔서 너무 감사드립니다.

    복받으실거에요.

  • 돈까스
    4k
    2020-10-09 00:36:17

    제가 뭐 뛰어난 개발자는 아니고, 그냥 그런 주제로 고민을 조금 더 많이 해봤을 뿐인거 같아요.

    뭐 고민만 많이 했지 내세울만한 서비스나 솔루션을 만들어보지도 못했습니다. :(

    저는 이런 이야기 하는 것 좋아하는데 제가 있는 회사에서는 이런 주제를 나눌 사람도 없고, 기회도 없네요. :)


  • Frudy
    6k
    2020-10-09 00:41:45

    아무튼 복받으실거에요.

  • 로그인을 하시면 댓글 을 등록할 수 있습니다.