다른 서버와의 통신을 위해 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)
에 유효성 검증(@NotNull
)을 추가하면서, 해당 API 호출시에 유효성 검증 조건에 위배된다는 슬랙 알림이 마구 터졌다.
그런데 UpdateMemberRequest
디버깅할 시에, job 필드
에 값이 존재하는데.. 요청할 때는 안 들어간다고요..??!
public class LoggerLevelConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
cloud:
openfeign:
client:
config:
default:
logger-level: full
종류 | 설명 |
---|---|
NONE | 로깅하지 않는다. (기본 설정) |
BASIC | Request Method, URL, Response 상태 코드, 실행 시간을 로깅한다. |
HEADERS | Request, Response 헤더 정보와 BASIC 정보를 로깅한다. |
FULL | Request와 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)
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 에서 제외하고 있다.
UpdateMemberRequest
의 job
필드에서 final
을 제거하면, map 에서 job 필드를 찾을 수 있다.