API
REST API에서 JSON 응답이 이상할 때 확인할 것
REST API에서 JSON 응답 형식이 예상과 다르거나 파싱 에러가 날 때 상태 코드, 본문, 인코딩을 확인하는 체크리스트를 정리했다.
API를 호출했는데 응답이 유효한 JSON이 아니거나, JSON은 맞는데 구조가 다르거나, 일부 필드가 누락된 일이 자주 생긴다. 대부분은 에러 상황에서 HTML을 반환하거나, 필드명이 변경되었거나, 인코딩이 깨진 경우다.
응답을 있는 그대로 살펴본다
먼저 API의 실제 응답을 완전히 본다:
# 상태 코드와 응답 헤더 함께 보기
curl -i 'https://api.example.com/items'
# 응답 본문을 파일로 저장해서 상세히 분석
curl -s 'https://api.example.com/items' > response.json
cat response.json
# 또는 포매팅해서 보기
curl -s 'https://api.example.com/items' | jq .
HTTP 상태 코드 확인
HTTP 상태 코드가 응답 형식을 결정한다:
# 상태 코드만 보기
curl -o /dev/null -s -w "%{http_code}" 'https://api.example.com/items'
# 상태 코드별 응답 형식
# 200 OK: 정상 JSON
# 201 Created: 생성됨, JSON
# 204 No Content: 응답 본문 없음
# 400 Bad Request: 에러 JSON
# 401 Unauthorized: 에러 JSON 또는 HTML
# 500 Internal Server Error: HTML 또는 에러 JSON
상태 코드가 200이 아닌데 JSON으로 파싱하려고 하면 실패한다.
응답 Content-Type 헤더 확인
# 응답 헤더만 보기
curl -s -I 'https://api.example.com/items'
# Content-Type 확인
curl -s -I 'https://api.example.com/items' | grep -i content-type
예상되는 것들:
# 올바른 JSON 응답
Content-Type: application/json; charset=utf-8
# 잘못된 응답 (에러 페이지)
Content-Type: text/html; charset=utf-8
# 빈 응답
Content-Type: application/json (본문 없음)
응답이 HTML인 경우
API가 에러 페이지를 반환하는 경우:
# 응답 본문을 보면?
curl -s 'https://api.example.com/items'
# <html><head>...
# 이렇게 HTML이 나온다면 서버 에러다
# 원인 파악
# 1. 인증 실패 (401 Unauthorized로 로그인 페이지 반환)
# 2. 접근 금지 (403 Forbidden로 에러 페이지 반환)
# 3. 엔드포인트 없음 (404 Not Found로 HTML 반환)
# 4. 서버 에러 (500으로 에러 페이지 반환)
# 권한 확인
curl -H "Authorization: Bearer <token>" 'https://api.example.com/items'
# API 엔드포인트 확인 (올바른 URL?)
curl -i 'https://api.example.com/items' # 상태 코드 보기
JSON 파싱 에러 디버깅
응답이 JSON이라고 생각하는데 파싱이 실패하는 경우:
# 응답을 파일로 저장
curl -s 'https://api.example.com/items' > response.txt
# 첫 몇 바이트만 보기 (인코딩 BOM 확인)
hexdump -C response.txt | head
# 유효한 JSON인지 검증
jq . response.txt # 유효하지 않으면 에러
# 또는 Python으로
python3 -m json.tool response.txt
흔한 문제:
// ✗ 문제: BOM(Byte Order Mark) 있음
// 응답이 UTF-8 BOM으로 시작하면 JSON 파서가 실패할 수 있음
EF BB BF ... {"key": "value"}
// 해결: BOM 제거
iconv -f UTF-8 -t UTF-8 -c response.txt > response_clean.txt
응답 필드 구조 확인
JSON은 파싱되는데 필드가 다른 경우:
# 예상한 구조
{
"items": [{"id": 1, "name": "Item 1"}]
}
# 실제 구조 (필드명 다름)
{
"data": [{"itemId": 1, "title": "Item 1"}]
}
# 확인 방법
curl -s 'https://api.example.com/items' | jq 'keys'
# 최상위 키 확인
curl -s 'https://api.example.com/items' | jq '.items | length'
# items 배열의 길이
curl -s 'https://api.example.com/items' | jq '.items[0] | keys'
# 첫 번째 item의 필드명
인코딩 문제
응답이 JSON이지만 일부 문자가 깨진 경우:
# 응답의 실제 인코딩 확인
file response.json
# Content-Type 헤더의 charset 확인
curl -i 'https://api.example.com/items' | grep -i charset
# 인코딩 변환
iconv -f cp1252 -t utf-8 response.json > response_utf8.json
# 또는 curl에서 직접 지정
curl -H 'Accept-Charset: utf-8' 'https://api.example.com/items'
응답 크기나 시간 초과
# 응답 크기 확인
curl -s -w "Size: %{size_download} bytes\n" 'https://api.example.com/items' > /dev/null
# 응답 시간 확인
curl -s -w "Time: %{time_total}s\n" 'https://api.example.com/items' > /dev/null
# 너무 크면 페이지네이션 사용
curl 'https://api.example.com/items?page=1&limit=10'
# 너무 느리면 타임아웃
curl --max-time 10 'https://api.example.com/items'
API 문서와 실제 응답 비교
# API 문서에서 예상한 응답
# {
# "id": "number",
# "name": "string",
# "created_at": "ISO 8601 date"
# }
# 실제 응답
curl -s 'https://api.example.com/items/1' | jq .
# 필드 타입 확인
curl -s 'https://api.example.com/items/1' | jq '.id | type'
# 문서에서는 number인데 실제로는 string?
API 버전 확인
# API 버전을 헤더로 명시
curl -H 'Accept: application/json; version=2' 'https://api.example.com/items'
# 또는 URL 경로에 버전
curl 'https://api.example.com/v2/items'
# 버전에 따라 응답이 다를 수 있음
JSON 응답 문제는 대부분 상태 코드, 인코딩, 필드명 변경 중 하나다. 응답을 있는 그대로 보고, API 문서와 비교하면 빠르게 원인을 찾을 수 있다.