요청 응답을 어떻게 보내야할까2 -Sequelize

codeing999·2022년 8월 15일
0

CRUD BACKEND 구현

목록 보기
7/10

{
"success": true,
"message": "회원가입에 성공하였습니다.",
"result": {
"nickname": "id8"
}
}
일단은 성공여부, 메세지, 결과 이렇게 세 부분으로 보내려고 한다. 물론 status code도 헤더에 실어서.

다만, 이번에는 저번글이랑 다른 점은,
콘트롤러, 서비스, 레포지토리 세군데에서 각각 어떻게 리턴을 해줘야할지 헷갈리는 부분을 좀 더 정리하려고 하고.

이번엔 MySQL로 하지않고 Sequelize RDB를 쓰기 때문에 쿼리 결과도 조금 다르므로 이 부분도 짚어보려고 한다.

또 한가지 고민해볼 부분은 게시물 조회같은 경우면 result로 뭘 보내야할지가 명확한데, 생성, 수정 그리고 삭제 시에는 result로 어떤 값을 넣어주는게 좋은 건지에 대한 것이다.

Controller에서

	const result = await this.commentService.createComment(userId, postId, text);
	return res.status(201).json({ ...result}) ;
//...
} catch(err){
      console.log(err);
      return res.status(400).json({ success : false, message : err.message });
    }

컨트롤러에서는 서비스를 호출한 후에 그 내용이 성공이든 리턴이든 그 값을 펼쳐서 리턴을 하면 끝난다. 이미 그전에 service에서 success가 true인지 false인지까지 담아서 리턴을 한다.

그러나 이 controller 안에서 joi 등을 통해서 error가 발생한 경우는
success : false를 직접 작성하여 응답하도록 하였다.
이 때 result라는 항목을 응답 형식의 통일성을 위해 {} 이런 식으로 빈 객체로라도 실어야 할지 그냥 생략해도 될지 고민이다.

Service에서

 try {

      //const isExistPost = await this.postRepository.isExistPost()

      const result = await this.commentRepository.createComment(userId, postId, text);
      //if (result.success === false) throw new Error('댓글 작성에 실패하였습니다.');
      return result;
      
    } catch(err){

      console.log(err);
      //return { success : false, result : `${err.name} : ${err.message}`};
      return { success : false, message : err.message };

    }

service 여기가 제일 고민되던 부분이다.
중간에 레포지토리 호출 이후 저 if문을 주석 처리한다는 거는,
repository단계에서 난 에러의 원인을 프론트엔드단계까지 전달해주겠다는 것인데 그것이 과연 프론트엔드단계에게 필요한 부분인가 하는 것이다.
예를 들면, 이 service 단계에서는
'해당 글이 없습니다', '권한을 가진 사용자가 아닙니다' 와 같은 에러를 던져줄 수가 있고 그런 것은 프론트한테 필요하다고 생각된다.
그러나 레포지토리에서 난 쿼리 실패의 원인을 프론트가 알필요가 있을까 그것을 해결해야할 필요가 있는 나한테만 console.log로 출력해서 보기만 하면 되는 것 아닐까.

일단은, 그래서 저 주석을 제거하고 실패했다고만 응답으로 넘겨주게 하기로 결정했다. 다른 실패일 땐 실패 원인을 말해주지만, 레포지토리 단계에서 난 실패는 그냥 실패했다고만 알려주는 것.
if문들로 처리하지 못한 그 외의 에러라는 거로 받아들이면 될듯.
아마도 레포지토리 단계에서 발생했을 에러라고 생각하고.

그리고 서비스에서는 위에도 말한 '해당 글이 없습니다'와 같은 에러들을 if문으로 처리해줘서 그런 에러는 콘트롤러에 에러 원인을 담아 넘겨줄 것이다.

저 주석처리된 isExistPost 부분은 게시글 담당자가 저 함수를 완성해서 넘겨주면 추가 작성할 부분이다.

에러캐치부분에서 주석처리된것처럼 잘못 작성되어있던것 발견하여 수정하였다. message로 넘겨줘야될것을 result로 담았었구나.
여기도 근데 esult : {}이런거 추가해야될지 고민.

