Swagger 3.0 - 1

๋ชฝ๋ฃจ๋ฌธยท2023๋…„ 12์›” 13์ผ
0

Swagger

๋ชฉ๋ก ๋ณด๊ธฐ
1/2
post-thumbnail

๐Ÿ“ Swagger ๋ž€?

Swagger๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ REST ์›น ์„œ๋น„์Šค๋ฅผ ์„ค๊ณ„, ๋นŒ๋“œ, ๋ฌธ์„œํ™”, ์†Œ๋น„ํ•˜๋Š” ์ผ์„ ๋„์™€์ฃผ๋Š” ๋Œ€ํ˜• ๋„๊ตฌ ์ƒํƒœ๊ณ„์˜ ์ง€์›์„ ๋ฐ›๋Š” ์˜คํ”ˆ ์†Œ์Šค ์†Œํ”„ํŠธ์›จ์–ด ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

Swagger๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐœ๋ฐœํ•œ API๋ฅผ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ Swagger๊ฐ€ ์ƒ์„ฑํ•œ ํŽ˜์ด์ง€์— ์ ‘์†ํ•˜์—ฌ ๋‘˜๋Ÿฌ๋ณด๊ณ  ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉฐ ์ง์ ‘ ์ปจํŠธ๋กค ๋ฐ ๊ฐœ๋ฐœ์— ํŽธ๋ฆฌํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.




๐Ÿšฉ SpringFox vs SpringDoc

SpringFox ์™€ SpringDoc์€ ๋‘˜ ๋‹ค SpringFramework๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ํ”„๋กœ์ ํŠธ์˜ Swgger ๋ฌธ์„œ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‚˜ ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ Anntation๋“ค์ด ์•ฝ๊ฐ„์”ฉ ๋‹ค๋ฅผ๋ฟ ๊ธฐ๋Šฅ์„ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค.
SpringFox๋Š” Maven Repository ๊ธฐ์ค€ 2020๋…„ 7์›” ๊ธฐ์ค€์œผ๋กœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋Š๊ฒผ์œผ๋ฉฐ, SpringDoc์€ 2023๋…„ 5์›”๊นŒ์ง€ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ง„ํ–‰๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— SpringDoc๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ•˜์˜€๋‹ค.
๋˜ํ•œ SpringDoc์ด ๊ทธ๋ฃน๊ฐ„ API์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•˜๋Š”๋ฐ, ํฌ๊ฒŒ ์˜๋ฏธ ์—†๋Š”๊ฑฐ ๊ฐ™์œผ๋ฏ€๋กœ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.


๐Ÿšฉ Swagger 3.0 - SpringDoc ์„ค์ •

๐Ÿ“ pom.xml์˜ ์˜์กด์„ฑ ๋ชฉ๋ก์— SpringDoc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€

<!-- Swagger 3 SpringDoc Dependency-->
<dependency>
 	<groupId>org.springdoc</groupId>
 	<artifactId>springdoc-openapi-ui</artifactId>
 	<version>1.7.0</version>
</dependency>
  • pom.xml์˜ ์˜์กด์„ฑ ๋ชฉ๋ก์— SpringDoc ๋ผ์ด๋ธŒ๋ฒ„๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.
  • 2023๋…„ 12์›” ๊ธฐ์ค€ 1.7.0 Version์ด ๊ฐ€์žฅ ์ตœ์‹  ๋ฒ„์ „์ด๋‹ค.

๐Ÿ“ SpringDoc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ณธ ์„ค์ •

@Configuration
public class OpenApiConfig {
    @Bean
    public OpenAPI openAPI(@Value("${springdoc.version}") String version,
                           @Value("${springdoc.title}") String title,
                           @Value("${springdoc.description}") String description) {
        Info info = new Info()
                .title(title)
                .version(version)
                .description(description);

        return new OpenAPI()
                .components(new Components())
                .info(info);
    }
}
  • Swagger 3.0 - SpringDoc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ™˜๊ฒฝ์„ค์ • ํด๋ž˜์Šค ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค€๋‹ค
  • ํ™˜๊ฒฝ์„ค์ • ํด๋ž˜์Šค ํŒŒ์ผ์— @Configuration Annotation๋ฅผ ์„ค์ •ํ•ด์„œ ํ™˜๊ฒฝ์„ค์ • ํด๋ž˜์Šค ํŒŒ์ผ์„ ์ธ์‹์‹œ์ผœ์ค€๋‹ค.
  • @Bead Annotation์œผ๋กœ openAPI Method๋ฅผ ๋“ฑ๋กํ•˜์—ฌ Swagger 3.0 - SpringDoc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์„ฑํ™” ์‹œ์ผœ์ค€๋‹ค.
  • version, title, desciption ๋‚ด์šฉ๋“ค์„ @Value Annotation ์ด์šฉํ•˜์—ฌ application.yml์—์„œ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

๐Ÿ“ Application.yml๋ฅผ ์ด์šฉํ•œ ์„ค์ •

springdoc:
  version: v1.0.0
  title: Swagger 3.0 - SpringDoc Title
  description: Swagger 3.0 - SpringDoc Description
  packages-to-scan: com.boot.controller
  swagger-ui:
    path: /api-docs
  default-consumes-media-type: application/json; charset=UTF-8
  default-produces-media-type: application/json; charset=UTF-8
  • version, title, desciption : Swaager ํŽ˜์ด์ง€์— ํ‘œ์‹œ๋  ๋ฒ„์ „, ์ œ๋ชฉ, ๋‚ด์šฉ
  • package-to-scan : Swaager ํŽ˜์ด์ง€์— ์ƒ์„ฑ๋  API๊ฐ€ ์ •์˜๋œ Controller Package
  • path : Swaager ํŽ˜์ด์ง€์— ๊ฐ„ํŽธํ•˜๊ฒŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ๋กœ
  • default-consumes-media-type : ํด๋ผ์ด์–ธํŠธ๋กœ ๋ถ€ํ„ฐ ๋“ค์–ด์˜ค๋Š” API์˜ ๋ฐ์ดํ„ฐ์˜ Media Type
  • default-produces-media-type : ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ œ๊ณต๋  API์˜ ๋ฐ์ดํ„ฐ์˜ Media Type

