통합 데이터 API 시작하기: 기능 카탈로그에서 사용 가능한 첫 결과까지
platform, action, params로 여러 플랫폼의 데이터에 접근합니다. 기능 카탈로그를 읽고, 최소한의 요청을 완료하고, 비동기 작업과 부분 결과, 과금을 처리하며, 추적 가능한 데이터 기록을 만듭니다.
플랫폼 하나에 대한 요청 코드를 작성하는 일은 대개 간단합니다. 진짜 문제는 두 번째 플랫폼이 들어오면서 시작됩니다. 파라미터 이름이 바뀌고, 사용자와 콘텐츠 식별자가 다르며, 어떤 엔드포인트는 데이터를 즉시 반환하고 어떤 엔드포인트는 작업부터 생성합니다. cron 작업이 돌기 시작하면 재시도 로직, 중복 제거, 과금 대사가 각자 별도의 코드 경로로 불어납니다.
통합 데이터 API는 이런 중복된 연동 부담을 줄여 줍니다. EveryInfra의 EveryData에서는 동일한 Bearer 인증을 사용하며, platform으로 플랫폼을, action으로 기능을 선택하고, params로 기능별 파라미터를 전달합니다. 통합되는 것은 호출 진입점과 일반적인 처리 흐름이며, 모든 플랫폼 데이터를 하나의 비즈니스 객체로 억지로 균일화하는 것은 아닙니다.
이 튜토리얼에서는 Xiaohongshu 노트 검색으로 최소 요청을 보여 준 뒤, 다른 기능으로 확장하는 방법을 설명합니다. 목표는 HTTP 요청 한 번을 실행하는 데 그치지 않고, 프로그램이 어떤 데이터를 가져왔는지, 어떤 결과가 아직 대기 중인지, 다음 실행에서 빈틈을 어떻게 메울지 알게 하는 것입니다. 예시는 2026-09-04 기준으로 검증한 공개 카탈로그와 구현을 바탕으로 합니다. 프로덕션 POST 스니펫은 허용된 시나리오를 위한 호출 템플릿이며, 새로 측정한 실제 성공 사례가 아닙니다.
먼저 판단하기: 데이터 조회가 필요한가, 검색과 생성이 필요한가
특정 노트, 상품, 장소 등 대상이 어느 플랫폼에 속하는지 이미 알고 있고 그 대상의 구조화된 필드를 읽고 싶다면 데이터 API에서 시작하는 것이 맞습니다. 자료가 온라인 어디에 있는지부터 찾는 중이라면 먼저 웹 검색을 실행하세요. 이미 자료를 갖고 있고 요약, 분류, 보고서 작성이 필요하다면 모델 처리를 사용하세요.
댓글 분석을 예로 들면, 수집은 댓글의 내용과 출처를 알려 주고, 모델은 해당 텍스트에 어떤 문제가 나타나는지 분석합니다. 모델은 수집 실패로 누락된 레코드를 지어낼 수 없으며, 반환되지 않은 댓글 수를 0으로 해석해서도 안 됩니다. 두 단계를 분리하면 결론에 이의가 제기됐을 때 전체 호출 체인을 다시 추측하지 않고 원래 근거로 돌아갈 수 있습니다.
1단계: 플랫폼 이름으로 엔드포인트를 추측하지 말고 카탈로그에서 기능 확인하기
기능 카탈로그는 API 키 없이 읽을 수 있습니다. 먼저 간략 버전으로 사용 가능한 플랫폼과 액션을 파악한 뒤, 선택한 플랫폼의 전체 파라미터 및 필드 레퍼런스를 가져오세요. 간략 보기는 탐색용이며 파라미터와 필드 설명이 빠져 있으므로, 간략 카탈로그를 완전한 요청 검증기로 취급하지 마세요.
curl -fsS --max-time 30 \
'https://api.everyinfra.com/api/v1/social/catalog?compact=1' \
| jq '.capabilities[] | {platform, action, required_params, mode, available}'예를 들어 연구 키워드와 관련된 Xiaohongshu 노트를 찾으려면 먼저 search를 확인하세요. 이미 노트 링크가 있고 상세 정보나 댓글이 필요하다면 note나 comments를 선택하세요. 이름이 비슷하다고 서로 바꿔 쓸 수 있는 것은 아닙니다. 검색 키워드를 상세 요청 URL로 그대로 넘길 수는 없습니다.
curl -fsS --max-time 30 \
'https://api.everyinfra.com/api/v1/social/catalog?platform=xiaohongshu' \
| jq -e '.capabilities[] | select(.action == "search") | {
platform, action, required_params, optional_params,
param_meanings, mode, returns_list,
default_limit, max_limit, response_fields, available
}'이번 카탈로그 검증에서 xiaohongshu.search의 필수 파라미터는 keyword이며, mode는 sync, returns_list는 true로 설정되어 있습니다. 기본 개수는 20, 상한은 50입니다. 이 두 값은 이 기능의 수량 설정을 설명할 뿐, 요청마다 전달을 보장하거나 모든 플랫폼에 공통으로 적용되는 한도가 아닙니다. 카탈로그에는 sort와 content_type도 있습니다. 필터링할 때는 param_meanings의 허용 값을 사용하고, 다른 플랫폼의 열거값을 복사하지 마세요.
- required_params: 반드시 필요한 입력입니다. 먼저 이러한 필수 입력을 채운 뒤 필터를 하나씩 추가하세요.
- param_meanings: 파라미터 정의와 선언된 허용 값입니다. 목록에 없는 필드에 임의의 열거값을 만들지 마세요.
- mode와 returns_list: 작업 폴링이 필요한지, 최종 업무 데이터가 목록인지 단일 객체인지를 결정합니다.
- response_fields: 필드 매핑을 계획하는 데 쓰입니다. 실제 응답이 아니며, 모든 필드에 값이 있다고 보장하지도 않습니다.
- available: 카탈로그 수준의 사용 가능 여부 플래그입니다. 특정 대상 URL이 지금 데이터를 반환한다는 것을 미리 증명하지는 않습니다.
목록 기능은 공통 limit 파라미터도 지원하며, 이 파라미터는 optional_params 안에 다시 표시되지 않을 수 있습니다. 이 구분은 요청 검증 코드로 확인됩니다. 연동할 때는 목록 선언, 기본값과 한도, 전체 설명을 함께 검토하세요. optional_params와 문자열을 대조하는 것만으로 유효한 limit 파라미터를 제거하지 마세요.
2단계: 확인하기 쉬울 만큼 작은 요청 보내기
적절한 기능 권한을 가진 API 키를 준비하고, 서버 환경 변수로 전달하세요. 브라우저 프런트엔드 코드, 스크린샷, 공개적으로 내려받을 수 있는 예제 파일에는 넣지 마세요. 아래 예시는 자체 비밀 관리 수단으로 EVERYINFRA_API_KEY가 설정되어 있다고 가정합니다. 명령은 자동 재시도 없이 요청 하나만 보냅니다.
: "${EVERYINFRA_API_KEY:?set the server-side API Key first}"
curl --silent --show-error --include --max-time 180 \
'https://api.everyinfra.com/api/v1/social' \
-H "Authorization: Bearer ${EVERYINFRA_API_KEY}" \
-H 'Content-Type: application/json' \
--data '{
"platform": "xiaohongshu",
"action": "search",
"params": {
"keyword": "AI tools",
"limit": 5
}
}'여기서 5는 목표로 하는 작은 샘플 크기이며 전달 보장이 아닙니다. 180초는 이 예시의 클라이언트 대기 타임아웃이며 서비스 SLA가 아닙니다. 수량을 늘리기 전에 작은 결과 집합으로 필드, 타임스탬프 형식, 소스 링크를 확인하세요. 초기 디버깅 중에는 HTTP 상태 줄과 응답 본문을 보존하세요. 그래야 4xx나 5xx를 만났을 때 일반적인 curl 실패 메시지 대신 구체적인 오류를 읽을 수 있습니다.
최상위 필드 세 개는 구분해야 합니다. platform과 action은 기능을 선택하고, 모든 업무 조건은 params에 넣습니다. keyword를 최상위로 올리지 말고, 지원하지 않는 액션에 page, cursor, sort를 붙이지 마세요. 카탈로그에 없는 파라미터는 대부분의 API가 그렇게 설계되어 있다는 이유만으로 지원된다고 가정할 수 없습니다.
OpenAPI는 사람과 프로그램이 요청 본문, 파라미터, 응답을 기술하도록 돕지만, 플랫폼 간에 동일한 비즈니스 모델을 강제하지는 않습니다. 타입을 생성하거나 호출 코드를 만들 때는 사양으로 인터페이스 기술 형식을 이해한 뒤, 정확한 필드는 서비스 자체의 카탈로그와 응답 형식을 기준으로 판단하세요.
3단계: 동기 결과의 바깥 구조와 안쪽 구조 이해하기
선택한 xiaohongshu.search의 경우, 구현상 목록은 results 안에 들어가고 그 바깥에 id, platform, action, count, billing, quota 등의 메타데이터가 함께 위치합니다. 바깥의 id는 요청 추적 식별자이고, results 안 각 레코드의 id는 콘텐츠 식별자입니다. 두 값을 혼동하지 마세요. 전자는 디버깅과 정산 대조에, 후자는 레코드 중복 제거에 사용합니다.
results를 모든 클라이언트의 유일한 조회 경로로 간주하지 마세요. 다른 액션은 이름이 다른 비즈니스 객체를 반환할 수 있습니다. returns_list는 객체 형태를, 필드 사전은 내부 필드를 설명하지만, 둘 다 선택한 기능의 바깥 구조를 직접 확인하는 일을 대신하지는 못합니다. 새 기능을 추가할 때는 모든 응답에서 첫 번째 배열을 재귀적으로 찾지 말고 명확한 결과 어댑터 설정을 두어야 합니다.
curl -fsS --max-time 30 \
'https://api.everyinfra.com/api/v1/social/fields?platform=xiaohongshu&action=search' \
| jq '{fields, undocumented}'필드 처리에서 결론을 자주 바꾸는 세부 사항이 두 가지 있습니다. 첫째, 참여 지표가 null이면 공개되지 않았거나 얻을 수 없는 데이터라는 뜻이므로, 평균을 계산하기 전에 자동으로 0을 채워 넣으면 안 됩니다. 둘째, posted_at에 대한 공개 문서는 플랫폼의 원본 타임스탬프 문자열을 그대로 유지하는 것을 허용합니다. 모든 값이 하나의 ISO 형식으로 바로 파싱된다고 가정하지 마세요. 파싱한 타임스탬프는 별도로 저장하고, 파싱에 실패한 날짜를 오늘 날짜로 채우는 대신 실패 상태 플래그를 남기세요.
응답에 partial 또는 missed 플래그가 포함되어 있으면 전달되지 않은 대상을 별도로 추적해야 합니다. HTTP 200이 배치 안 모든 대상에서 데이터가 나왔다는 보장은 아닙니다. 빈 배열에서 내릴 수 있는 유일한 타당한 결론은 이번에 반환된 레코드가 없다는 것이며, 원본 플랫폼에 데이터가 없다는 뜻은 아닙니다. 요청이 올바른 대상을 다루었는지, 범위 제한을 지켰는지는 별개의 문제입니다.
4단계: 비동기 기능은 job_id에서 멈추지 말고 최종 상태까지 기다리기
mode가 async인 기능으로 전환하면 제출 응답이 HTTP 202와 함께 status, job_id, poll_url을 반환할 수 있습니다. 작업 조회를 시작하기 전에 이 필드들을 저장하세요. HTTP 사양에서 202는 요청이 접수되었지만 처리가 완료되지 않았음을 뜻합니다. 이를 근거로 ‘보고서 생성 완료’ 같은 비즈니스 알림을 보내면 안 됩니다.
: "${EVERYINFRA_API_KEY:?set the API Key used for this task first: API Key}"
: "${EVERYINFRA_JOB_ID:?paste the job_id from the actual submit response}"
curl --silent --show-error --include --max-time 30 \
"https://api.everyinfra.com/api/v1/jobs/${EVERYINFRA_JOB_ID}" \
-H "Authorization: Bearer ${EVERYINFRA_API_KEY}"현재 조회 구현은 제출할 때 사용한 API 키를 기준으로 작업을 찾습니다. 같은 API 키로 조회하고, 같은 계정의 다른 API 키로 바꿔도 작업을 찾을 수 있다고 가정하지 마세요. 작업을 찾지 못했다고 해서 같은 작업을 바로 다시 만들면 안 됩니다. 사용한 API 도메인, job_id, API 키를 확인하고, 필요하면 저장해 둔 요청 정보를 참고하세요.
- running 또는 finalizing: 처리 중 상태입니다. 작업을 유지하고 미리 정한 범위 내에서 간격을 두고 계속 폴링합니다.
- succeeded: 작업이 성공 종료 상태에 도달했습니다. 기능의 데이터 객체를 파싱하고 비즈니스 요구 사항을 충족하는지 확인합니다.
- failed: 실패 종료 상태에 도달했습니다. error를 읽고 작업 레코드를 보존하며, 빈 데이터 성공으로 처리하지 않습니다.
- 조회 시간 초과 또는 알 수 없는 상태: 미확인으로만 표시합니다. 후속 복구 워크플로에 적용할 총 대기 시간 한도를 설정하되, 상태를 성공이나 실패로 변경하지 않습니다.
폴러는 촘촘한 루프를 방지하기 위해 최대 대기 시간을 적용하고 폴링 간격을 점차 늘려야 합니다. 프로그램을 재시작하면 작업을 다시 제출하지 말고 저장해 둔 job_id를 사용해 폴링을 재개하세요. 제출 시의 billing은 별도로 저장하세요. 현재 결과 조회 응답은 billing 블록 전체를 다시 반환하지 않으므로, 조회 결과에 billing이 없다고 해서 과금이 0이라는 뜻은 아닙니다.
Microsoft의 Asynchronous Request-Reply 패턴도 접수, 상태 확인, 최종 결과를 분리하고 폴링 힌트를 다룹니다. 클라이언트 워크플로 설계에 참고할 만하지만, Location이나 Retry-After 같은 헤더를 EveryInfra가 여기서 반환한다는 보장은 없으며, 실제 조회는 현재 응답에 제공된 진입점을 계속 사용합니다.
5단계: 근본 원인별로 오류를 처리하고, 특히 POST를 무작정 재시도하지 않기
비즈니스 오류는 HTTP 상태와 error.code를 함께 확인해야 합니다. 현재 데이터 진입점은 인증을 먼저 확인한 뒤 기능, 권한, 파라미터를 확인하고, 그다음 할당량과 실행 흐름으로 들어갑니다. 유효한 API 키가 없을 때 401이 나왔다고 해서 비즈니스 파라미터가 검증을 통과했다는 뜻은 아닙니다.
- 401: API 키가 존재하는지, 유효한지, Bearer 헤더가 올바른지 확인합니다. 키워드를 바꿔서 인증 실패를 해결하려 하지 마십시오.
- 403: API 키에 대상 제품과 기능을 사용할 권한이 있는지 확인합니다. 권한 문제는 권한이 있는 담당자가 처리해야 하며, 계정을 자동으로 전환해서는 안 됩니다.
- 400 unknown_capability: platform과 action이 맞는지 확인합니다. 카탈로그를 다시 읽고 서비스가 제시한 후보 이름을 검토합니다.
- 422: 필수 항목, 알 수 없는 파라미터, 허용되지 않는 enum 값을 확인합니다. 오류 메시지가 가리키는 문제를 하나씩 해결한 뒤 새 요청을 보냅니다.
- 402: 할당량이 부족합니다. 계정 크레딧 문제를 해결해야 하며, 같은 요청을 반복해도 결과는 달라지지 않습니다.
- 429, 일시적인 서비스 오류, 네트워크 끊김: 백오프한 뒤 원래 요청의 상태를 확인합니다. 안전하다고 확인된 경우에만 횟수를 제한해 재시도합니다.
가장 놓치기 쉬운 부분은 클라이언트에서 시간 초과가 났지만 서버는 이미 요청을 접수했을 수 있는 경우입니다. 데이터 가져오기는 비즈니스 관점에서는 읽기 전용처럼 보이지만 POST로 실행되므로 작업이 생성되고 과금될 수 있습니다. Correlation ID는 여러 번의 시도를 서로 연결하는 데 도움이 되지만 서버 측 멱등성을 자동으로 보장하지는 않습니다. API가 명시적으로 지원하지 않는데 Idempotency-Key 헤더를 넣고 중복 요청이 한 번만 실행되리라 가정하지 마십시오.
RFC 9110은 멱등이 아닌 요청의 자동 재시도를 엄격하게 제한합니다. 이처럼 결과를 알 수 없는 경우에는 먼저 기존 작업을 조회하거나 요청 기록을 확인하십시오. 정보가 부족할 때는 배치 전체를 자동으로 다시 보내는 것보다 알 수 없는 상태로 남겨 두는 편이 안전합니다.
6단계: 데이터, 수집 상태, 과금 정보를 따로 저장하기
통합 진입점의 가장 큰 가치는 공통 레코드와 플랫폼별 필드 매핑 사이의 역할 분담을 분명히 하는 데 있습니다. 최소한 비즈니스 작업, API 시도, 플랫폼 객체의 세 가지 레코드를 관리하십시오. 이렇게 하면 작업 하나가 몇 번 시도되었는지 추적할 수 있고, 여러 번 수집하면서 같은 콘텐츠를 업데이트해도 중복 객체가 새로 생기지 않습니다.
- 작업 레코드: 자체 task_id, 대상 범위, 기대 필드, 완료 기준. 여기서 완료는 HTTP 성공만으로 판단하지 않고 비즈니스 기준으로 정의합니다.
- 요청 레코드: 플랫폼, 액션, 민감하지 않은 파라미터 요약, 시작/종료 시각, API 요청 ID, job_ids, 상태, 과금 정보. 실패한 시도도 보존합니다.
- 객체 레코드: 플랫폼, 객체 유형, 객체 ID, 출처 링크, 실제로 확보한 필드, observed_at. 서로 다른 플랫폼에서 ID가 우연히 같은 객체를 병합하지 마십시오.
이는 애플리케이션 데이터 모델에 대한 권장 사항이며, EveryInfra가 반환하는 추가 필드가 아닙니다. observed_at은 수집기가 관측 시각을 나타내기 위해 기록해야 하고, posted_at은 원본 콘텐츠의 게시 시각을 나타냅니다. 둘을 함께 쓰면 콘텐츠가 언제 게시되었는지와 우리가 언제 알게 되었는지를 구분할 수 있어, 지연된 데이터와 반복 관측을 분석할 수 있습니다.
플랫폼 간 비교를 할 때는 비즈니스에 필요하고 의미가 비교 가능한 필드만 매핑하십시오. 좋아요, 북마크, 상품 평점, 댓글 수는 서로 다른 지표이며, 모두 score로 이름을 바꾼다고 같은 척도가 되지는 않습니다. 의미를 해석하지 못한 필드는 단위와 의미를 추측하지 말고 결측 상태를 그대로 유지하거나 데이터 사전을 확인하십시오.
과금은 결과 항목 수로 역산할 수 없습니다. 다중 대상 기능은 대상별로 과금하므로 HTTP 요청이 과금 단위가 아니며, 샘플 수를 적게 제한했다고 반환 건수에 비례해 할인되는 것도 아닙니다. 현재 동기 구현에는 빈 결과 및 부분 전달 시 과금·환불을 처리하는 분기가 있지만, 감사를 위해 클라이언트는 실제 과금 정보와 원장 기록을 저장해야 합니다. 200이나 빈 배열만 보고 정산이 끝났다고 판단하지 마십시오.
요청을 로깅할 때는 OWASP의 상호작용 ID 설계를 참고하십시오. 하나의 비즈니스 의도에 속한 이벤트를 서로 연결하되, 액세스 토큰 같은 민감한 항목은 제외합니다. 디버깅 가능한 정보를 남기는 것이 요청 헤더와 원문을 그대로 로그에 쏟아 넣는 것을 뜻하지는 않습니다.
두 번째 플랫폼으로 확장할 때 어떤 코드를 재사용할 수 있을까
인증 주입, 시간 초과 설정, 오류 로깅, 작업 조회 스케줄러, 보안 로깅은 재사용할 수 있습니다. 반면 파라미터 이름과 의미, 결과 객체 경로, 필드 매핑, 페이지네이션 규칙, 완료 기준은 기능별로 따로 두어야 합니다. 두 부분을 분리해 두면 나중에 기능을 추가할 때 클라이언트 전체를 복사해 붙여 넣는 일이 생기지 않습니다.
카탈로그는 관측 시점을 기준으로 캐시해 두고, 새 기능을 연동하거나 업데이트를 배포하기 전에 다시 확인하는 것이 좋습니다. 캐시를 무기한 유지하지 말되, 레코드마다 카탈로그 전체를 내려받지도 마십시오. 비즈니스가 변경을 얼마나 감당할 수 있는지에 맞춰 갱신 주기를 정하고, unknown_capability나 파라미터 불일치가 발생했을 때만 해당 부분을 다시 확인하십시오.
페이지네이션과 증분 수집은 특히 신중해야 합니다. 특정 액션이 페이지네이션 파라미터와 종료 신호를 명시적으로 제공할 때만 진행하고, 그렇지 않으면 클라이언트에서 커서를 임의로 만들지 마십시오. 주기적(cron) 조회는 여러 번의 관측을 만들 뿐, 완전한 이력이나 모든 신규 콘텐츠와 자동으로 같아지지 않습니다. 첫 버전의 보고서에는 증명할 수 없는 전체 커버리지를 주장하지 말고 확인한 대상과 시간 범위를 명시해야 합니다.
이 방식을 그대로 적용하기에 적합하지 않은 작업
사용자를 대신해 게시하거나, 판매자 프로필을 관리하거나, 계정 권한 부여를 처리하거나, 플랫폼 데이터를 수정해야 한다면 공개 데이터 엔드포인트를 계정 관리 인터페이스로 쓰지 말고 플랫폼의 공식 API와 권한 부여 절차를 확인하십시오. 비공개 콘텐츠, 제한된 데이터, 허용되지 않은 용도에 대해서는 통합 엔드포인트가 접근 권한을 넓혀 주지 않습니다.
데이터가 공개되어 있더라도 저장, 분석, 재표시는 해당 플랫폼의 규칙과 비즈니스 목적에 비추어 평가해야 합니다. 조사 범위는 필요한 대상과 필드로 제한하고, 보존 기간을 관리하며, 작성자 프로필, 접근 파라미터가 포함된 링크, 원문을 공개 로그에 그대로 출력하지 마십시오. 기술적으로 요청할 수 있는지와 비즈니스상 사용이 허용되는지는 별개의 확인 사항입니다.
설명할 수 있는 결과 하나에서 시작하기
초기 연동을 마쳤다면 스스로 네 가지를 질문해 보십시오. 호출한 기능이 정확히 무엇인지 분명하게 말할 수 있는가? 모든 데이터 항목을 출처까지 추적할 수 있는가? 성공, 처리 중, 부분 전달, 알 수 없는 결과를 구분할 수 있는가? 요청이 실패하거나 중복되었을 때 그에 따른 레코드와 과금을 설명할 수 있는가?
네 질문에 모두 답할 수 있게 되면 플랫폼을 늘리고, 동시 요청 수를 높이고, 모델 분석을 연동하십시오. 통합 데이터 API의 가치는 모든 차이를 없애는 데 있지 않고, 플랫폼 간 차이가 실제로 존재하는 곳에서만 맞춤 로직을 작성하게 해 주는 데 있습니다. 아래 문서에서 기능을 하나 고르고, 소량 샘플로 확인한 뒤, 결과를 올바르게 저장하고 다음 단계를 시작하십시오.
참고 LF-01