[개발 깨알 상식_Tips] / JSON 검사를 실패 신호로 바로 세우기.md

JSON 검사를 실패 신호로 바로 세우기

조회

2026년 6월 3일 | 개발 깨알 상식_Tips


JSON 검사를 실패 신호로 바로 세우기 흐름 도식
JSON 검사를 사람 눈 확인에 맡기지 않고, 자동화가 읽을 수 있는 실패 신호로 바꾸는 흐름.

jq -e는 JSON을 예쁘게 출력하는 옵션이 아니라, 필터 결과를 명령의 성공·실패 신호로 바꿔 주는 옵션에 가깝다. 나는 API 응답이나 실험 로그를 확인할 때, 화면에 값이 보이는지만 보고 넘어갔다가 나중에 자동화 단계에서 놓친 적이 몇 번 있었다. 특히 상태값 하나만 틀린 응답은 터미널에서는 금방 보이지만, 배치에서는 조용히 다음 단계로 넘어가기 쉽다. 사람이 눈으로 보는 검사와 스크립트가 믿을 수 있는 검사는 다르다. 그 사이를 좁힐 때 -e가 꽤 쓸 만하다.

값 출력과 통과 판정을 분리하기

jq를 그냥 쓰면 필터 결과가 false여도 출력 자체는 정상적으로 끝날 수 있다. 예를 들어 응답 JSON 안의 상태가 ok인지 보려면 아래처럼 쓸 수 있다.

jq '.status == "ok"' response.json

이 명령은 화면에 true 또는 false를 보여 준다. 사람이 터미널을 보고 있을 때는 충분해 보인다. 하지만 CI나 배치 스크립트에서는 false가 찍혔다는 사실만으로 다음 단계가 멈추지 않을 수 있다. 출력은 실패를 말하고 있는데, 종료 코드는 성공으로 남는 식이다. 이럴 때 출력값을 사람이 읽는 정보로만 두지 말고, 종료 코드까지 같이 설계해야 한다.

jq -e '.status == "ok"' response.json >/dev/null

-e를 붙이면 마지막 결과가 falsenull일 때 실패 종료 코드가 나온다. 반대로 true나 실제 값이 나오면 성공으로 본다. 그래서 위 명령은 “JSON을 파싱할 수 있고, status가 ok인가”를 한 줄의 판정으로 만든다. 값 자체를 화면에 남길 필요가 없으면 >/dev/null로 출력은 버리고 종료 코드만 쓰면 된다.

필드 존재 여부는 null과 false를 구분하기

자주 헷갈리는 지점은 필드 존재 검사다. 어떤 필드가 반드시 있어야 한다면 .items만 보는 것보다 조건을 분명히 쓰는 편이 낫다.

jq -e '.items != null' response.json >/dev/null
jq -e '(.items | type) == "array"' response.json >/dev/null
jq -e '(.items | length) > 0' response.json >/dev/null

세 줄은 서로 다른 질문이다. 첫 줄은 필드가 비어 있지 않은지만 본다. 둘째 줄은 배열인지 확인한다. 셋째 줄은 배열이 하나 이상 들어 있는지까지 본다. 나는 예전에는 이런 검사를 뭉뚱그려 “items가 있나?”라고 적었는데, 나중에 빈 배열과 누락 필드가 같은 실패처럼 섞였다. 검사 문장은 실제로 멈추고 싶은 조건만큼 좁게 쓰는 편이 로그 해석을 덜 피곤하게 만든다.

파이프라인에서는 앞단 실패도 같이 보존하기

jq -e를 API 호출 뒤에 바로 붙일 때는 앞단 명령 실패도 같이 생각해야 한다. HTTP 요청이 실패했는데 빈 파일이나 에러 HTML이 뒤로 흘러가면, 문제는 JSON 필터가 아니라 입력 자체다. 그래서 나는 응답 본문을 파일로 한 번 저장하고, 그 파일을 jq -e로 검사하는 흐름을 더 선호한다.

curl --fail-with-body -sS -o response.json https://example.com/api/status
jq -e '.status == "ok"' response.json >/dev/null

이렇게 나누면 실패했을 때 볼 것이 분리된다. curl이 실패했으면 네트워크, 인증, HTTP 상태를 본다. curl은 통과했는데 jq -e가 실패했으면 JSON 구조나 값 조건을 본다. 한 줄로 멋지게 엮는 것보다, 입력 확보와 JSON 판정을 다른 단계로 두는 것이 재현에는 더 편했다.

여러 조건은 all로 접기

조건이 많아지면 셸의 &&만 늘어놓기보다, JSON 안에서 묶어 판정하는 편이 읽기 쉽다.

jq -e 'all([
  .status == "ok",
  (.items | type) == "array",
  (.items | length) > 0,
  .error == null
]; .)' response.json >/dev/null

이 필터는 네 조건이 모두 참일 때만 통과한다. 조건 목록이 길어질수록 장점이 있다. 실패했을 때는 같은 파일을 열어 각 조건을 하나씩 출력해 보면 된다. 나는 보통 자동화에서는 조용한 판정 명령을 쓰고, 디버깅할 때만 조건별 값을 보여 주는 별도 필터를 만든다. 운영용 판정과 디버깅용 설명을 분리해 두면 로그가 덜 지저분해진다.

테스트 스크립트에는 실패 메시지를 따로 붙이기

jq -e는 실패를 잘 알려 주지만, 왜 실패했는지까지 친절하게 설명해 주지는 않는다. 그래서 테스트 스크립트에 넣을 때는 조용한 판정 뒤에 내가 읽을 메시지를 한 줄 붙인다. 자동화가 멈춘 뒤 로그를 다시 열었을 때, “JSON 파싱 실패인지”, “필드 누락인지”, “값 조건 실패인지”를 바로 구분할 수 있어야 한다.

if ! jq -e '.status == "ok"' response.json >/dev/null; then
  printf '%s\n' 'status가 ok가 아니어서 다음 단계를 멈춤' >&2
  exit 1
fi

이 정도 메시지는 사소해 보이지만, 여러 검사가 이어질 때 차이가 난다. 특히 nightly job이나 데이터 수집 배치처럼 실패를 다음 날 아침에 보는 작업에서는, 조건식만 남은 로그가 생각보다 불친절하다. 같은 jq -e 실패라도 “값이 false였다”와 “입력 JSON이 아니었다”는 다음 행동이 완전히 다르다. 판정은 기계가 하되, 실패 문장은 미래의 내가 읽는다는 기준으로 한 줄 붙여 두는 편이 좋았다.

언제 쓰지 말아야 하나

jq -e가 모든 JSON 검증을 대신하지는 않는다. 스키마 전체를 검증해야 하거나, 타입과 필수 필드가 많은 계약을 확인해야 하면 JSON Schema 같은 도구가 더 맞다. -e는 가벼운 컷라인이다. “이 응답을 다음 단계에 넘겨도 되는가”, “이 실험 로그가 최소 조건을 만족했는가”, “이 배치 결과가 빈 목록으로 끝나지 않았는가”처럼 작은 판정을 빠르게 고정할 때 좋다.

내 기준은 단순하다. 화면에서 한 번 보고 끝낼 확인이면 일반 jq도 충분하다. 하지만 그 확인 결과가 다음 명령의 실행 여부를 결정한다면 jq -e를 먼저 붙인다. 출력은 사람에게 설명하고, 종료 코드는 자동화가 행동하게 만든다. 이 둘을 분리해 두면, JSON 로그를 다루는 작은 스크립트가 훨씬 덜 애매해진다. 작은 옵션 하나지만, 실패를 눈치가 아니라 계약으로 바꾸는 느낌에 가깝다.

댓글

홈으로 돌아가기

검색 결과

"" 검색 결과입니다.