전체 보기
🍀

Swagger로 API 문서 자동화(with 마주한 문제점들) - cors, generic, enum, multipart, authorization

작성일자
2023/10/09
태그
DIARY_DEVELOP
프로젝트
FIS
책 종류
1 more property

Swagger로 API 문서 자동화

Swagger 적용 방법

서론) swagger 적용은 무지무지 간단하다
본론) 단계별로 적겠다
springdoc-openapi-ui 의존성 설치 (build.gradle)
// implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' -> springboot ver2 이하 implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' // springboot ver3 이상
Java
복사
application.yml 설정 추가
springdoc: packages-to-scan: # 패키지명 (ex. app.company.backend) default-consumes-media-type: application/json;charset=UTF-8 default-produces-media-type: application/json;charset=UTF-8 swagger-ui: path: swagger-ui.html api-docs: path: /api-docs/json
Java
복사
SwaggerConfig 파일 생성
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @Configuration public class SwaggerConfig { @Bean public OpenAPI openAPI() { return new OpenAPI() .components(new Components()) .info(apiInfo()); } private Info apiInfo() { return new Info() .title("POLICE API 명세서") .description("경찰청 서비스 백엔드 API 명세서") .version("1.0.0"); } }
Java
복사
controller 별로 @tag@operation 적용
@Tag(name = "AgentController(현장요원 API)") @RestController @RequiredArgsConstructor @Slf4j public class AgentController { ... @Operation(summary = "현장요원 추가", description = "새로운 현장요원을 추가합니다. 어드민만 사용할 수 있습니다.") @PostMapping("/agent") public void saveAgent( ...
Java
복사
결론)
swagger 초간단 설정이 끝났다. 실행 후 http://localhost:8080/swagger-ui.html 로 접속하면 된다. 401이 뜬다면, security 단에서 해당 엔드포인트를 permitAll로 허용해주자.
적용은 쉽게 했지만, 내가 원하는 대로 문서가 잘 뽑히진 않았다.
그 이유는,,,, 레거시 코드 때문,,,,
스웨거가 인식할 수 없는 부분들이 많아서 RequestBody인데 RequestParam으로 뜬다던가,,, 하는 요상한 것들이 많았따..
이건 결국 코드가 컨벤셔널 하지 않아서 그런 거 같다. 어느 정도 규격을 맞춰주는 작업이 필요하다 절실히 느꼈다.
참고)
OpenAPI 와 Swagger-ui 적용하기
API를 개발하고 사용방법에 대한 명세를 작성하는 방법은 여러 가지가 있다. 가장 심플하게 개발 코드와는 별도로 직접 수기로 작성하여 파일 혹은 문서 링크를 전달하는 방법이 있다. 하지만 개발 코드와 별도로 직접 작성을 한다는 점에서 오타/실수가 발생할 수 있고 최신화가 안되는 여러 가지 문제가 발생한다. 그에 등장한 API 문서화 자동화 툴의 양대 산맥인 SpringRestDocs 와 Swagger.  과거 SpringRestDocs 에 대한 포스팅을 했기에 이번엔 Swagger에 대한 사용방법에 대해 정리해보고자 한다. 이 둘의 장단점은 너무 뚜렷하기에 API문서를 제공하는 상황에 따라 적절하게 선택하여 사용할 수 있었으면 좋겠다. SpringBoot에 Swagger 적용  기본 SpringBoot 가 셋팅되어 있다는 가정하에 Swagger 관련 dependency를 추가해주자. 아참, 이제부터의 프로젝트 셋팅은 Gradle로 하려한다. (물론 Maven으로 해도 무방하지만…) dependencies { implementation "io.springfox:springfox-boot-starter:3.0.0" }  이후 JavaConfig 을 아래와 같이 설정하는데 아래 내용은 아주 기본 세팅이니 자세한 내용은 공식 도큐문서를 참고해 보면 좋을 것 같다. (물론 샘플 프로젝트를 만들며 필요할 것 같은 내용은 아래에서 설명하겠다.) @EnableSwagger2 @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } }  테스트할 컨트롤러를 아래처럼 심플하게 작성하고(사칙연산…) 실행을 시킨 후 /swagger-ui/에 접속을 해보면 swagger 관련 javaConfig 하나만 추가했는데 문서가 만들어진 것을 확인할 수 있다. (http method는 편의상 다양하게 작성했으니 왜 DELETE 인가라는 의문은 접어두자.) @RestController public class SampleController { @GetMapping(value = "/addition") public Integer addition(Integer num1, Integer num2) { return num1 + num2; } @PostMapping(value = "/subtraction") public Integer subtraction(Integer num1, Integer num2) { return num1 - num2; } @PutMapping(value = "/multiplication") public Integer multiplication(Integer num1, Integer num2) { return num1 * num2; } @DeleteMapping(value = "/division") public Integer division(Integer num1, Integer num2) { return num1 / num2; } } 기본 셋팅만 했는데 이런 화면이 나타났다." 기본 셋팅만 했는데 이런 화면이 나타났다.  위에서 했던 설정들 중 몇 가지만 좀 더 자세히 살펴보자. 설정 설명 Docket Springfox 프레임 워크의 기본 인터페이스가 될 빌더로 구성을 위한 여러 가지 기본값과 편리한 방법을 제공하고 있다. 이후 select()로 ApiSelectorBuilder를 반환받아 사용할 수 있도록 해준다. apis 어떤 위치에 있는 API들을 가져올 것인가에 대한 정의. RequestHandlerSelectors.any()이라고 했으니 SpringBoot에서 기본으로 제공하는 basic-error-controller 도 API 문서로 만들어진 것을 확인할 수 있다. 특정 패키지만 적용하기 위해서는 RequestHandlerSelectors.basePackage("com.taetaetae.swagger.api") 와 같은 형식으로 지정하면 해당 패키지 하위에 있는 Controller를 기준으로 문서를 만들어 준다. paths 이름에서도 눈치를 챌 수 있듯이 특정 path만 필터링해서 문서를 만들어 준다. useDefaultResponseMessages 기본 http 응답 코드를 사용해야 하는지를 나타내는 플래그 이외에도 security 나 공통으로 사용되는 파라미터 등 다양한 옵션을 설정할 수 있으니 가능하면 상황에 맞게 설정을 변경해 보는 것도 좋을 것 같다. 다른 설정들을 추가시켜서 좀 더 친절하게 만들어 보면 아래처럼 만들 수 있고 해당 코드는 Github에서 확인 가능하다. API 문서화는 최대한 친절하게!!" API 문서화는 최대한 친절하게!! OpenAPI  Swagger 공식 홈페이지를 이리저리 둘러보면 OpenAPI라는 내용이 많이 나온다. 그렇다면 OpenAPI는 무엇일까? 문서에 나와있는 내용을 직역해보면 Swagger 사양으로 알려져 있으며 RESTful 웹 서비스를 설명, 생성, 소비 및 시각화하기 위한 기계 판독 가능 인터페이스 파일에 대한 사양이라고 한다. 즉, API 자체를 설명하는 인터페이스 스펙이라고 이해를 해볼 수 있다. 위에서 만들어졌던 Swagger를 보면 http://localhost:8080/v2/api-docs?group=Test API 라고 나와있는데 이를 클릭해보면 아래와 같이 json 형태로 보인다.

