나는 현재 치과 기록 및 커뮤니티로 치아 건강을 관리하는 서비스 투스데이 백엔드 개발 중 커뮤니티 기능 대부문을 맡아서 개발하고 있다.

 

그런데, 커뮤니티 기능을 모두 개발하고 전체 api 테스트를 해보던 와중 좋아요 취소 부분에서 에러가 발생했다.

 

"timestamp": "2024-07-14T04:00:10.191+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 2; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 2\\r\\n\\tat org.springframework.orm.jpa.

 

 

내용을 보니 query did not return a unique result 하나만 정의되어있어야 하는 값이 중복되어 있는 것 같다.

db를 살펴보니 역시나 한 명의 유저가 하나의 게시글에 좋아요를 두번 눌러 버렸다.

직전에 좋아요 등록 테스트를 할 때 같은 정보로 2번 눌렸고 아무런 저항 없이 새로운 좋아요가 생성되어 버린 것이다.

@PostMapping("/api/community/{postId}/like")
    public ResponseEntity<String> like(@PathVariable Long postId, 
																		   HttpServletRequest request) {
        String token = request.getHeader("Authorization").replace("Bearer ", "");
        Long userId = JwtUtil.getUserIdFromToken(token);
        User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
        
        Post post = postRepository.findById(postId);
        PostLike like = new PostLike();
        like.setUser(user);
        like.setPost(post);
        likeService.save(like);
        return ResponseEntity.ok("Like successful");
    }

    @DeleteMapping("/api/community/{postId}/like")
    public ResponseEntity<String> unlike(@PathVariable Long postId, HttpServletRequest request) {
        String token = request.getHeader("Authorization").replace("Bearer ", "");
        Long userId = JwtUtil.getUserIdFromToken(token);
        
        Post post = postRepository.findById(postId);
        PostLike like = likeService.findByPostIdAndUserId(postId, userId);
        if(like!=null) {
            likeService.delete(like);
            return ResponseEntity.ok("Like Delete successful");
        } else {
            return ResponseEntity.ok("Like not found");
        }
    }

내가 작성한 좋아요 등록, 취소 api이다.

 

public PostLike findByPostIdAndUserId(long postId, long userId) {
        try {
            return em.createQuery("select pl from PostLike pl where pl.post.id=:postId and pl.user.id=:userId", PostLike.class)
                    .setParameter("postId", postId)
                    .setParameter("userId", userId).getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

 

당연하게도 유저 한 명당 게시글 하나에 좋아요를 한번만 누를 수 있다고 생각하였고 postId와 userId를 사용해서 좋아요를 찾아내고 삭제하도록 설계하였다.

 

그리고 위와 같이 좋아요가 2개 이상 생성되어 있으니 삭제할 수 없는 문제가 발생한 것이다.

 

 

생각해보니 좋아요는 등록/취소 api를 따로 설계하지 말고

하나의 api만으로 좋아요가 눌려있다면 → 취소, 좋아요가 눌려있지않다면 → 등록 이렇게 로직을 짜주면 될 것 같았다. 

 

 

@PostMapping("/api/community/{postId}/like")
    public ResponseEntity<String> like(@PathVariable Long postId, HttpServletRequest request) {
        String token = request.getHeader("Authorization").replace("Bearer ", "");
        Long userId = JwtUtil.getUserIdFromToken(token);
        User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
        Post post = postRepository.findById(postId);
        PostLike isLiked = likeService.findByPostIdAndUserId(postId, userId);
        if (isLiked == null) {
            PostLike postLike = new PostLike();
            postLike.setPost(post);
            postLike.setUser(user);
            likeService.save(postLike);
            return ResponseEntity.ok("Like successful");
        }
        else {
            likeService.delete(isLiked);
            return ResponseEntity.ok("Like Deleted successful");
        }
    }

 

성공하였다!

+ Recent posts