data.go.kr API 레퍼런스¶
이 문서는 KPubData의 DataGoAdapter에 영향을 주는 data.go.kr
(공공데이터포털)의 공개 API 관례를 정리합니다.
1. 범위¶
datago 어댑터는 apis.data.go.kr와 api.odcloud.kr 계열을 모두 지원합니다.
provider_family: "odcloud" 메타데이터로 프로토콜을 분기합니다.
(social_enterprise 데이터셋이 ODcloud 프로토콜을 사용합니다.)
2. 인증¶
모든 요청에는 serviceKey 쿼리 파라미터가 필요합니다.
- 키는 특정 데이터셋에 대해 활용신청한 뒤 https://www.data.go.kr에서 사용자별로 발급됩니다.
- 일부 레거시 API는 파라미터를
ServiceKey(대문자 S)로 표기합니다. 어댑터는 기본적으로serviceKey를 사용하되, 데이터셋 메타데이터로 파라미터 이름을 재정의할 수 있어야 합니다. - 포털은 인코딩된 키와 디코딩된 키를 모두 제공합니다. 어댑터는 디코딩된 형태를 받아들이고, HTTP 라이브러리가 퍼센트 인코딩을 투명하게 처리하도록 해야 합니다 — 중복 인코딩하지 마세요.
3. 기본 URL¶
단일 통합 엔드포인트는 없습니다. apis.data.go.kr에 등록된 각
데이터셋은 자체 base URL을 가집니다:
| 패턴 | 예시 |
|---|---|
http(s)://apis.data.go.kr/{org}/{service} |
http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0 |
어댑터는 base URL을 DatasetRef.endpoint 필드에서 받습니다.
오퍼레이션 결정(예: /getVilageFcst)은 데이터셋 메타데이터에서 오며
어댑터에 하드코딩하면 안 됩니다.
4. 응답 형식¶
4.1 형식 선택¶
대부분의 API는 다음 방식으로 JSON과 XML을 모두 지원합니다:
resultType=json(일부 API는type=json)- 보통 이 파라미터를 생략하면 기본값은 XML입니다.
KPubData는 지원되는 경우 JSON을 우선 사용합니다. 데이터셋이 XML만
지원하면 전송 계층이 xmltodict로 이를 파싱하며, 결과 dict는
JSON 형태를 따릅니다.
4.2 표준 envelope¶
{
"response": {
"header": {
"resultCode": "00",
"resultMsg": "NORMAL SERVICE."
},
"body": {
"items": {
"item": [ ... ]
},
"numOfRows": 10,
"pageNo": 1,
"totalCount": 150
}
}
}
주요 경로:
| 필드 | 경로 | 설명 |
|---|---|---|
| 성공 여부 | response.header.resultCode == "00" |
"00"이면 정상 |
| 오류 메시지 | response.header.resultMsg |
사람이 읽을 수 있는 상태 메시지 |
| 레코드 | response.body.items.item |
정규화는 §4.3 참고 |
| 전체 건수 | response.body.totalCount |
참고용 — §5 참고 |
| 페이지 번호 | response.body.pageNo |
현재 페이지 (1부터 시작) |
| 페이지 크기 | response.body.numOfRows |
페이지당 행 수 |
4.3 item 정규화 특이사항¶
items.item 필드는 항상 리스트가 아닙니다:
| 조건 | items.item 값 |
|---|---|
| 결과가 여러 개 | list[dict] |
| 결과가 한 개 | dict (리스트로 감싸지 않음) |
| 결과가 0개 | null, 누락, 또는 items 자체가 없음 |
어댑터는 레코드를 반환하기 전에 모든 경우를 list[dict]로
정규화해야 합니다.
4.4 문자열로 전달되는 숫자값¶
pageNo, numOfRows, totalCount 같은 숫자 필드는
문자열로 올 수 있습니다. 어댑터는 방어적으로 이를 int로
변환해야 합니다.
4.5 XML 변형¶
XML도 동일한 논리 구조를 사용합니다. items > item은 반복되는
<item> 요소가 됩니다. 변환에는 xmltodict를 사용하세요. 결과 dict는
JSON 형태를 따르지만, 단일 항목을 리스트 대신 dict로 반환할 가능성이
더 높습니다.
5. 페이지네이션¶
두 개의 파라미터를 사용하는 페이지 기반 방식입니다:
| 파라미터 | 기본값 | 설명 |
|---|---|---|
pageNo |
1 |
1부터 시작하는 페이지 번호 |
numOfRows |
10 |
페이지당 행 수 (최대값은 API마다 다름) |
어댑터는 기본값으로 충분해 보여도 항상 페이지 파라미터를 명시적으로 전송해야 동작이 결정적으로 유지됩니다.
중단 조건 (방어적)¶
어댑터는 다음 조건 중 하나라도 만족하면 페이지 순회를 멈춰야 합니다:
- 정규화 후 반환된 item 리스트가 비어 있음
- 반환된 item 수가 요청한
numOfRows보다 작음 (짧은 페이지 = 마지막 페이지) pageNo * numOfRows >= totalCount(참고용 상한)
totalCount는 참고용 상한으로만 사용하고, 유일한 종료 조건으로
쓰면 안 됩니다 — 일부 API는 오래되었거나 잘못된 건수를 반환합니다.
잘못된 envelope 처리¶
응답에 response.header.resultCode가 아예 없으면
ProviderResponseError를 발생시킵니다. JSON/XML 파싱이 실패하면
ParseError를 발생시킵니다.
6. 오류 코드¶
오류는 HTTP 상태 코드가 아니라 응답 envelope 안에 들어옵니다 (대부분 오류여도 HTTP 200을 반환합니다).
resultCode |
resultMsg |
의미 |
|---|---|---|
"00" |
NORMAL SERVICE | 성공 |
"01" |
APPLICATION ERROR | 서버 측 애플리케이션 오류 |
"02" |
DB ERROR | 제공기관 측 데이터베이스 오류 |
"10" |
INVALID REQUEST PARAMETER | 잘못된 쿼리 파라미터 |
"12" |
NO OPEN API SERVICE ERROR | 서비스 ID를 찾을 수 없거나 비공개 상태 |
"20" |
SERVICE ACCESS DENIED ERROR | 이 API에 대해 키 권한이 없음 |
"22" |
일일 트래픽 초과 | 일일 트래픽 할당량 초과 |
"30" |
KEY IS NOT REGISTERED | 유효하지 않거나 폐기된 키 |
"31" |
DEADLINE HAS EXPIRED | 키 유효기간 만료 |
"32" |
UNREGISTERED IP | 호출 IP가 화이트리스트에 없음 |
KPubData 예외로의 매핑¶
| 코드 | KPubData 예외 | 비고 |
|---|---|---|
"30", "31", "20", "32" |
AuthError |
세부 경우 구분은 provider_code 사용 |
"22" |
RateLimitError |
retryable=False 설정 — 일일 할당량 소진으로, 일시적 스로틀링이 아님 |
"10" |
InvalidRequestError |
|
"12" |
DatasetNotFoundError |
서비스/데이터셋을 찾지 못함 |
"01", "02" |
ServiceUnavailableError |
상위 제공기관 장애, retryable=True |
| 잘못된 envelope | ProviderResponseError |
resultCode 누락 또는 계약 위반 |
| 잘못된 JSON/XML | ParseError |
전송 계층 디코드 실패 |
7. 호출 제한¶
- 서비스 키별 일일 호출 할당량이 있습니다 (오류 코드
"22"). - 할당량은 데이터셋 및 계정별로 다르며, 각 데이터셋의 포털 페이지에 표시됩니다. 하나의 공통 제한값은 없습니다.
Retry-After헤더는 제공되지 않습니다. 코드"22"가 오면 어댑터는retryable=False가 설정된RateLimitError를 발생시킵니다 — 일일 할당량 소진은 같은 날 안에 재시도해도 해결되지 않습니다.
8. 일반적인 쿼리 파라미터¶
| 파라미터 | 필수 여부 | 설명 |
|---|---|---|
serviceKey |
API 키 | |
pageNo |
(항상 전송) | 페이지 번호 (기본값 1) |
numOfRows |
(항상 전송) | 페이지 크기 (기본값 10) |
resultType |
json 또는 xml (기본값 XML) |
|
| dataset-specific | varies | 검색 필터, 날짜 범위 등 |
9. 어댑터 설계에 주는 시사점¶
- 카탈로그 엔드포인트 없음 — 데이터셋 탐색은 외부
(포털 웹사이트)에서 이뤄집니다.
list_datasets는 선별된 정적 목록을 반환하거나 로컬 카탈로그 파일을 읽습니다. - 데이터셋별 base URL —
DatasetRef.endpoint에 저장합니다. 오퍼레이션 결정은 데이터셋 메타데이터에서 오며, 경로를 하드코딩해 구성하지 않습니다. - JSON 우선 — 데이터셋이 지원하면
resultType=json을 전송합니다. JSON을 지원하지 않으면 전송 계층이 XML을 파싱하도록 둡니다. - 본문 내부 오류 —
body를 처리하기 전에resultCode를 확인합니다. HTTP 200이라고 성공을 의미하지는 않습니다. - 방어적 페이지 순회 —
query_records는 §5의 중단 조건과 함께pageNo/numOfRows를 사용해 자동 페이지네이션해야 합니다. call_raw— 임의의 파라미터를 그대로 전달하고 최소한만 가공한 제공기관 응답 dict를 반환합니다. 평탄화하거나 canonicalize하지 마세요 — raw 비상구를 보존하기 위함입니다.- 미지원 capability — 데이터셋 메타데이터가 명시적으로 증명하지 않는 한
get_schema는 기본적으로 지원하지 않습니다. 지원된다고 표시하지 마세요. - item 정규화 — §4.3 설명대로 항상
items.item을list[dict]로 강제 변환합니다.
10. 참고 구현체¶
- data-go-mcp-servers — NPS, NTS, PPS data.go.kr API용 MCP 서버 래퍼입니다. 인증, 페이지네이션, 오류 처리 패턴을 보여줍니다.