API 구조 변경

권태형·2023년 1월 29일
0

이집은

목록 보기
8/12

어느 글에서 읽은 기억이 있다.

'코딩은 생산적인 작업이며 창조적인 작업이다. 내가 코딩으로 무엇을 만들 때 그것에 제한을 두는 것은 맞지만 그건 無에서부터 제한이라는 것을 만드는 것이지, 처음부터 제한 되었던 것은 아니다.'

정확한 기억은 아니지만 대충 이런 내용이었다. 물론 'RESTful하게 API를 짜야한다'같은 코딩에서 지켜야할 틀이나 제한은 존재한다. 하지만 이 또한 협업함에 있어 서로의 코드가 잘 맞게? 하기 위한 하나의 방법이고 우리가 제한을 만든 것일 뿐! 반드시 이렇게 하지 않으면 코드가 동작하지 않는다는 원초적 제한은 아니다.

나는 코딩을 시작한지 벌써 80일이 넘었다. 그런데 아직도 많은 고정관념을 가지고 정보의 바다에서 얻은 믿지 못 할 정보를 그대로 믿고 행하는 사이비 신도가 되어 있었다. 솔찍하게 정확한 기억인지 어디서 읽은 기억인지 모르겠으나, 하나의 API는 하나의 동작을 하도록 설계하는게 좋다고 어디선가 읽었는지 모를 이상한 고정관념이 있었다.

그래서 이번 코드를 설계하면서 게시글의 전체조회를 각 특성에 나눠서 댓글순서로 정렬API, 최신순서로 정렬API, 검색어에 맞는 게시글 전체조회API등 세가지로 나눠서 API를 3개를 따로따로 만들었다.

실제로 지금 이 블로그를 작성하고있는 Velog 또한 주소창을 보면서 각 API를 호출했을때 URL이 달라지는 것을 확인 할 수 있다. 당연히 여긴 개발자들이 주로 이용하는 블로그이며, 이런식의 벤치마킹이 좋다고 생각해서 그렇게 작성한 점도 있었다.

//지역 게시글 댓글 순 조회
postRouter.get('', getApiLimiter, postController.getLocationPosts);
//지역 게시글 최신 순 조회
postRouter.get('/recent', getApiLimiter, postController.getRecentPosts);
//검색한 게시글 (제목, 내용, 작성자) 조회
postRouter.get('/search', postController.getSearchedPost);

위와 같이 router를 나눠서 각 API가 각각의 기능을 하도록 설계 했었다. 3계층 구조로 나누어서 진행한 작업이었는데 댓글순 조회를 작성한 후 최신순 조회를 작성할 때 의문점이 들었다. 두 API는 라우터의 경로와 repository의 orderBy만 다를 뿐 같은 인자를 받고 98퍼센트 같은 로직을 수행하는데 왜 나눠야 할까? 뭔가 합칠 방법은 없을까? 같은 의문이 먼저 들었다.

이러한 구조는 가질 수 없는건가? 중간 로직이 같다면 router의 URI를 가지고 service단에서 분기처리를 하면 같은 로직을 굳이 여러번 쓸 필요 없을 것이라는 생각이 들었는데 정보의 바다에서 어떻게 검색을 해야할 지 몰라서 마구잡이로 검색해서 그런지 전혀 관련정보를 얻을 수 없어서 일단 MVP에 맞춰 따로 따로 작성했었다.

어쨋든 저쨋든 위와 같은 구조를 만드는 방법은 아무리 찾아봐도 모르겠고, 현재의 로직은 잘 굴러가고, Velog처럼 다른 게시글 파트를 가진 웹사이트 들도 각 URI를 나눠서 만든것 같아 보여서 그냥 만족하고 있었는데, 이렇게 작성하게 되면, 똑같은 API의 요청을 Front End에서는 각 URI에 대해서 같은작업을 여러번 해야한다고 한다.

당연하지! 나도 같은작업을 여러번했으니까....^^;; 이게 맞다! 라고 하진 않았다. 내가 현재 생각 할 수 있던 방법이 이 것 뿐이었을 뿐!

이 부분에 대해서 '하나의 요청으로 모두 가능한 것 아닌가요?' 라는 질타를 매니저님께 받았다. 생각하지도 않았던 부분이었다. 나는 API하나는 하나의 동작만 하는게 맞다고 생각해서 전체조회를 하지만! 어쨋든 정렬 순서가 다르기에 다른 동작이라고 생각하고 있었기 때문이었는데, 위와 같은 말을 듣고 나서 보니 큰 동작으로 보면 전체조회가 하나의 동작인 것이고, 정렬순서가 다르거나 찾을 때 조회하는 컬럼의 기준이 다른 것은 세부적인 동작의 옵션이라고 생각할 수도 있겠다 싶었다.

따라서 비슷한 구조를 가진 세가지 코드를 하나의 구조로 바꿔서 아래와 같이 service 로직을 작성했다

 getLocationPosts = async (getPostInfo) => {
    let pageNum = 1;
    let order = [
      ['commentsCount', 'DESC'],
      ['createdAt', 'DESC'],
    ];

    const { postLocation1, postLocation2, page, type, search } =
      await getpostValidation.validateAsync(getPostInfo);

    if (!postLocation1 && postLocation2) throw badRequest('지역선택1 없음');

   //검색어 sequelize의 OP문법 like를 사용해서 내용 제목 이메일 어느것이든 일치하는 내용물을 모두 가져옴
    const searchObject = {
      [Op.or]: [
        { content: { [Op.like]: `%${search}%` } },
        { title: { [Op.like]: `%${search}%` } },
        { email: { [Op.like]: `%${search}%` } },
      ],
    };

    let whereLocation = {};

   //OP문법 and를 사용해서 커뮤니지 지역별 구분에 맞게 설정할 수 있도록 함
    if (postLocation1) {
      whereLocation = postLocation2
        ? { [Op.and]: [{ postLocation1 }, { postLocation2 }, searchObject] }
        : { [Op.and]: [{ postLocation1 }, searchObject] };
    } else whereLocation = searchObject;
    if (page) pageNum = page;
   
   //최신순, 트랜드순 정렬 분기처리해서 정렬 방법을 변경
    if (type === 'recent') order = [['createdAt', 'DESC']];
    if (type === 'trend')
      order = [
        ['commentsCount', 'DESC'],
        ['createdAt', 'DESC'],
      ];

    const posts = await this.postRepository.getLocationPosts(
      whereLocation,
      pageNum,
      order,
    );

    return posts;
  };

내가 작성한 코드가 정답은 아닐 것이라 생각한다. 물론 정상 동작은 하지만 로직이 너무 구리고 복잡해 보인다. 위의 코드 처럼 현재 상세게시글, 이전게시글, 다음게시글 이라는 비슷한 로직을 가진 API또한 하나의 API로 통합하는 과정중에 있는데 오히려 전체 조회의 서비스 로직 코드는 43줄로 마무리 되었지만 상세조회는 현재80줄이 넘어가고 있다. 이게 맞나..? 싶은 생각으로 작성 중 이기는 한데... 잘 모르겠다. 확신을 가지고 코드는 언제쯤 짤 수 있을지..

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.

0개의 댓글