Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 8
Introduction
Welcome to Part 8 of creating a Reddit clone using Spring Boot, and React.
What are we building in this part?
- Vote DTO
- Vote Exception
- Vote Service
- Vote Controller
In Part 7 we added the CREATE && READ endpoints for creating and reading comments!!
Important Links
- Backend Source: https://github.com/MaxiCB/vox-nobis/tree/master/backend
- Frontend Source: https://github.com/MaxiCB/vox-nobis/tree/master/client
- Live URL: In Progress
Part 1: Vote DTO π¨
Let's cover our the DTO's we will need for receiving and sending Vote information. Inside com.your-name.backend.dto we will create the following class.
- VoteDTO: Handles creation of the data that will be sent from the client to the API.
import com.maxicb.backend.model.VoteType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VoteDTO {
private VoteType voteType;
private Long id;
}
Part 2: Vote Exception π«
Let's cover our custom exceptions we will need. Inside com.your-name.backend.exception we will create the following class.
- VoteException: Handles exceptions related to looking for a invalid user.
package com.maxicb.backend.exception;
public class VoteException extends RuntimeException {
public VoteException(String message) {
super(message);
}
}
Part 3: Vote Service π
Let's cover the vote service our application will have. Inside com.your-name.backend.services add the following class.
- VoteService: Hold the logic for mapping data to and from DTO's, and adding votes to a post.
package com.maxicb.backend.service;
import com.maxicb.backend.dto.VoteDTO;
import com.maxicb.backend.exception.PostNotFoundException;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.Vote;
import com.maxicb.backend.repository.PostRepository;
import com.maxicb.backend.repository.VoteRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static com.maxicb.backend.model.VoteType.UPVOTE;
@Service
@AllArgsConstructor
public class VoteService {
private final VoteRepository voteRepository;
private final PostRepository postRepository;
private final AuthService authService;
private Vote maptoVote(VoteDTO voteDTO, Post post) {
return Vote.builder()
.voteType(voteDTO.getVoteType())
.post(post)
.user(authService.getCurrentUser())
.build();
}
@Transactional
public void vote(VoteDTO voteDTO) {
Post post = postRepository.findById(voteDTO.getId())
.orElseThrow(() -> new PostNotFoundException("Post not found with id:" + voteDTO.getId()));
Optional<Vote> votePostAndUser = voteRepository.findTopByPostAndUserOrderByVoteIdDesc(post, authService.getCurrentUser());
if(votePostAndUser.isPresent() && votePostAndUser.get().getVoteType().equals(voteDTO.getVoteType())) {
throw new PostNotFoundException("You've already " + voteDTO.getVoteType() + "'d this post");
}
if(UPVOTE.equals(voteDTO.getVoteType())) {
post.setVoteCount(post.getVoteCount() + 1);
} else {
post.setVoteCount(post.getVoteCount() - 1);
}
voteRepository.save(maptoVote(voteDTO, post));
postRepository.save(post);
}
}
Part 4: Vote Controller π
Let's cover the vote controller our application will have. Inside com.your-name.backend.controller add the following class.
- VoteController: Hold the endpoints adding votes to a specific post.
package com.maxicb.backend.controller;
import com.maxicb.backend.dto.VoteDTO;
import com.maxicb.backend.service.VoteService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/vote")
@AllArgsConstructor
public class VoteController {
private final VoteService voteService;
@PostMapping
public ResponseEntity<Void> vote(@RequestBody VoteDTO voteDTO) {
voteService.vote(voteDTO);
return new ResponseEntity<>(HttpStatus.OK);
}
}
Conclusion π
- To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below
- If there are no error's in the console you can test the voting logic by sending a post request to http://localhost:8080/api/vote with the following data. You will still have to follow the same steps covered in the previous parts to login to an account to make post's, as well as create a subreddit, and valid post to add a comment to.
{
"voteType": "UPVOTE",
"id": <post-id>
}
- You can now make a GET reguest to http://localhost:8080/api/posts/ to see the voteCount change on the post you just upvoted.
{
"postId": 9,
"postTitle": "Testing Post",
"url": "URL",
"description": "DESCRIPTION",
"userName": "USERNAME",
"subredditName": "/r/NAME",
"voteCount": 1,
"commentCount": 1,
"duration": "4 hours ago",
"upVote": true,
"downVote": false
}
- In this article we implemented the logic for voting on post's!.
Top comments (0)