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] docs: Swagger를 활용한 API 문서 자동화 #31

Merged
merged 11 commits into from
Jul 19, 2024
2 changes: 2 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'

runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
Copy link
Contributor

Choose a reason for hiding this comment

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


testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Expand Down
22 changes: 22 additions & 0 deletions backend/src/main/java/reviewme/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package reviewme.config;

import io.swagger.v3.oas.models.OpenAPI;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reviewme.config.properties.SwaggerProperties;

@Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
@RequiredArgsConstructor
public class SwaggerConfig {
Copy link
Contributor

@donghoony donghoony Jul 18, 2024

Choose a reason for hiding this comment

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

@ConfigurationProperties를 사용해보면 좋겠습니다. 설정 책임을 가지는 클래스를 분리하면 명확할 것 같아요.

@ConfigurationProperties(prefix = "docs.info")
public record SwaggerProperties(String title, String description, String version) {

    public Info swaggerInfo() {
        return new Info()
                .title(title)
                .description(description)
                .version(version);
    }
}
@EnableConfigurationProperties(SwaggerProperties.class)
@RequiredArgsConstructor
public class SwaggerConfig {

    private final SwaggerProperties swaggerProperties;

    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .info(swaggerProperties.swaggerInfo());
    }
}

swagger-docs.yml:

docs:
  info:
    title: "리뷰미 API"
    description: "이 문서는 리뷰미 API 구현 방법을 소개합니다."
    version: "0.0.1"

Copy link
Contributor

Choose a reason for hiding this comment

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

설정 책임을 가지는 클래스와 프로퍼티 정보를 저장하고 있는 클래스 분리 좋네요 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

@donghoony @Kimprodp
아이 해브 어 퀘스티옹~

API 문서와 관련된 것을 yml 로 뺀 이유가 있는지 궁금합니다!


private final SwaggerProperties swaggerProperties;

@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(swaggerProperties.swaggerInfo());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package reviewme.config.properties;

import io.swagger.v3.oas.models.info.Info;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "docs.info")
public record SwaggerProperties(
String title,
String description,
String version
) {

public Info swaggerInfo() {
return new Info()
.title(title)
.description(description)
.version(version);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package reviewme.keyword.contoller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import reviewme.keyword.dto.response.KeywordsResponse;

@Tag(name = "키워드 관리")
public interface KeywordApi {

@Operation(
summary = "모든 키워드 조회",
description = "모든 키워드를 조회한다."
)
ResponseEntity<KeywordsResponse> findAllKeywords();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@RestController
@RequiredArgsConstructor
public class KeywordController {
public class KeywordController implements KeywordApi {

private final KeywordService keywordService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package reviewme.keyword.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "키워드 응답")
public record KeywordResponse(

@Schema(description = "키워드 ID")
long id,

@Schema(description = "키워드명")
String detail
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package reviewme.keyword.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

public record KeywordsResponse(List<KeywordResponse> keywords) {
@Schema(description = "키워드 목록 응답")
public record KeywordsResponse(

@Schema(description = "키워드 목록")
List<KeywordResponse> keywords
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package reviewme.member.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import reviewme.member.dto.response.ReviewerGroupResponse;

@Tag(name = "리뷰어 그룹 관리")
public interface ReviewerGroupApi {

@Operation(
summary = "리뷰어 그룹 조회",
description = "리뷰어 그룹을 조회한다."
)
ResponseEntity<ReviewerGroupResponse> findReviewerGroup(@PathVariable long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@RestController
@RequiredArgsConstructor
public class ReviewerGroupController {
public class ReviewerGroupController implements ReviewerGroupApi {

private final ReviewerGroupService reviewerGroupService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package reviewme.member.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "사용자 응답")
public record MemberResponse(

@Schema(description = "사용자 ID")
long id,

@Schema(description = "사용자 이름")
String name
) {
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package reviewme.member.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;

@Schema(description = "리뷰어 그룹 응답")
public record ReviewerGroupResponse(

@Schema(description = "리뷰어 그룹 아이디")
long id,

@Schema(description = "리뷰 그룹 이름 (레포지토리명)")
String name,

@Schema(description = "리뷰 작성 기한")
LocalDateTime deadline,

@Schema(description = "리뷰이")
MemberResponse reviewee
) {
}
27 changes: 27 additions & 0 deletions backend/src/main/java/reviewme/review/controller/ReviewApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package reviewme.review.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import reviewme.review.dto.request.CreateReviewRequest;
import reviewme.review.dto.response.ReviewResponse;

@Tag(name = "리뷰 관리")
public interface ReviewApi {

@Operation(
summary = "리뷰 등록",
description = "리뷰 작성 정보를 받아 리뷰를 등록한다.",
responses = @ApiResponse(responseCode = "201")
)
ResponseEntity<Void> createReview(@RequestBody CreateReviewRequest request);

@Operation(
summary = "리뷰 조회",
description = "단일 리뷰를 조회한다."
)
ResponseEntity<ReviewResponse> findReview(@PathVariable long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

@RestController
@RequiredArgsConstructor
public class ReviewController {
public class ReviewController implements ReviewApi {

private final ReviewService reviewService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package reviewme.review.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "리뷰 내용 등록 요청")
public record CreateReviewContentRequest(

@Schema(description = "리뷰 항목 순서")
Long order,

@Schema(description = "리뷰 문항")
String question,

@Schema(description = "리뷰 문항에 대한 답변")
String answer) {
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package reviewme.review.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

@Schema(description = "리뷰 등록 요청")
public record CreateReviewRequest(

@Schema(description = "리뷰어 ID")
Long reviewerId,

@Schema(description = "리뷰어 그룹 ID")
Long reviewerGroupId,

@Schema(description = "리뷰 내용 목록")
List<CreateReviewContentRequest> contents,

@Schema(description = "선택된 키워드 ID 목록")
List<Long> selectedKeywordIds) {
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package reviewme.review.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "리뷰 내용 응답")
public record ReviewContentResponse(

@Schema(description = "리뷰 내용 ID")
long id,

@Schema(description = "리뷰 문항")
String question,

@Schema(description = "리뷰 문항에 대한 답변")
String answer
) {
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
package reviewme.review.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import reviewme.keyword.dto.response.KeywordResponse;
import reviewme.member.dto.response.MemberResponse;
import reviewme.member.dto.response.ReviewerGroupResponse;

@Schema(description = "리뷰 응답")
public record ReviewResponse(

@Schema(description = "리뷰 ID")
long id,

// LocalDateTime createdAt,

@Schema(description = "리뷰어")
MemberResponse reviewer,

@Schema(description = "리뷰어 그룹")
ReviewerGroupResponse reviewerGroup,

@Schema(description = "리뷰 내용 목록")
List<ReviewContentResponse> contents,

@Schema(description = "선택된 키워드 목록")
List<KeywordResponse> keywords
) {
}
5 changes: 5 additions & 0 deletions backend/src/main/resources/application-api-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
docs:
info:
title: "리뷰미 API"
description: "이 문서는 리뷰미 API 구현 방법을 소개합니다."
version: "0.0.1"
8 changes: 8 additions & 0 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ spring:
show-sql: true
hibernate:
ddl-auto: update
profiles:
include: api-docs

springdoc:
swagger-ui:
path: /api-docs
operations-sorter: alpha
tags-sorter: alpha