스프링 부트

[SpringBoot] OpenAPI 3.0 구성하기! (swagger-ui)

h__hj 2023. 1. 14. 23:29

# OpenAPI 3.0 example code - 2 (swagger-ui)

 이전 설정인 https://hjho95.tistory.com/39 에서 OpenAPI에 대한 pom.xml, application.yml, Configuration을 작성하여 기동해보는 걸 해보았다.

 이번에는 Document 내에 들어가는 해당 API의 설명, 정의 등 작성해보는 시간이다.

 

https://hjho95.tistory.com/39 는 OpenAPI를 사용하기 위한 설정.

https://hjho95.tistory.com/40 은 Annotation을 이용한 Document작성.

https://hjho95.tistory.com/41 은 ApiResponse의 ref 구현.

# Refference

document: https://springdoc.org

example-ui: http://158.101.191.70:8081/swagger-ui/index.html

github: https://github.com/springdoc/springdoc-openapi-demos/blob/master/springdoc-openapi-spring-boot-2-webmvc/src/main/java/org/springdoc/demo/app2/Application.java

# 환경

Tool  : STS 4.13.0
Ver   : 2.7.5 [GA]
JDK   : 11
Repo  : MAVEN
DB    : ORACLE XE (11g), PostgreSQL (14)
View  : Thymeleaf
jQuery: 3.6.0

# 기본 페이지 (DrinksController)

@RestController
@RequestMapping("/api-v1/drinks")
public class DrinksController {
    @GetMapping
    public RestResponse listDrinks(@ModelAttribute DrinksPVO drinks) {
        RestResponse response = new RestResponse();
        
        List<DrinksRVO> listDrinks = new ArrayList<DrinksRVO>();
        
        response.setOk();
        response.setData(listDrinks);
        return response;
    }
    @GetMapping("/{drinksNo}") ,,,생략
    @PostMapping ,,,생략
    @PutMapping ,,,생략
    @DeleteMapping("/{drinksNo}") ,,,생략
}

DrinksController의 API 목록
아무것도 작성하지않은 API

 dringks-controller는 DrinksController.java 파일에 정의된 URL이다. 아무것도 작성하지 않은 일반 Controller도 그냥 알아서 잘해준다,,, 이 정도면 그냥 혼자 api 단위 테스트를 할 수 잇을 정도는 되는 듯,,,!

# 어노테이션 작성 페이지 (DataController)

DataController의 API 목록

1. @GetMapping & @RequestParam & application/x-www-form-urlencoded & String

@Tag(name = "Data", description = "데이터베이스 조회 API")
@RestController
@RequestMapping("/api-v1/common/data")
public class DataController {

    @Autowired
    private OracleService oracleService;
    
    @Autowired
    private PostgreService postgreService;
    
    @Operation(tags = { "Data" }, 
               summary = "오라클 데이터베이스 조회", 
               description = "Read to Oracle database",
               parameters = {
                       @Parameter(name = "name", description = "테스트 입력 파라미터", example = "오라클", required = true)
               },
               responses = {
                       @ApiResponse(responseCode="200", description = "OK [Response Data Schema: Map]", content = 
                               @Content(mediaType = "application/json", schema = 
                                       @Schema(example = "{\"code\": \"0000\", \"message\": \"정상적으로 처리 되었습니다.\", \"data\": {\"INPUT_NAME\": \"parameters[name]\",\"DATABASE_ID\": \"Oracle\",\"NOW_TIME\": \"2023-01-14 17:59:10\"},\"success\": true}")
                               )
                       ),
                       @ApiResponse(responseCode="0000", ref="success"),
                       @ApiResponse(responseCode="9999", ref="error"),
                       @ApiResponse(responseCode="9001", description = "입력 값이 존재하지 않습니다.", content = @Content),
                       @ApiResponse(responseCode="9004", description = "토큰이 만료되었습니다.", content = @Content),
               }
    )
    @GetMapping("/oracle")
    public RestResponse oracle(@RequestParam String name){
        Map<String, Object> data = oracleService.oracle(name);
        
        RestResponse response = new RestResponse();
        response.setOk();
        response.setData(data);
        return response;

    }
}

@GetMapping & @RequestParam & application/x-www-form-urlencoded & String

1. 설명

@Tag

 Contoller class 단위의 붙이는 어노테이션.

메소드(url)들을 name으로 그룹핑, description으로 설명을 적어준다.

@Operation

 메소드 단위에 붙이는 어노테이션.

tags는 @Tag의 name으로 그룹 설정한다. (여러개 가능).

summary는 바로 보이는 설명, description은 열면 보이는 설명을 작성할 수 있다.

parameters 는 @Parameter 를 이용하여 name 파라미터의 필수여부(required), 예제입력(example), 설명(description)을 작성할 수 있다. 

responses는 @ApiResponse을 이용하여 각각의 응답 내용을 정의 할 수 있다. responses 중 @ApiResponse responseCode가 같은 값이 여러개일 경우, 마지막에 설정한 값으로 표시된다.

 

차근차근보면 어노테이션이 @ApiResponse → @Content → @Shcema 로 정의가 되는데 아래에서 부터 보면

@Shcema는 VO 단위.

@Content는 해당 VO가 무슨 ContentType(mediaType)인지 정의.

@ApiResponse로 그 VO가 어떤 코드(responseCode)일 경우 응답이 나가는지와 설명(description)을 적어준다고 보면 된다. 

@Content 내 입력이 없으면 @ApiResponse의 code, description만 보여진다. 특정 에러코드일 때의 메시지를 보여주면 좋을 것 같아 작성해보았다.

