배송 추적 연동을 문서대로 만들었는데 실제 응답이 다르게 왔다.
Table of contents
Open Table of contents
문서와 실제가 달랐다
문서에는 result 가 대문자 Y 와 N 으로 오고 regDate 가 구분자 있는 형식으로 온다고 적혀 있었다. log_message 로 응답을 통째로 남겨 실제를 봤다.
{"result":"y","status":"41","statusName":"배송완료","regDate":"20150407103022"}
세 가지가 달랐다. result 가 소문자로 왔다. regDate 에 구분자가 없었다. 어떤 응답에는 statusName 이 아예 없었다. 상대에게 알렸지만 고쳐 주는 데 시간이 걸린다고 해서 우리 쪽에서 다뤄야 했다.
실제를 기준으로 고쳤다
strtolower 로 대소문자를 안 가리게 했다. 날짜는 preg_match 로 두 형식을 갈라 받는다. 문서 형식으로 바뀔 수도 있으니 둘 다 두는 것이 맞았다.
$raw = $res['regDate'] ?? '';
if (preg_match('/^\d{14}$/', $raw)) {
$dt = DateTime::createFromFormat('YmdHis', $raw);
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} /', $raw)) {
$dt = DateTime::createFromFormat('Y-m-d H:i:s', $raw);
} else {
log_message('error', '알 수 없는 날짜 형식: ' . $raw);
$dt = null;
}
모르는 형식이 오면 log_message 에 남기고 null 로 둔다. 조용히 오늘 날짜로 채우지 않았다. 채우면 그 자리에서는 넘어가지만 나중에 이상한 날짜를 보고 원인을 못 찾는다.
DateTime::createFromFormat 자체에도 조용히 채우는 성질이 있다. 형식에 시분초가 없으면 그 자리를 현재 시각으로 메운다. 'Ymd' 로 '20150407' 을 넘기면 뒤에 지금 시각이 붙는다. 앞에 ! 를 붙여 '!Ymd' 로 줘야 00:00:00 이 된다.
statusName 이 없는 경우에는 status 코드로 우리 표에서 채웠다. 그 표는 상대 문서에서 옮긴 것이라 낡을 수 있다. 모르는 코드가 오면 log_message 에 남기게 했다. 실제로 두 달 뒤 새 코드가 하나 늘었고 그 로그에서 봤다.
받은 것을 그대로 남겼다
파싱한 결과 말고 받은 응답 자체를 저장했다.
$this->db->insert('delivery_log', [
'invoice' => $invoice,
'raw' => json_encode($res, JSON_UNESCAPED_UNICODE),
'reg_date' => date('Y-m-d H:i:s'),
]);
raw 에 원문이 있으니 우리가 잘못 읽은 것인지 상대가 이상하게 준 것인지가 갈린다. JSON_UNESCAPED_UNICODE 를 준 이유는 따로 있다. 한글이 \uXXXX 로 박히면 눈으로 못 본다. 이걸 안 남겼으면 문서와 다르다는 것 자체를 몰랐을 것이다.
바뀌면 알게 하는 장치
한 번 맞춘 것이 나중에 또 바뀔 수 있어서 array_diff 로 응답 항목을 검사하게 했다.
$expected = ['result', 'status', 'regDate'];
$missing = array_diff($expected, array_keys($res));
if ($missing) {
log_message('error', '응답에 없는 항목: ' . implode(',', $missing));
}
$extra = array_diff(array_keys($res), $expected, ['statusName']);
if ($extra) {
log_message('info', '응답에 새 항목: ' . implode(',', $extra));
}
없어진 항목과 새로 생긴 항목을 둘 다 봤다. 새 항목이 생기는 것 자체는 문제가 아니지만 나중에 필요할 수 있어서 남겼다.
상대에게 언제 무엇을 알렸는지도 날짜와 함께 적어 뒀다. 나중에 그때 알렸다는 말에 근거가 생기고, 상대가 고쳐 주면 우리 쪽 대응 코드를 뺄지 판단하는 자리가 된다. 실제로는 안 뺐다. 둘 다 받는 쪽이 안전했다.
정리
- 문서와 실제 응답이 다를 수 있다
- 받은 것을
log_message로 남겨 무엇이 오는지 확인한다 - 다르면 실제를 기준으로 맞춘다. 상대가 고칠 때까지 기다릴 수 없다
- 여러 형식을
preg_match로 갈라 받되 모르는 것은null로 두고 남긴다 createFromFormat은 형식에 없는 시분초를 현재 시각으로 메운다'!Ymd'처럼!를 앞에 붙여야00:00:00이 된다raw를JSON_UNESCAPED_UNICODE로 저장하면 누가 잘못한 것인지 갈린다array_diff로 없어진 항목과 새 항목을 둘 다 본다- 상대에게 알린 것을 날짜와 함께 남긴다