[API] json 데이터가 지 맘대로 null이 된다.
@RequestBody 써서 그냥 데이터 받아오면 되는 거 아닌가????
(외부 api와 연동할 때, 일어날 확률이 높을지도...?)
간단한 결제 기능을 구현할 때 일어난 일이다.
포트원은 안정적인 결제 처리를 위해 웹훅을 권장하기에, ngrok를 이용해 웹훅 연동을 해봤다.
로컬호스트를 이용해 서버를 띄우는 분들이라면, 다른 블로그를 통해 ngrok 사용법을 검색해보길.
@PostMapping("/webendpoint")
@ResponseBody
public String handleWebhook(@RequestBody Payment payload) {
System.out.println(payload.getimp_uid());
System.out.println(payload.getmerchant_uid());
System.out.println(payload.getStatus());
System.out.println("웹훅 수신이 정상적으로 완료됨");
return null;
}
import com.siot.IamportRestClient.response.Payment;
임포트하면 우리는 Payment 를 사용할 수 있다. 단순하게 나는 제대로 수신이 되는지 확인하려고 get()를 이용했으나 이상하게 자꾸 null이 들어왔다. Payment 에는 수많은 변수들이 설정되어 있는 걸 알 수 있는데, @RequestBody를 통해 들어오는 값이, 지정한 get()와 일치하지 않는다고 판단해 그럴싸?한 get()을 사용해봤지만 전부 null... 그러다가 payload.getStauts()를 통해 paid라는 값이 들어온 걸 알게 된다. 그렇다면 위 코드에 표기된 2개의 값은 들어오지 않았다? 라고 생각했지만 말이 되지 않는다. 위 2개의 값은 무엇보다 결제의 고유값?을 확인할 때 무엇보다 필요할 테니 말이다. 그래서 든 생각은 '테스트'로 진행되는 결제이기에 애초에 imp_uid 와 merchant_uid 값을 보내주지 않았다? 그래서 받지 못했다고 생각했다. 그렇다면 유일하게 받은 paid는 무엇이란 말인가... 그래서 포트원 관리자 페이지를 뒤진 끝에 웹훅으로 전송하는 값이 무엇인지 알아낼 수 있었다.
{"imp_uid":"imp_614505216799","merchant_uid":"IMPtz60b24qh0elxd3320p","status":"paid"}
json 형식으로 웹훅을 전송한다. 따라서 나는 위 3개의 키에 해당하는 값을 받을 수 있어야 한다. 하지만 여전히 받지 못하니 다시 검색을 했고, 끝내 해결 방법을 찾아냈다. 키 이름에 해당하는 _ 이 문제였다. 스네이크 표기법이라고 하는데, 이 키가 Payment로 들어갈 때.
실제 Payment.class
@SerializedName("imp_uid")
String imp_uid;
@SerializedName("merchant_uid")
String merchant_uid;
변수명과는 일치하지만!
public String getImpUid() {
return imp_uid;
}
public String getMerchantUid() {
return merchant_uid;
}
get()에 표기된 이름과는 다른 걸 알 수 있다. 변수명은 스네이크 표기법, 메서드 이름은 카멜 표기법의 차이인 것이다.
그래서 필드명과 get()의 이름이 동일한 status만 올바르게 값을 받아올 수 있었던 것...
@SerializedName("status")
String status;
public String getStatus() {
return status;
}
이러한 이유로 status 값만 받아왔다는 사실이 진짜... 솔직히 소름 돋음.
다른 개발자 블로그를 통해 알게 된 사실은 필드명이 아닌 get() 이름이 기준이 된다는 것.
(필드명과 getter 이름을 다르게 하고 데이터를 출력해보면 {"getter이름" : "값"})
public class MyPayment {
private String imp_uid;
private String merchant_uid;
private String status;
public String getimp_uid() {
return imp_uid;
}
public void setimp_uid(String imp_uid) {
this.imp_uid = imp_uid;
}
public String getmerchant_uid() {
return merchant_uid;
}
public void setmerchant_uid(String merchant_uid) {
this.merchant_uid = merchant_uid;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
직접 따로 객체를 만들어서 (필드명과 getter를 만들 때 이름 같게 설정)
@PostMapping("/webendpoint")
@ResponseBody
public String handleWebhook(@RequestBody MyPayment payload) {
// ngrok를 통해 통신한다.
// 포트원이 보내는 형식
// {"imp_uid":"imp_614505216799","merchant_uid":"IMPtz60b24qh0elxd3320p","status":"paid"}
System.out.println(payload.getimp_uid());
System.out.println(payload.getmerchant_uid());
System.out.println(payload.getStatus());
System.out.println("웹훅 수신이 정상적으로 완료됨");
return null;
}
정상적으로 값을 받을 수 있었다.
json을 통해 값을 주고 받을 때 조심해야할 문제들을 알게 됐다.
(자바공부 시작할 때, class는 대문자로 시작하고, 변수명은 소문자로 시작해서 단어가 바뀔 때 첫글자를 대문자로 표기하고... 등등 대수롭지 않게 여긴 규약? 이 이렇게 문제로 드러날 수도 있겠다고 처음으로 생각한 에러였다. 개발자들 사이에서 약속이 얼마나 중요한 건지.)
다른 개발자 분들이 써놓은 글들을 보니 이정도만 알고 넘어가기에는, 단순히 에러를 해결하기 위해 해결 방안을 찾고 적용해 끝! 이라고 하기에는 너무나 중요하다고 생각이 들었으니 더 공부해야겠다...