@Operation 아래 responses가 아니라 @ApiResponses 를 따로 어노테이션을 걸고 @ApiResponse를 작성해도 된다. 

2. @PostMapping & @RequestBody & application/json & Map

    @Operation(tags = { "Data" }, 
               summary = "포스트그레SQL 데이터베이스 조회", 
               description = "Read to PostgreSQL database",
               requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Input Schema: Map<String, String>", content = {
                       @Content(mediaType = "application/json", schema = 
                               @Schema(example = "{\"text\":\"포스트그레SQL\"}"))})
    )
    @PostMapping("/postgre")
    public RestResponse postgre(@RequestBody Map<String, String> input){
        Map<String, Object> data = postgreService.postgre(MapUtils.getString(input, "text", ""));
        
        RestResponse response = new RestResponse();
        response.setOk();
        response.setData(data);
        return response;
    }

@PostMapping & @RequestBody & application/json & Map

2. 설명

그냥 하는 건 어렵지 않다. 하지만 점점 응용하는 게 복잡해진다.

@RequestParam은 그냥 paramters로 정의하면 되는 데 API는 보통 json이다. 거기에 정의되지 않은 Map이라면 key 자동으로 "additionalProp1" 으로 입력 되어있다. 

responseBody는 @ResponseBody(패키지루트가 다름) 로 정의 할 수 있는데, @Schema 로 VO단위인 Map의 기본 입력값을 설정해주면 자동으로 예제와 같이 text가 key로 입력 되고 포스트그레SQL이 입력값으로 매핑되어있다.

3. @PostMapping & @RequestBody & application/json & VO(Schema)

	@PostMapping("/twice1")
	public RestResponse twice1(@RequestBody DataPVO dataPVO){
		Map<String, Object> data = oracleService.twice(dataPVO.getText());
		
		RestResponse response = new RestResponse();
		response.setOk();
		response.setData(data);
		return response;
	}
@Schema(description = "데이터베이스 조회 파라미터")
@Data
public class DataPVO {

    @Schema(title = "문자", description = "입력 파라미터가 input_name으로 리턴", format = "YYYY-MM-DD HH24:MI:SS", requiredMode = RequiredMode.REQUIRED, minLength = 1, maxLength = 30, example = "오라클과 포스트그레SQL", defaultValue = "oracle and postgreSQL")
    private String text;
    
    @Schema(title = "여부", description = "여부", requiredMode = RequiredMode.NOT_REQUIRED)
    private String yn;
    
    @Schema(hidden = true)
    private String hidden;
}

@PostMapping & @RequestBody & application/json & VO(Schema)
프로젝트 전체의 Schema 목록

3. 설명

 기본적인 케이스라고 볼수 있다.

@Schema 어노테이션을 등록한 VO는 Swagger의 Schemas Component에 등록된다. 

등록되면 @Content > @Schemas > ref 로 등록한 VO를 참조할 수 있다. 

Class단위에 @Schema를 붙이면 해당 클래스가 Schema로 등록이 되고, Field 단위로 등록이 되면 해당 필드에 대한 정의를 작성할 수 있다. 

필드 단위의 @Schema를 보면, title로 필드명, maxLength/minLength로 길이제한, format으로 값이 어떤 형식인지, requiredMode로 필수값인지 아닌지, description으로 설명, hidden으로 Schema의 표시 여부, example로 자동입력값을 작성할 수 있다. 정의한다고 try it out 시 적용되는게 아니라 단지 Document성으로 필드에 대한 정보를 정의한다고 볼 수 있다.

4. @PostMapping & @ModelAttribute & application/x-www-form-urlencoded & VO(Schema)

	@Operation(tags = { "Data" }, 
			   summary = "오라클과 포스트그레SQL 데이터베이스 조회", 
			   description = "Read to Oracle and PostgreSQL database",
			   requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
					   description = "json 형식이 아닌 form 형식", 
					   content = @Content(mediaType = "application/x-www-form-urlencoded", schema = @Schema(ref = "DataPVO")))
	)
	@PostMapping("/twice2")
	public RestResponse twice2(@ModelAttribute DataPVO dataPVO){
		Map<String, Object> data = oracleService.twice(dataPVO.getText());
		
		RestResponse response = new RestResponse();
		response.setOk();
		response.setData(data);
		return response;
	}

@PostMapping & @RequestBody & application/x-www-form-urlencoded&nbsp;& VO(Schema)

4. 설명

설정 찾는게 힘들었다. 코드보면 이해가 쉽지만, swagger가 자동으로 ModelAttribute를 인식하여 설정되지 않았다. 

VO를 사용하는데 application/x-form-urlencoded 방식이라면 responseBody 설정에서 @Content의 mediaType을 설정해주어야 Swagger가 위와 같이 만들어준다. @Schema는 ref를 이용해 DataPVO를 등록해준다. 

 

# 전체적인 내용 

 일단 하고싶은 건 다 해본 듯 하다. 특정 상황, 특정 타입 별로 확인해보고, Document의 표시 될 수 있는가가 제일 중요했다. 

추가로 @ApiResponse ref 에 대해서 3 편에서 해볼 생각이다. 

 

https://hjho95.tistory.com/41 은 ApiResponse의 ref 구현.

 

[SpringBoot] OpenAPI 3.0 example code - 3 (swagger-ui)

# OpenAPI 3.0 example code - 3 (swagger-ui) https://hjho95.tistory.com/39 는 OpenAPI를 사용하기 위한 설정. https://hjho95.tistory.com/40 은 Annotion을 이용한 Document작성. https://hjho95.tistory.com/41 은 ApiResponse의 ref 구현. 이번

hjho95.tistory.com