Skip to content

Commit 1ce0e11

Browse files
committed
Feat: Swagger 어노테이션을 이용한 API 문서화
1 parent 7045f64 commit 1ce0e11

File tree

4 files changed

+69
-1
lines changed

4 files changed

+69
-1
lines changed

build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ dependencies {
5050

5151
// Kotlin
5252
implementation 'org.jetbrains.kotlin:kotlin-reflect'
53+
54+
// Swagger
55+
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
56+
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0'
5357
}
5458

5559
dependencyManagement {

src/main/kotlin/kea/dpang/faq/config/SecurityConfig.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class SecurityConfig {
2828
return WebSecurityCustomizer { web ->
2929
web.ignoring()
3030
.requestMatchers(
31-
"/api-document/**",
31+
"/v3/api-docs/**",
3232
"/swagger-ui/**"
3333
)
3434
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package kea.dpang.faq.config
2+
3+
import io.swagger.v3.oas.annotations.OpenAPIDefinition
4+
import io.swagger.v3.oas.annotations.info.Info
5+
import io.swagger.v3.oas.models.OpenAPI
6+
import io.swagger.v3.oas.models.security.SecurityRequirement
7+
import io.swagger.v3.oas.models.security.SecurityScheme
8+
import lombok.RequiredArgsConstructor
9+
import org.springdoc.core.customizers.OpenApiCustomizer
10+
import org.springdoc.core.models.GroupedOpenApi
11+
import org.springframework.context.annotation.Bean
12+
import org.springframework.context.annotation.Configuration
13+
import org.springframework.http.HttpHeaders
14+
15+
/**
16+
* Swagger(Spring Docs) 설정
17+
*/
18+
@OpenAPIDefinition(info = Info(title = "DPANG FAQ 서비스 API 명세서", description = "DPANG FAQ 서비스 API 명세서", version = "0.2.0"))
19+
@RequiredArgsConstructor
20+
@Configuration
21+
class SwaggerConfig {
22+
23+
fun securityBudiler(): OpenApiCustomizer {
24+
return OpenApiCustomizer { openApi: OpenAPI ->
25+
openApi.addSecurityItem(SecurityRequirement().addList("Access Token"))
26+
.components
27+
.addSecuritySchemes(
28+
"Access Token", SecurityScheme()
29+
.name(HttpHeaders.AUTHORIZATION)
30+
.type(SecurityScheme.Type.HTTP)
31+
.`in`(SecurityScheme.In.HEADER)
32+
.bearerFormat("JWT")
33+
.scheme("bearer")
34+
)
35+
}
36+
}
37+
38+
@Bean
39+
fun openApi(): GroupedOpenApi {
40+
val paths = arrayOf("/**")
41+
return GroupedOpenApi.builder()
42+
.group("DPANG FAQ 서비스 API")
43+
.pathsToMatch(*paths)
44+
.addOpenApiCustomizer(securityBudiler())
45+
.build()
46+
}
47+
}

src/main/kotlin/kea/dpang/faq/controller/PostController.kt

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package kea.dpang.faq.controller
22

3+
import io.swagger.v3.oas.annotations.Operation
4+
import io.swagger.v3.oas.annotations.Parameter
5+
import io.swagger.v3.oas.annotations.tags.Tag
36
import kea.dpang.faq.base.BaseResponse
47
import kea.dpang.faq.base.SuccessResponse
58
import kea.dpang.faq.dto.PostCreateRequestDto
@@ -13,13 +16,17 @@ import org.springframework.web.bind.annotation.*
1316
import java.util.*
1417

1518
@RestController
19+
@Tag(name = "FAQ")
1620
@RequestMapping("/api/posts")
1721
class PostController(private val postService: PostService) {
1822

23+
@Operation(summary = "게시글 작성", description = "관리자 권한을 가진 사용자가 새로운 게시글을 생성합니다.")
1924
@PreAuthorize("hasRole('ADMIN') or hasRole('SUPER_ADMIN')")
2025
@PostMapping
2126
fun createPost(
27+
@Parameter(hidden = true)
2228
@RequestHeader("X-DPANG-CLIENT-ID") clientId: UUID,
29+
@Parameter(description = "포스트 생성 정보")
2330
@RequestBody postCreateDto: PostCreateRequestDto
2431
): ResponseEntity<SuccessResponse<PostResponse>> {
2532

@@ -35,9 +42,11 @@ class PostController(private val postService: PostService) {
3542
return ResponseEntity(successResponse, HttpStatus.CREATED)
3643
}
3744

45+
@Operation(summary = "게시글 조회", description = "특정 게시글을 조회합니다.")
3846
@PreAuthorize("hasAnyRole('USER', 'ADMIN','SUPER_ADMIN')")
3947
@GetMapping("/{postId}")
4048
fun readPost(
49+
@Parameter(description = "조회할 포스트의 ID")
4150
@PathVariable postId: Long
4251
): ResponseEntity<SuccessResponse<PostResponse>> {
4352

@@ -53,9 +62,11 @@ class PostController(private val postService: PostService) {
5362
return ResponseEntity(successResponse, HttpStatus.OK)
5463
}
5564

65+
@Operation(summary = "카테고리별 게시글 조회", description = "특정 카테고리의 게시글을 조회합니다.")
5666
@PreAuthorize("hasAnyRole('USER', 'ADMIN','SUPER_ADMIN')")
5767
@GetMapping("/category/{categoryName}")
5868
fun readPostsByCategory(
69+
@Parameter(description = "조회할 카테고리")
5970
@PathVariable categoryName: String
6071
): ResponseEntity<SuccessResponse<List<PostResponse>>> {
6172

@@ -71,11 +82,15 @@ class PostController(private val postService: PostService) {
7182
return ResponseEntity(successResponse, HttpStatus.OK)
7283
}
7384

85+
@Operation(summary = "게시글 수정", description = "관리자 권한을 가진 사용자가 특정 게시글을 수정합니다.")
7486
@PreAuthorize("hasAnyRole('ADMIN','SUPER_ADMIN')")
7587
@PutMapping("/{postId}")
7688
fun updatePost(
89+
@Parameter(hidden = true)
7790
@RequestHeader("X-DPANG-CLIENT-ID") clientId: UUID,
91+
@Parameter(description = "수정할 포스트의 ID")
7892
@PathVariable postId: Long,
93+
@Parameter(description = "포스트 수정 정보")
7994
@RequestBody faqUpdateDto: PostUpdateRequestDto
8095
): ResponseEntity<SuccessResponse<PostResponse>> {
8196

@@ -91,9 +106,11 @@ class PostController(private val postService: PostService) {
91106
return ResponseEntity(successResponse, HttpStatus.OK)
92107
}
93108

109+
@Operation(summary = "게시글 삭제", description = "관리자 권한을 가진 사용자가 특정 게시글을 삭제합니다.")
94110
@PreAuthorize("hasAnyRole('ADMIN','SUPER_ADMIN')")
95111
@DeleteMapping("/{postId}")
96112
fun deletePost(
113+
@Parameter(description = "삭제할 게시글의 ID")
97114
@PathVariable postId: Long
98115
): ResponseEntity<BaseResponse> {
99116

0 commit comments

Comments
 (0)