토이프로젝트: 공감 기능 만들기(1)

글에 공감할 수 있는 기능인 좋아요 버튼을 만드는 중이다.

서버 DB table 만들기

  • 필요한 정보: 사용자가 공감한 글
    • id, user id, post id
    • create, update date는 아직 왜 있는지 모르겠으나, 읽은 목록을 구현할 때 유용하게 사용하리라 보아 추가하였다.

  • uuid를 생성할 때 3rd party로 설치하고 uuid_generate_v4로 default값을 주면 된다고 한다.

why DB?

  • 공감을 하면 하트가 눌러진 표시가 된다! DB, 캐싱, local state일지 모를 땐 요구사항을 명세해보면 된다.
  • 요구사항
    • 공감을 누르면 button에 계속 눌러진 표시가 나야한다: local state
    • 브라우저 혹은 세션을 종료해도 다시 이 글을 눌렀을 때 계속 눌러진 표시가 나야한다: 캐싱
    • 다른 기기로 접속해도 계속 눌러진 표시가 나야한다: DB
  • 이렇게 순서대로 생각해보면 쉽다.

공감을 누른 velog 예시 화면

REST API 만들기

글에대한 공감 정보 가져오는 GET API

  • user가 특정 post를 like 했는지 가져온다.
/:userName/liked/:postId
  • table에 있는지 체크만하는 select 쿼리 사용

공감, 공감 취소하는 POST API

  • user가 특정 post를 like하거나 unlike한 api
/:userName/like/:postId
/:userName/unlike/:postId
  • table에 insert하거나 delete하는 쿼리를 사용
    • INSERT INTO public."POST_LIKES" ~ VALUES ~
    • DELETE FROM public."POST_LIKES" WHERE ~
  • 사실 db 업데이트 전에 사전 조건을 체크해야 하는데, 이미 데이터가 있는지 post는 존재하는지를 확인해야한다.
    • post가 있는지 select 문으로 확인하고 없으면 404 에러를 반환
    • post가 있으나, 이미 공감/비공감 처리된 데이터면 204나 304로 HTML error state 의미를 참고하여 반환하였다.
  const postResult = await dbConn.query(`SELECT id FROM public."BLOG_POSTS" WHERE ~`);
  if (postResult.rowCount === 0) {
    return response.status(404).json({ err: 'Post Not Found' });
  }

  const alreadyLiked = await dbConn.query(
    `SELECT id FROM public."POST_LIKES" WHERE ~
  );
  if (!alreadyLiked.rowCount) {
    return response.status(204).json({ err: 'Post Not Liked' });
  }
  • 후속작업으로 post table에 like된 모든 count값도 있어서 sync를 맞춰야 하는데 sql로 수동으로 업데이트 했는데 맞는지 모르겠다.
  const countResult = await dbConn.query(
    `SELECT COUNT(*) FROM public."POST_LIKES" WHERE ~;`
  );

  try {
    await dbConn.query(
      `UPDATE public."BLOG_POSTS" SET ~ WHERE ~;`
    );
  } catch (e) {
    return e;
  }

좋아요한 모든 글의 목록을 보여주는 GET API

  • readling list 기능을 도드라지게 'readingList' 키워드를 먼저 앞세웠으나 오류인거 같다..
/readingList/:userName/liked/
  • 의논사항: reading list 자원은 user에게 속하니 순서를 바꿀것인가?
/:userName/readingList/liked/

문제점

post id(uuid)를 이용하니 post를 api로 받은 후에 요청해야하는 비효율적 형태가 되었다.

  useEffect(() => {
    axios({
      baseURL: API_HOST,
      url: `/@${userId}/${urlSlug}`,
    })
      .then(response => {
        const _post = response.data;
        setPost(_post);
        axios({
          baseURL: API_HOST,
          url: `/${userId}/liked/${_post.id}`,
        }).then(reponse => {
          setLiked(reponse.data.length !== 0);
        });
        console.log(response.data);
      })
      .catch(error => {
        console.error(error);
      });
  }, [userId, urlSlug]);
  • 그래서 해결방법으로 post url로 별도로 요청하는 방법을 생각 중이다.
    • api 수정:/${userId}/liked/${urlSlug},
    • 내부적으로 db에서 urlSlug로 post id를 select하여 다시 like 정보를 select하는 중첩 select 쿼리를 쓸 예정이다.

TODO

  • user like api 수정
  • 공감 component 구현 완료
  • 읽은 목록 page 구현

좋은 웹페이지 즐겨찾기