-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: API 명세를 정의, 문서를 제작 (#7) #10
Conversation
@PostMapping | ||
fun create( | ||
@RequestBody request: NewsCreateRequest, | ||
): ResponseEntity<ApiResponse<UUID>> { | ||
val id = newsCommandService.create(request.toCommand()) | ||
return ResponseEntity.created("/api/v1/news/${id}".toUri()) | ||
.body(ApiResponse.success(id)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Service로 요청을 보낼 때 Request.toCommand() 메서드를 사용하여 의존성을 단방향으로 향하게 했습니다.
@RestController | ||
@RequestMapping("/api/v1/news") | ||
class NewsControllerV1( | ||
private val newsCommandService: NewsCommandService, | ||
private val newsQueryService: NewsQueryService, | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Service를 조회(R)를 담당하는 Query
, 명령(CUD)을 담당하는 Command
로 분리하여 사용했습니다.
지금은 이점이 없지만, 추후 캐싱을 적용할 때 이점이 있을것이라 판단됩니다.
fun findAll(): List<NewsResponse> { | ||
return newsRepository.findAll() | ||
.map { NewsResponse.from(it) } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금은 모든 뉴스를 제공하지만, 추후 페이지네이션을 적용하여 일부만 가져올 수 있도록 해야할 것 같네요.
fun getDetailByIdAndLanguage(id: UUID, language: Language): NewsDetailResponse { | ||
return newsRepository.getByDetailByIdAndLanguage(id, language) | ||
.let { | ||
val content = it.getContentByLanguage(language) | ||
NewsDetailResponse.of(it, content) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository에서 이미 id와 language에 대한 뉴스를 가져오지만, getContentByLanguage()
메서드를 사용하는 이유는 Repository에 비즈니스 로직을 담지 않게 하기 위해서 입니다.
}.andDocument("news/find-detail") { | ||
pathParameters( | ||
"id" pathMeans "뉴스 식별자" constraint "UUID" | ||
) | ||
queryParameters( | ||
"language" pathMeans "뉴스 언어" formattedAs ENUM(Language::class) | ||
) | ||
responseBody( | ||
"data" type OBJECT means "뉴스 상세 정보", | ||
"data.id" type STRING means "뉴스 식별자", | ||
"data.newsType" type ENUM(NewsType::class) means "뉴스 타입", | ||
"data.title" type STRING means "뉴스 제목", | ||
"data.excerpt" type STRING means "뉴스 발췌", | ||
"data.language" type ENUM(Language::class) means "뉴스 언어", | ||
"data.publishedAt" type ZONEDDATETIME means "뉴스 발행 시간", | ||
"data.content" type STRING means "뉴스 내용", | ||
"data.supportLanguages" type ARRAY means "뉴스 지원 언어", | ||
"data.originId" type NUMBER means "원본 뉴스 식별자", | ||
"data.originUrl" type STRING means "원본 뉴스의 URL", | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코틀린의 Infix 함수를 사용한 DSL 입니다.
링크 참조하시면 될 것 같습니다.
class KotestProjectConfig : AbstractProjectConfig() { | ||
|
||
override fun extensions() = listOf(SpringExtension) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kotest를 Spring과 함께 사용할 때
해당 함수를 다음과 같이 재정의를 해줘야 하더군요. 😂
override fun extensions() = listOf(SpringExtension)
매 클래스 마다 함수를 재정의하기 번거로우므로, AbstractProjectConfig
클래스를 상속하여 모든 Kotest에 기본 값을 세팅해줬습니다.
- 불필요한 internal 키워드 삭제 - getAllEmptyFormats -> gatAllEmptyAttributes 메서드명 변경
- news/v1 -> v1/news
관련 이슈
close #7
PR 세부 내용
News API 명세와 Spring REST Docs를 사용하여 문서화를 하였습니다.
서버 실행 후
/docs/index.html
로 접속하면 API 문서 볼 수 있습니다.그 전에 Gradle을 통해
documentation-asciidoctor
Task 실행하셔야 합니다..! (혹은 build)예외 명세는 API 문서에 나와있지 않습니다.
지금은 단순히
message
필드를 통해 어떤 예외가 발생했는지 알려주고 있습니다.추후 회의를 통해 예외 명세를 어떻게 할 지 정의해야 할 것 같네요. (
ErrorCode
와 같은 값 등)코드가 긴 관계로 세부적인 사항은 커맨트를 통해 설명 남기겠습니다.