[트러블슈팅 - Spring] Feign Form 요청시에는 final 필드를 조심하자

Hocaron·2023년 6월 18일
0

트러블슈팅

목록 보기
7/9

다른 서버와의 통신을 위해 Spring Cloud Feign 을 사용하고 있다. 요청 필드 중에 디폴트값으로만 보내야하는 요구사항이 있어 해당 필드는 final 로 선언을 해놓았다.

    @PutMapping(value = "/v1/members/{memberNo}", consumes = APPLICATION_FORM_URLENCODED)
    ApiResponseModel update(@PathVariable long memberNo,
                            @ModelAttribute UpdateMemberRequest request);
public class UpdateMemberRequest {

    private final String job = "개발자"; // 문제의 발단

    private String name;
}

카롱님, job 필드가 null 로 들어와요

다른 서버에서 해당 필드(job) 에 유효성 검증(@NotNull)을 추가하면서, 해당 API 호출시에 유효성 검증 조건에 위배된다는 슬랙 알림이 마구 터졌다.

그런데 UpdateMemberRequest 디버깅할 시에, job 필드에 값이 존재하는데.. 요청할 때는 안 들어간다고요..??!

Feign 로그를 찍어보자

public class LoggerLevelConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
cloud:
  openfeign:
    client:
      config:
        default:
          logger-level: full

Logger.Level 종류

종류설명
NONE로깅하지 않는다. (기본 설정)
BASICRequest Method, URL, Response 상태 코드, 실행 시간을 로깅한다.
HEADERSRequest, Response 헤더 정보와 BASIC 정보를 로깅한다.
FULLRequest와 Response의 헤더, 본문, 메타데이터를 로깅한다.

로깅 설정은 application.yml 파일을 이용하거나 Configuration 설정을 통해 지정할 수 있다.

@FeignClient(name = "member-api-service", configuration = LoggerLevelConfiguration.class)
public interface MemberClient {


    @PutMapping(value = "/v1/members/{memberNo}", consumes = APPLICATION_FORM_URLENCODED)
    ApiResponseModel update(@PathVariable long memberNo,
                            @ModelAttribute UpdateMemberRequest request);

아래 로그를 보면 job 필드는 요청 시에 안 들어가고 있다.

2023-06-18 14:00:34.958 DEBUG 98885 --- [nio-8088-exec-4]  c.k.m.m.a.c.c.a.MemberClient       : [MemberClient#update] ---> PUT http://member-api-service/v1/members/25487634 HTTP/1.1
2023-06-18 14:00:34.959 DEBUG 98885 --- [nio-8088-exec-4] c.k.m.m.a.c.c.a.MemberClient        : [MemberClient#update] Content-Type: application/x-www-form-urlencoded; charset=UTF-8
2023-06-18 14:00:34.959 DEBUG 98885 --- [nio-8088-exec-4] c.k.m.m.a.c.c.a.MemberClient        : [MemberClient#update] name=hocaron
2023-06-18 14:00:34.959 DEBUG 98885 --- [nio-8088-exec-4] c.k.m.m.a.c.c.a.MemberClient        : [MemberClient#update] ---> END HTTP (431-byte body)

Dto 에는 값이 담기는데, 요청 시에 null 로 가는 이유는 뭘까?

Feign 에서 Form 데이터 바인딩 시에 PojoUtil 이용하는데 필드가 final 또는 static 이면 map 에 추가 되지 않아서, 요청시에 해당 필드는 안 들어어가고 있었다...😱

테스트를 통해 한번더 확인하자

public class FieldTest {

    private UpdateMemberRequest request;

    @BeforeEach
    void setUp() {
        request = new UpdateMemberRequest("hocaron");
    }

    @Test
    @DisplayName("final 필드는 map 에 추가되지 않는다")
    void PojoUtilTest() throws Exception {
        Map requestMap = PojoUtil.toMap(request);

        assertThat(requestMap)
                .contains(entry("name" ,"hocaron"))
                .doesNotContain(entry("job", "개발자"));
    }

    @Test
    @DisplayName("final 필드도 직렬화한다.")
    void ObjectMapperTest() throws Exception {
        String requestString = new ObjectMapper().writeValueAsString(request);
        assertThat(requestString).isEqualTo("{\"job\":\"개발자\",\"name\":\"hocaron\"}");
    }

    @AllArgsConstructor
    @Getter
    public class UpdateMemberRequest {

        private final String job = "개발자"; // 문제의 발단

        private String name;
    }
}
}

ObjectMapper 는 final 필드를 직렬화를 하고 있지만, PojoUtil 은 map 에서 제외하고 있다.

UpdateMemberRequestjob 필드에서 final 을 제거하면, map 에서 job 필드를 찾을 수 있다.

정리

  • Feign Form 요청 시에는 Final, static 필드를 조심하자.
  • Feign 로그를 통해 의도한 대로 요청이 가고 있는지 확인해보는 것도 좋을 것 같다.
profile
기록을 통한 성장을

0개의 댓글