๐Ÿ“ Controller interface ์„ค์ •

@Tag(name = "Template", description = "Template Description")
public interface ITemplateController {
    @Operation(summary = "Get Request Template", description = "HttpMethod.Get Method๋ฅผ ์ด์šฉํ•œ HTTP Request")
    @Parameters({
            @Parameter(name = "name", description = "TestGetRequestPayload ์˜ Test Field", required = true)
    })
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = UserInfoResponsePayload.class))),
            @ApiResponse(responseCode = "400", description = "bad request operation", content = @Content(schema = @Schema(implementation = ResponsePayload.class)))
    })
    ResponseEntity<ResponsePayload> httpMethodGet(@ParameterObject @ModelAttribute @Validated GetMethodRequestPayload payload, BindingResult error) throws CustomRunTimeException;

    @Operation(summary = "Post Request Template", description = "HttpMethod.Post Method๋ฅผ ์ด์šฉํ•œ HTTP Request")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = PostMethodResponsePayload.class))),
            @ApiResponse(responseCode = "201", description = "created operation", content = @Content(schema = @Schema(implementation = PostMethodResponsePayload.class))),
            @ApiResponse(responseCode = "400", description = "bad request operation", content = @Content(schema = @Schema(implementation = ResponsePayload.class)))
    })
    ResponseEntity<ResponsePayload> httpMethodPost(@RequestBody @Validated PostMethodRequestPayload payload, BindingResult error) throws CustomRunTimeException;

    @Operation(summary = "Put Request Template", description = "HttpMethod.Put Method๋ฅผ ์ด์šฉํ•œ HTTP Request")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = PostMethodResponsePayload.class))),
            @ApiResponse(responseCode = "201", description = "created operation", content = @Content(schema = @Schema(implementation = PostMethodResponsePayload.class))),
            @ApiResponse(responseCode = "400", description = "bad request operation", content = @Content(schema = @Schema(implementation = ResponsePayload.class)))
    })
    ResponseEntity<ResponsePayload> httpMethodPut(@RequestBody @Validated PostMethodRequestPayload payload, BindingResult error) throws CustomRunTimeException;

    @Operation(summary = "Delete Request Template", description = "HttpMethod.Delete Method๋ฅผ ์ด์šฉํ•œ HTTP Request")
    @Parameters({
            @Parameter(name = "tempString", description = "TestPostRequestPayload ์˜ tempString Field", required = true)
    })
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = PostMethodResponsePayload.class))),
            @ApiResponse(responseCode = "400", description = "bad request operation", content = @Content(schema = @Schema(implementation = ResponsePayload.class)))
    })
    ResponseEntity<ResponsePayload> httpMethodDelete(@ParameterObject @RequestBody @Validated PostMethodRequestPayload payload, BindingResult error) throws CustomRunTimeException;
}
  • Controller ๊ตฌํ˜„์ฒด์— Swgger Annotation์„ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด Controller ๊ธฐ๋Šฅ์— ์žˆ๋Š” Source๋“ค๊ณผ ์„ž์—ฌ์„œ ๊ฐ€๋…์„ฑ์ด ๋„ˆ๋ฌด ๋–จ์–ด์ง€๊ธฐ์— Interface๋กœ ๋งŒ๋“  ๋’ค Interface์—์„œ๋Š” Swagger Annotation๋งŒ ์„ ์–ธํ•˜๊ณ , ํ•ด๋‹น Interface๋ฅผ ์ƒ์†๋ฐ›์€ Controller ๊ตฌํ˜„์ฒด์—์„œ API Annotation & Source๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๋ฉด ์ฒ˜์Œ์—๋Š” ์กฐ๊ธˆ ๊ท€์ฐฎ์ง€๋งŒ ๋‚˜์ค‘์— ํ›จ์”ฌ ํŽธํžˆ๋ผ๊ฒŒ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Controller Interface์—์„œ ์‚ฌ์šฉ๋œ Swaager Annotation๋“ค์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ๊ธ€์—์„œ ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž

๐Ÿ“ Swagger ํŽ˜์ด์ง€ ์ƒ์„ฑ

  • ์œ„์™€ ๊ฐ™์ด ์Šค์›จ๊ฑฐ ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.





๐Ÿ“Œ ๋งˆ๋ฌด๋ฆฌ

Swagger์— ๋Œ€ํ•ด์„œ ์˜ค๋Š˜ ๊ธฐ๋ณธ์ ์ธ ์„ค์ • ๋ฐฉ๋ฒ•๊ณผ ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด์„œ ๊ธฐ๋กํ•˜์˜€๋‹ค.
๋‹ค์Œ์—๋Š” Swagger์˜ Anntation์— ๋Œ€ํ•ด์„œ ์ž์„ธํžˆ ๊ธฐ๋กํ•˜๋ ค๊ณ  ํ•œ๋‹ค.
๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ์˜ ํ˜‘์—…์„ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

profile
์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ์ •๋ฆฌํ•˜๊ณ , ์ƒˆ๋กœ์šด ๊ฒƒ์„ ์•Œ๊ธฐ์œ„ํ•ด ๋„์ ์ด๋Š”๊ณณ..

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด