Skip to content
isdnetworks
Go back

성공이 아니었던 200

외부 시스템의 옵션 수정 엔드포인트를 다루고 있었다. 응답 계약을 확인하다 상태 코드가 200인데 실패인 경우를 봤다.

Table of contents

Open Table of contents

상황 — 200인데 실패

응답이 이렇게 온다.

HTTP 200
{ "resultCode": "500", ... }

HTTP 200 인데 resultCode 에는 500 이 들어 있다.

[상태 코드]  전송·처리 자체는 됐다
[바디 코드]  업무적으로 됐나

상태 코드바디 코드 가 서로 다른 것을 말하고 있었다.

원인 — 두 층으로 나뉜 결과

이 방식 자체는 특별한 것이 아니고 많은 시스템이 이렇게 한다. 문제는 부르는 쪽에서 잊기 쉽다는 점이다.

if ($response->successful()) {   // 200이면 참
    // 성공 처리
}

successful() 만 보면 업무 실패가 성공으로 기록된다.

if (!$response->successful()) {
    throw new \Exception('전송 실패');
}
$body = $response->json();
if ($body['resultCode'] !== '0') {
    throw new \Exception("업무 실패: {$body['resultCode']}");
}

successful()resultCode 를 두 단계로 나눠 봐야 한다.

HTTP 200 이면 대개 성공이라 이 실수는 평소에 안 드러난다. 실패가 생기는 날에만 그것이 성공으로 남는다.

필드를 빼면 호출이 두 번이 됐다

규격을 더 읽다가 다른 것이 나왔다. 특정 필드를 생략하면 서버 동작 자체가 바뀐다.

[필드 포함]  바로 수정 호출
[필드 생략]  선행 조회 → 값을 얻음 → 수정 호출

생략하면 상대 쪽에서 선행 조회 와 수정으로 호출이 두 번이 된다.

그 필드는 원래 값을 유지해야 하는 것이라 누군가는 현재 값을 알아야 한다. 부르는 쪽이 모르면 서버가 대신 조회하는 편의를 준 것으로 보인다.

[한 번 호출]  실패 지점 하나
[두 번 호출]  선행 조회 실패 + 수정 실패

편의를 얻는 대신 실패 지점이 늘고 그 실패가 다른 모양으로 온다.

선행 조회 파싱 실패 → 상위 서비스 불가 오류

상위 서비스 불가 처럼 우리가 보낸 것과 무관해 보이는 오류가 돌아오는 셈이다.

제약 — 겹칠 때만 나는 오류

오류 코드 하나가 특이했다.

404 = 필드 생략 + 그 하위 항목이 그 상위에 속하지 않음

404 는 두 조건이 동시에 성립할 때만 난다.

[필드 포함]  선행 조회 없음 → 소속을 확인 안 함
[필드 생략]  선행 조회 → 그 안에서 못 찾음 → 404

소속 검사가 선행 조회 의 부수 효과라서 그렇다.

각 조건을 따로 시험하면 둘 다 통과하므로 조합을 적어 두지 않으면 그 경우는 운영에서 처음 만나게 된다.

정리하면 필드를 빼는 쪽이 느리고 검사가 많아서 우리는 값을 알고 있으면 넣는 쪽으로 갔다.

비교 — 우리가 정한 것과 남이 정한 것

응답 경로가 하나 더 있었다.

422 = 프레임워크의 기본 역직렬화 실패

요청이 우리 코드에 닿기 전에 프레임워크가 422 를 자기 형식으로 돌려보내는 경우다.

[우리 검증]  400 + 우리가 정한 JSON 형식
[프레임워크]  422 + 라이브러리가 정한 형식

부르는 쪽에서는 같은 엔드포인트인데 경우에 따라 다른 모양이 온다.

이 422 응답의 본문 문자열을 테스트로 고정할지가 판단이었다.

[고정]      회귀를 잡음. 라이브러리 올리면 깨짐
[안 고정]   버전 올려도 안 깨짐. 형식 변화를 못 잡음

안 고정하기로 했는데 422 의 본문은 우리가 정한 것이 아니기 때문이다.

우리가 안 정한 것을 우리 테스트로 묶으면 라이브러리를 올릴 때마다 무의미하게 깨진다. 422 가 나온다는 것은 확인하되 본문 문자열은 보지 않는 선에서 검증을 멈추기로 했다.

조치 — 조건별 응답 표를 남겼다

확인한 것들을 한 표로 모았다.

200 + resultCode 0     성공
200 + resultCode 그 외  업무 실패
404                    필드 생략 + 소속 불일치
422                    역직렬화 실패 (프레임워크 경로)
502                    선행 조회 실패

200 두 줄만 봐도 상태 코드만으로는 구분되지 않는다.

이 표가 없으면 502 를 받은 사람이 엉뚱한 데를 본다. 502를 보고 상대 서버가 죽었다고 판단해 그쪽에 문의하는데 실제로는 우리가 필드를 빼서 선행 조회가 실패한 것일 수 있다.

어떤 조건이 어떤 코드를 만드는지를 적어 두면 그 왕복이 없어지고 새로 붙이는 사람이 상대에게 물어보는 일도 준다.

정리


Share this post on:

Previous Post
대상이 늘면 장비가 늘어야 했다
Next Post
초기화 스크립트가 소스와 어긋났다