Swagger 적용하며 만난 자잘한 이슈

Swagger로 제네릭 타입 감지
잠깐 보고 가는 제네릭 두 가지 방식 : 난 첫 번째 방식이 더 좋은 거 같음. 타입 검사가 되어서
1.
return new Result<>(agents);
제네릭(Generic)을 사용하여 Result 클래스의 생성자를 호출하는데,
agents 변수의 타입이 Result 클래스의 타입 매개변수와 일치하도록 추론
다이아몬드 문법으로 제네릭 타입을 더 간결하게 작성할 수 있도록 도와줌
agents의 실제 타입은 컴파일러가 타입 추론을 통해 결정함
2.
return new Result(agents);
명시적으로 제네릭을 사용하지 않고 Result 클래스의 생성자를 호출
컴파일러는 agents의 타입에 대한 제네릭 정보를 사용하지 않고 그냥 agentsResult 생성자에 전달함
Swagger https cors
Swagger애서 api 테스트를 하려 할 때 계속해서 CORS 에러가 났다
직접 url을 명시해줘서 해결해줬다. 요렇게 써두면 swagger ui에서 url을 선택할 수 있다.
@OpenAPIDefinition(servers = { @Server(url = "http://localhost:8080", description = "Local Server URL"), @Server(url = "https://call-dev.iluvit.app", description = "Dev Server URL"), @Server(url = "https://call-api.iluvit.app", description = "Prod Server URL") }) @SpringBootApplication public class PoliceApplication {
YAML
복사
이번 swagger 적용 시 반영 안해준 친구들 → 추후 추가해줄 예정
사실 우리팀은 restDocs로 곧 갈아탈 거라,,,, swagger에 그렇게 힘을 들이진 않기로 했다,,, 그래서 detail한 부분은 조금,,, 놓아줬다,,, 완벽히 하고 싶은 분들은 아래 키워드들도 찾아보고 반영해주자
Swagger enum
Request body와 multipart file → 현재 multipart form data swagger가 인식 못함
Swagger RequestHeader Authorization