Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Expand Up @@ -2,22 +2,24 @@

import java.time.LocalDateTime;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import in.koreatech.koin.domain.version.model.Version;

@JsonNaming(SnakeCaseStrategy.class)
public record VersionResponse(
@JsonProperty("id") Long id,
@JsonProperty("version") String version,
@JsonProperty("type") String type,
@JsonProperty("created_at") LocalDateTime createdAt,
@JsonProperty("updated_at") LocalDateTime updatedAt) {
Long id,
String version,
String type,
LocalDateTime createdAt,
LocalDateTime updatedAt) {

public static VersionResponse from(Version version) {
return new VersionResponse(
version.getId(),
version.getVersion(),
version.getType().getValue(),
version.getType(),
version.getCreatedAt(),
version.getUpdatedAt()
);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package in.koreatech.koin.domain.version.exception;

import in.koreatech.koin.global.exception.DataNotFoundException;

public class VersionTypeNotFoundException extends DataNotFoundException {

public static final String DEFAULT_MESSAGE = "존재하지 않는 버전 타입입니다.";

public VersionTypeNotFoundException(String message) {
super(message);
}

public static VersionTypeNotFoundException withDetail(String detail) {
String message = String.format("%s %s", DEFAULT_MESSAGE, detail);
return new VersionTypeNotFoundException(message);
}
}
22 changes: 20 additions & 2 deletions src/main/java/in/koreatech/koin/domain/version/model/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import static lombok.AccessLevel.PROTECTED;

import java.time.Clock;
import java.time.LocalDate;

import in.koreatech.koin.global.domain.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down Expand Up @@ -32,11 +35,26 @@ public class Version extends BaseEntity {

@NotNull
@Column(name = "type", length = 50)
private VersionType type;
private String type;
Copy link
Member

Choose a reason for hiding this comment

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

R

이렇게 구성했을 때 enum이 필요없는 구조가 되지 않나요?
필요없다면 enum 없애는게 나아보이는데 어떻게 생각하나요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

API 파라미터와 DB 컬럼명의 일치 여부 검증 로직을 강화하는 역할로 쓰일 수 있기 때문에 남겨두는게 적절하다고 생각합니다!

Copy link
Member

Choose a reason for hiding this comment

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

음~ 알겠습니다~!


@Builder
private Version(@NotNull String version, @NotNull VersionType type) {
private Version(@NotNull String version, @NotNull String type) {
this.version = version;
this.type = type;
}

public void update(Clock clock) {
version = generateVersionName(clock);
}

public void updateAndroid(String version) {
this.version = version;
}

private String generateVersionName(Clock clock) {
String year = Integer.toString(LocalDate.now().getYear());
String padding = "0_";
String epochSeconds = Long.toString(clock.instant().getEpochSecond());
return year + padding + epochSeconds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Arrays;

import in.koreatech.koin.domain.version.exception.VersionTypeNotFoundException;
import lombok.AllArgsConstructor;
import lombok.Getter;

Expand All @@ -21,6 +22,6 @@ public static VersionType from(String value) {
return Arrays.stream(values())
.filter(versionType -> versionType.value.equals(value))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("잘못된 버전 타입입니다.. type: " + value));
.orElseThrow(() -> VersionTypeNotFoundException.withDetail("versionType: " + value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

import org.springframework.data.repository.Repository;

import in.koreatech.koin.domain.version.exception.VersionException;
import in.koreatech.koin.domain.version.exception.VersionTypeNotFoundException;
import in.koreatech.koin.domain.version.model.Version;
import in.koreatech.koin.domain.version.model.VersionType;

public interface VersionRepository extends Repository<Version, Long> {

Version save(Version version);

Optional<Version> findByType(VersionType type);
Optional<Version> findByType(String type);

default Version getByType(VersionType type) {
return this.findByType(type).orElseThrow(() -> VersionException.withDetail("versionType: " + type));
return this.findByType(type.getValue()).orElseThrow(() -> VersionTypeNotFoundException.withDetail("versionType: " + type));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public class VersionService {

public VersionResponse getVersion(String type) {
Version version = versionRepository.getByType(VersionType.from(type));

return VersionResponse.from(version);
}
}
15 changes: 15 additions & 0 deletions src/main/java/in/koreatech/koin/global/config/ClockConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package in.koreatech.koin.global.config;

import java.time.Clock;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ClockConfig {

@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import in.koreatech.koin.domain.version.exception.VersionException;
import in.koreatech.koin.global.auth.exception.AuthException;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -33,12 +32,6 @@ public ResponseEntity<ErrorResponse> handleAuthException(AuthException e) {
.body(ErrorResponse.from("잘못된 인증정보입니다."));
}

@ExceptionHandler
public ResponseEntity<String> handleVersionException(VersionException e) {
log.warn(e.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}

@ExceptionHandler
public ResponseEntity<ErrorResponse> handleDataNotFoundException(DataNotFoundException e) {
log.warn(e.getMessage());
Expand Down
16 changes: 7 additions & 9 deletions src/test/java/in/koreatech/koin/acceptance/VersionApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void findVersionByType() {

Version version = Version.builder()
.version(versionDetail)
.type(versionType)
.type(versionType.getValue())
.build();

versionRepository.save(version);
Expand All @@ -49,11 +49,13 @@ void findVersionByType() {
softly.assertThat(response.body().jsonPath().getString("version")).isEqualTo(versionDetail);
softly.assertThat(response.body().jsonPath().getString("type")).isEqualTo(versionType.getValue());
});
}

// 실패 케이스 설정
VersionType failureType = VersionType.TIMETABLE;

// 실패 케이스 테스트
@Test
@DisplayName("버전 타입을 통해 버전 정보를 조회한다. - 저장되지 않은 버전 타입을 요청한 경우 에러가 발생한다.")
void findVersionByTypeError() {
VersionType failureType = VersionType.TIMETABLE;
ExtractableResponse<Response> notFoundFailureResponse = RestAssured
.given()
.log().all()
Expand All @@ -64,19 +66,15 @@ void findVersionByType() {
.statusCode(HttpStatus.NOT_FOUND.value())
.extract();

// 존재하지 않는 Enum 케이스
String undefinedType = "undefined";

// 정의되지 않은 버전 타입으로 API 호출
ExtractableResponse<Response> enumTypeFailureResponse = RestAssured
.given()
.log().all()
.when()
.get("/versions/" + undefinedType)
.then()
.log().all()
.statusCode(HttpStatus.BAD_REQUEST.value())
.statusCode(HttpStatus.NOT_FOUND.value())
.extract();

}
}