Repository에서

    createComment = async (userId, postId, text) => {
        try {
            const result = await Comment.create({
        
                userId : userId,
                postId : postId,
                text : text
    
            });
            return { success : true, result : result.dataValues };

        } catch (err){
            console.log(err);
            return { success : false, message : err.message};
        }

여기는 쿼리가 성공하면 true고 실패하면 false인 건 맞는데.
글 조회시에야 쿼리 결과를 응답에 실어준다 하지만은
생성, 수정시에도 보내야할까, 그리고 삭제시에는 뭘보내야할까 이게 고민이다. 일단 생성, 수정시엔 그 생성하거나 수정한 내용을 실어보내게 할 생각이다.
그리고 여기서 에러캐치부분에서는 message를 작성할 필요가 없긴하다. 서비스 단계에서 그냥 댓글 작성이 실패했다고 퉁치게 될 것이기 때문.
그냥 콘솔로그를 통해 내가 쿼리실패 원인이 뭔지 알아챌 수 만 있으면 충분.

Error: 댓글 작성에 실패하였습니다.
    at CommentService.createComment (C:\Users\jcl12\OneDrive\바탕 화면\projects\mypet-back\src\layers\services\comment.service.js:15:43)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async createComment (C:\Users\jcl12\OneDrive\바탕 화면\projects\mypet-back\src\layers\controllers\comment.controller.js:21:22)

이런 식으로 콘솔에 출력.

조회 시

findByPk()는 못찾으면 null을 리턴.

조회 시 작성자까지 보내주기 위해서 join을 사용.

 const comment = await Comment.findAll( {
                where : { postId : postId},
                include : [{
                    model:User,
                    attributes:['nickname'],

                }],
                raw:true
            });
{
  "result": true,
  "data": [
    {
      "commentId": 2,
      "text": "ddd",
      "createdAt": "2022-08-15T15:29:03.000Z",
      "updatedAt": "2022-08-15T15:29:03.000Z",
      "userId": 1,
      "postId": 4,
      "User.nickname": "곰돌"
    },

그러면 위와 같은 댓글 목록이 쫙 뜨는데, 닉네임이 User.nickname으로 들어가있다. 이걸 응답할 때는 author로 바꿔서 보내줘야한다. map을 사용해서 다른 변수에 담아서 리턴하였다.

      const commentdata = comment.data.map(data => {
        return {
          commentId : data.commentId,
          text : data.text,
          createdAt : data.createdAt,
          updatedAt : data.updatedAt,
          userId : data.userId,
          postId : data.postId,
          author : data['User.nickname']
        }

      })

댓글 생성 시

성공 시 다음과 같이 리턴

return { success : true, result : result.dataValues };
{
  "success": true,
  "result": {
    "commentId": 2,
    "userId": 1,
    "postId": "1",
    "text": "ddd",
    "updatedAt": "2022-08-14T22:18:37.797Z",
    "createdAt": "2022-08-14T22:18:37.797Z"
  }
}

댓글 수정 시

댓글 수정시에는 댓글이 존재하는지 먼저
서비스에서 isExistComment를 호출한다.
그 함수는 findByPk로 쿼리하도록 되어있는데 해당 댓글을 찾으면

Comment {
  dataValues: {
    commentId: 2,
    text: 'ddd',
    createdAt: 2022-08-14T22:18:37.000Z,
    updatedAt: 2022-08-14T22:18:37.000Z,
    userId: 1,
    postId: 1
  },
  _previousDataValues: {
    commentId: 2,
    text: 'ddd',
    createdAt: 2022-08-14T22:18:37.000Z,
    updatedAt: 2022-08-14T22:18:37.000Z,
    userId: 1,
    postId: 1
  },
  uniqno: 1,
  _changed: Set(0) {},
  _options: {
    isNewRecord: false,
    _schema: null,
    _schemaDelimiter: '',
    raw: true,
    attributes: [
      'commentId',
      'text',
      'createdAt',
      'updatedAt',
      'userId',
      'postId'
    ]
  },
  isNewRecord: false
}

이 와 같이 리턴하고 못찾으면 null을 리턴한다.
isExistComment 함수는 실패 시에는 null을 리턴하고.
성공 하더라도 이 함수는 존재 여부만 판단하는 함수이므로 true를 리턴하도록 하였다.

const result = await Comment.findByPk(commentId);
            if (result === null) return null;
            else return true;

아래는 처음에
//return result.dataValues;
성공시에 이걸 리턴하도록 했을 때 리턴되는 값

result: {
  commentId: 2,
  text: '바뀐 댓글2',
  createdAt: 2022-08-14T22:18:37.000Z,
  updatedAt: 2022-08-14T22:23:07.000Z,
  userId: 1,
  postId: 1
}

이제 서비스에서는 null 인지 여부만 판단하면 된다.

update 함수는 성공 시에 [1]을 리턴한다. 실패시엔 [0]. 성공시엔 수정된 데이터들을 리턴할줄 알았더니 아니었네.

if (result[0] !== 1) throw new Error('댓글 수정에 실패하였습니다');
            return { success : true};

그래서 result[0]이 1이 아니면 실패 에러를 던지고
아니면 그냥 트루를 반환.

생성은 성공하면 그 댓글을 반환하는데 난 글쓴이까지 리턴해주고 싶어서 글목록조회 쿼리 한번 더 날림. 댓글이 작성되면 글과 댓글들 전체가 보일거기 때문에 글목록 조회를 하는 것. 여차하면 글 조회까지 같이 리턴할지도.

댓글 삭제 시

얜 성공하면 1 반환해서 수정과 비슷하다.

if (result !== 1) throw new Error('댓글 삭제에 실패하였습니다');
            return { success : true, result : result };

실패하면 0을 반환하지만, 댓글이 원래 존재하지않으면 이미 존재여부검사에서 에러처리 해놨기때문에 0일 때가 나올 일이 왠만하면 없긴하다. 그래도 알수없는 이유로 실패할 수도 있기 때문에 1 아니면 에러 던짐.

profile
코딩 공부 ing..

0개의 댓글