개인정보처리방침이 2026년 9월 20일부터 변경됩니다. 온라인 맞춤형 광고 도입에 따라 행태정보 수집·이용 및 국외 이전 관련 조항이 추가됩니다.
개정 내용 보기

direct 모드와 proxy 모드

CORS 때문에 브라우저에서 API 호출이 막히는 이유와, SDK가 두 모드를 어떻게 자동 선택하는지.

SDK는 두 가지 방식으로 데이터를 가져옵니다. direct 모드는 원본 API를 직접 호출하고, proxy 모드는 ApiCook 서버를 거칩니다. 대부분은 신경 쓸 필요가 없습니다 — SDK가 실행 환경을 보고 알아서 고릅니다.

왜 두 가지가 필요한가

브라우저는 다른 도메인으로 나가는 요청을 기본적으로 막습니다. 서버가 Access-Control-Allow-Origin 헤더로 허락해야 통과하는데, 공공데이터 API 상당수는 이 헤더를 보내지 않습니다. 그래서 브라우저에서 직접 호출하면 요청 자체는 나갔는데 응답을 읽지 못하고 CORS 오류가 납니다.

서버(Node 등)에는 이 제약이 없습니다. 같은 코드가 환경에 따라 되기도 하고 안 되기도 하는 이유가 여기 있습니다.

자동 선택 규칙

this.mode = options.mode
    ?? (globalThis.window !== undefined && globalThis.document !== undefined
        ? 'proxy' : 'direct');

windowdocument둘 다 있으면 브라우저로 보고 proxy, 그 외에는 direct입니다.

실행 환경 자동 선택
브라우저 proxy
Node.js direct
Deno · Bun direct
Vercel Edge · Cloudflare Workers direct
Next.js 서버 컴포넌트 direct
Next.js 클라이언트 컴포넌트 proxy

명시하면 자동 감지를 덮어씁니다.

const cook = new ApiCook('proj_xxx', { apiKey: 'apk_xxx', mode: 'direct' });

모드는 인스턴스를 만들 때 정해지고 나중에 바꿀 수 없습니다. 두 모드를 섞어 써야 한다면 인스턴스를 두 개 만드세요.

각 모드가 하는 일

direct — 설정 JSON을 먼저 받고, 그 안의 baseUrl·path·파라미터 정의로 URL을 만들어 원본 API를 직접 호출합니다. 응답은 SDK 안에서 가공 규칙을 적용해 돌려줍니다.

SDK → api.apicook.dev/api/v1/sdk/{projectId}.json   (설정, 60초 캐시)
SDK → apis.data.go.kr/...?serviceKey=...            (원본 API 직접)

proxy — 설정을 받지 않고 ApiCook 서버로 바로 요청합니다. 서버가 원본을 호출하고 가공까지 마친 결과를 돌려줍니다.

SDK → api.apicook.dev/api/v1/proxy/{projectId}/{slug}   (POST)
                          ↓
              서버 → 원본 API → 가공 → 응답

모드별 차이

direct proxy
CORS 제약 원본 API가 허용해야 함 우회됨
응답 캐시 없음 서버 Redis, 기본 60초
cook.endpoints fetch() 이후 채워짐 refresh() 전까지 []
fetch()body 옵션 동작 무시됨
설정 서명 검증 수행 건너뜀
사용량 텔레메트리 opt-in(telemetry: true) 서버가 자동 집계
단일 소스 타임아웃 없음 15초
멀티소스 타임아웃 소스별 기본 5초 소스별 기본 15초
SSRF 방어·응답 크기 상한 없음 있음(5MB)

proxy 모드에서 자주 걸리는 것

cook.endpoints가 빈 배열입니다. proxy 모드는 설정 JSON을 내려받지 않으므로 slug 목록을 모릅니다. 목록이 필요하면 먼저 갱신하세요.

await cook.refresh();
console.log(cook.endpoints);  // ['air-quality', 'bus-arrival']

POST 본문이 전달되지 않습니다. proxy 경로는 파라미터만 받도록 되어 있어 fetch()의 세 번째 인자 body가 서버까지 가지 않습니다. 본문이 필요한 API는 direct 모드로 호출해야 합니다.

응답이 최대 60초 묵을 수 있습니다. 같은 파라미터로 다시 부르면 서버 캐시가 그대로 돌아옵니다. 엔드포인트의 캐시 TTL을 콘솔에서 0으로 두면 캐시하지 않습니다. 실시간성이 중요한 데이터라면 확인해 두세요.

direct 모드에서 자주 걸리는 것

브라우저에서 CORS 오류가 납니다. mode: 'direct'를 직접 지정했는데 원본 API가 CORS를 허용하지 않는 경우입니다. 지정을 빼서 자동 감지에 맡기세요.

단일 소스 호출에는 타임아웃이 없습니다. 원본 API가 응답하지 않으면 fetch()가 그대로 매달립니다. 서버에서 쓸 때는 호출부에서 직접 시간을 제한하는 편이 안전합니다.

const data = await Promise.race([
    cook.fetch('air-quality', { sidoName: '서울' }),
    new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 5000)),
]);

Web Crypto가 필요합니다. 설정 JSON의 서명 검증이 기본으로 켜져 있고(verifySignature의 기본값은 true입니다), 검증에 crypto.subtle을 씁니다. Node 18 이상이나 최신 브라우저에서는 문제가 없지만, 그보다 낮은 환경에서는 폴리필이 필요합니다.

어느 쪽을 써야 하나

자동 감지에 맡기는 것이 기본값입니다. 브라우저에서는 CORS를 우회해야 하고 서버에서는 직접 호출이 빠르므로, 자동 선택이 대체로 옳습니다.

명시적으로 고를 만한 경우는 이렇습니다.

  • 서버에서 proxy를 쓴다 — 응답 캐시를 공유하고 싶을 때. 여러 인스턴스가 같은 데이터를 부르면 원본 API 호출 수가 줄어듭니다.
  • 브라우저에서 direct를 쓴다 — 원본 API가 CORS를 확실히 허용하고, 서버를 한 단계 거치는 지연을 줄이고 싶을 때.

키를 어디에 두어야 하는지는 인증 파라미터 관리보안에서 다룹니다.