Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 8
Tags: react, java, typescript, javascript
Published: 2021-03-10 04:38:38

# 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](https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n) 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

  ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mcnzflm8vjwnvjcx40sh.PNG "Successful Run")

- 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!.

## Next

### Follow to get informed when part nine is released, where we will cover the post voting functionality! If you have any questions be sure to leave a comment!