Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 행사 생성 기능 구현 #41

Merged
merged 2 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package server.haengdong.application;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import server.haengdong.application.request.EventAppRequest;
import server.haengdong.application.response.EventAppResponse;
import server.haengdong.domain.Event;
import server.haengdong.domain.EventTokenProvider;
import server.haengdong.persistence.EventRepository;

@RequiredArgsConstructor
@Service
public class EventService {

private final EventRepository eventRepository;
private final EventTokenProvider eventTokenProvider;

public EventAppResponse saveEvent(EventAppRequest request) {
String token = eventTokenProvider.createToken();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[R] 중복된 토큰이 생성될 수 있으니 저장 전에 검증을 한 번 해 주면 좋을 것 같습니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매 초 100만개의 UUID를 100년동안 생성할때 0.00009% 확률로 중복이 발생합니다. 라고 하는데 굳이 검증을 해야할까요?
DB에서 unique 조건을 한 번 걸어주는 것만으로 충분하다고 생각합니다.

Event event = request.toEvent(token);
eventRepository.save(event);

return EventAppResponse.of(event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package server.haengdong.application.request;

import server.haengdong.domain.Event;

public record EventAppRequest(String name) {

public Event toEvent(String token) {
return new Event(name, token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package server.haengdong.application.response;

import server.haengdong.domain.Event;

public record EventAppResponse(String token) {

public static EventAppResponse of(Event event) {
return new EventAppResponse(event.getToken());
}
}
5 changes: 5 additions & 0 deletions server/src/main/java/server/haengdong/domain/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ public class Event {
private String name;

private String token;

public Event(String name, String token) {
this.name = name;
this.token = token;
}
Comment on lines +24 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[R] : name 검증이 없는 것 같아요.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package server.haengdong.domain;

import java.util.UUID;
import org.springframework.stereotype.Component;

@Component
public class EventTokenProvider {

public String createToken() {
return UUID.randomUUID().toString();
}
}
Comment on lines +6 to +12
Copy link
Contributor

@Arachneee Arachneee Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[R] EventTokenProvider 생성 정책이 바뀔 가능성이 있을 것 같은데 인터페이스로 하는 것은 어떨까요?
test에서도 모킹을 하지 않고 함수형 인터페이스를 활용할 수 있을 것 같아요.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package server.haengdong.persistence;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import server.haengdong.domain.Event;

@Repository
public interface EventRepository extends JpaRepository<Event, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package server.haengdong.presentation;

import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import server.haengdong.application.EventService;
import server.haengdong.application.response.EventAppResponse;
import server.haengdong.presentation.request.EventSaveRequest;

@RequiredArgsConstructor
@RestController
public class EventController {

private final EventService eventService;

@PostMapping("/api/events")
public ResponseEntity<Void> saveEvent(EventSaveRequest request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[R] : @RequestBody 를 안붙여도 잘 동작하나요?
명시적으로 붙이는 것이 어떨까요?

EventAppResponse eventAppResponse = eventService.saveEvent(request.toAppRequest());

return ResponseEntity.ok()
.location(URI.create("events/" + eventAppResponse.token()))
.build();
Comment on lines +22 to +24
Copy link
Contributor

@Arachneee Arachneee Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[R] create()를 사용해서 status code를 201로 하는 것은 어떨까요?
201이 아니면 location 헤더가 있는지 예측하기 어려울것 같습니다.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package server.haengdong.presentation.request;

import server.haengdong.application.request.EventAppRequest;

public record EventSaveRequest(String name) {

public EventAppRequest toAppRequest() {
return new EventAppRequest(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package server.haengdong.application;


import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import server.haengdong.application.request.EventAppRequest;
import server.haengdong.application.response.EventAppResponse;
import server.haengdong.domain.EventTokenProvider;

@SpringBootTest
class EventServiceTest {

@Autowired
private EventService eventService;

@MockBean
private EventTokenProvider eventTokenProvider;

@DisplayName("행사를 생성한다")
@Test
void saveEventTest() {
EventAppRequest request = new EventAppRequest("test");
given(eventTokenProvider.createToken()).willReturn("TOKEN");

EventAppResponse response = eventService.saveEvent(request);

assertThat(response.token()).isEqualTo("TOKEN");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package server.haengdong.presentation;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import server.haengdong.application.EventService;
import server.haengdong.application.request.EventAppRequest;
import server.haengdong.application.response.EventAppResponse;
import server.haengdong.presentation.request.EventSaveRequest;

@WebMvcTest(EventController.class)
class EventControllerTest {

@Autowired
private MockMvc mockMvc;

@Autowired
private ObjectMapper objectMapper;

@MockBean
private EventService eventService;

@DisplayName("이벤트를 생성한다")
@Test
void saveEvent() throws Exception {
EventSaveRequest eventSaveRequest = new EventSaveRequest("test");
String requestBody = objectMapper.writeValueAsString(eventSaveRequest);
String token = "TOKEN";
EventAppResponse eventAppResponse = new EventAppResponse(token);
given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse);

mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token));
}
}