본문 바로가기
공부/프로그래밍

[swagger3] schema 등록시 Could not resolve reference: undefined 에러(Error-ModelName)

by demonic_ 2021. 4. 26.
반응형

Swagger3으로 변경하면서 이전에 output의 클래스를 지정하는 기능이 작동하지 않았다.

예를들면 다음과 같다.

 

Swagger2 버전에서의 설정

@ApiOperation(value = "1. 로그인")
@ApiResponses(
   @ApiResponse(code = 200, message = "success", response = ResponseLogin.class)
)
@PostMapping("/api/oauth/login")
public ResponseNoCount login(@RequestBody @Valid RequestLogin request) {
  ResponseLogin response = new ResponseLogin("aaa","Bbb",10, false);
  return new ResponseNoCount(response);
}

ResponseLogin.java

@Getter
public class ResponseLogin {
    @ApiModelProperty(value = "accessToken")
    private String accessToken;
    @ApiModelProperty(value = "refreshToken")
    private String refreshToken;
    @ApiModelProperty(value = "expiresIn(만료, 초단위)")
    private int expiresIn;
    @ApiModelProperty(value = "가입여부")
    private Boolean memberYn;
}

 

Swagger2 에선 이렇게 하면 다음처럼 잘 작동되었다.

문제는 3버전으로 오면서 다음처럼 수정을 했는데, 에러가 발생하면서 (no example avaliable) 이라고 뜨고 있었다.

 

변경된 설정

@Operation(tags = "1. 로그인", summary = "로그인",
  responses = {
      @ApiResponse(
          responseCode = "200", description = "ok"
          , content = @Content(schema = @Schema(implementation = ResponseLogin.class)))
  })
@PostMapping("/api/oauth/login")
public ResponseNoCount login(@RequestBody @Valid RequestLogin request) {
  ResponseLogin response = new ResponseLogin("aaa","Bbb",10, false);
  return new ResponseNoCount(response);
}

ResponseLogin.java 변경 (@ApiModelProperty => @Schema 로 변경)

@Schema(description = "로그인 요청")
@Getter
public class ResponseLogin {
    @Schema(description = "accessToken")
    private String accessToken;
    @Schema(description = "refreshToken")
    private String refreshToken;
    @Schema(description = "expiresIn(만료, 초단위)")
    private int expiresIn;
    @Schema(description = "가입여부")
    private Boolean memberYn;
}

 

 

에러문구

 

Swagger-ui 화면

 

그래서 api-docs 에서 생성된 json을 보니 다음과 같이 Error-ModelName 이라고 되어있다.

 

해당 상황은 다음과 같은 설정에서 문제가 발생하는데 output을 그대로 담는게 아니라 어떤 특정 폼을 담아서 리턴할때 그렇게 발생한다. 위 코드에서 ResponseNoCount 에대한 클래스를 공개하지 않았는데 해당 구성은 다음과 같다.

@Getter
public class ResponseNoCount<T> {
    private T values;

    public ResponseNoCount(T values) {
        this.values = values;
    }
}

즉 ResponseNoCount 클래스에서 제너릭으로 output으로 보낼 객체를 받은다음(여기서는 ResponseLogin.java) 리턴하게 되어있는데, 이것을 사용하지 않고 ResponseLogin 를 그대로 리턴하면 이런 문제가 발생하지 않는다.

@Operation(tags = "1. 로그인", summary = "로그인",
  responses = {
      @ApiResponse(
          responseCode = "200", description = "ok"
          , content = @Content(schema = @Schema(implementation = ResponseLogin.class)))
  })
@PostMapping("/api/oauth/login")
public ResponseLogin login(@RequestBody @Valid RequestLogin request) {
  ResponseLogin response = new ResponseLogin("aaa","Bbb",10, false);
  return response;
}

 

그런데 이미 만들어진 것을 모두 이렇게 바꿀 순 없는 노릇이었다. 그리고 ResponseNoCount.java 에는 최소한의 정보만 담겨있지만 그 외 데이터를 추가해도 form을 유지해서 사용하기 좋으며 frontend와의 협업에도 도움이 된다. 그럼 이 문제를 어떻게 해결해야 할까 고민하다 차선책이지만 방법을 찾았다.

 

Error-ModelName 이 발생하는 이유는 말그대로 모델을 생성하지 못해서 그렇다. 지금까지 찾아본 바로 모델을 생성하는 방법은 2가지가 있다.

1) 방금전처럼 return 을 즉각 던질경우

2) 지정한 클래스의 모델이 생성되도록 이전 버전의 @ApiResponse을 같이 등록하기

그러나 1번은 output form을 유지해야 한다는 점에서 불가하니 2번 방법을 사용하기로 했다.

 

수정된 방법은 다음과 같다.

@Operation(tags = "1. 로그인", summary = "로그인",
  responses = {
      @ApiResponse(
          responseCode = "200", description = "ok"
          , content = @Content(schema = @Schema(implementation = ResponseLogin.class)))
  })
@io.swagger.annotations.ApiResponses(
      @io.swagger.annotations.ApiResponse(
          response = ResponseLogin.class, message = "ok", code=200)
  )
@PostMapping("/api/oauth/login")
public ResponseNoCount login(@RequestBody @Valid RequestLogin request) {
  ResponseLogin response = new ResponseLogin("aaa","Bbb",10, false);
  return new ResponseNoCount(response);
}

 

이렇게 하면 Error-ModelName 이라든가 Could not resolve reference: undefined 에러가 사라진다.

 

뭔가 찜찜하게 끝났지만 일단 이정도로 마무리.

 

 

 

끝.

반응형

댓글