본문으로 건너뛰기

외부 연동 가이드

quant-ai 같은 외부 서비스가 GenD API 를 호출하기 위한 모든 정보를 한 곳에 모은 문서. M2M 인증 설계는 M2M 서비스 계정 인증 문서를 먼저 읽고 본 가이드로 돌아오세요.

TL;DR — 5분 안에 호출 시작

# 1. GenD admin → /admin/service-clients → 새 발급 (suffix=quant-ai, role=viewer)
# → 모달에서 표시되는 client_secret 즉시 복사

export GEND_BASE_URL="https://gend.genon.ai"
export GEND_REALM="gend"
export GEND_CLIENT_ID="gend-svc-quant-ai"
export GEND_CLIENT_SECRET="<발급 모달에서 복사한 값>"

# 2. 토큰 발급
TOKEN=$(curl -sS -X POST \
"$GEND_BASE_URL/auth/realms/$GEND_REALM/protocol/openid-connect/token" \
-d grant_type=client_credentials \
-d client_id="$GEND_CLIENT_ID" \
-d client_secret="$GEND_CLIENT_SECRET" \
| jq -r .access_token)

# 3. API 호출
curl -sS -H "Authorization: Bearer $TOKEN" \
"$GEND_BASE_URL/api/v1/catalog/catalogs"

엔드포인트 매트릭스

용도URL인증비고
헬스체크GET /health❌ publicprefix 없음. JSON 반환.
메트릭GET /metrics❌ publicPrometheus 텍스트
OpenAPI 스펙GET /openapi.json❌ public외부 클라이언트가 스펙 파싱용. #661 부터 외부 노출
Swagger UIGET /docs❌ public브라우저용 인터랙티브 docs
ReDoc UIGET /redoc❌ public정적 docs
API 라우터GET/POST /api/v1/...✅ Bearer JWTcatalog, query, ai, rag, notification, feature, quality, governance, ingestion 등
Keycloak 토큰POST /auth/realms/gend/protocol/openid-connect/tokenclient_credentials토큰 발급용

주의: GET /api/v1/health404 입니다 — health 는 prefix 없이 /health. ingress 설정상 의도된 분리이며 변경 예정 없음.

인증 — 토큰 라이프사이클

Realm 설정

항목
Realmgend
Issuer URLhttps://gend.genon.ai/auth/realms/gend
Token endpointhttps://gend.genon.ai/auth/realms/gend/protocol/openid-connect/token
JWKShttps://gend.genon.ai/auth/realms/gend/protocol/openid-connect/certs
Access Token 수명30분 (accessTokenLifespan: 1800)realm-export.json:28, 라이브 realm 과 일치. 클라이언트는 상수 대신 응답의 expires_in 을 사용할 것
Refresh Token사용 안 함 (client_credentials grant 표준)

클라이언트 캐시 패턴 (권장)

토큰을 매 요청마다 발급하지 말고 만료 60초 전까지 재사용하세요.

import os, time, httpx

class GendClient:
def __init__(self):
self.base = os.environ["GEND_BASE_URL"]
self.realm = os.environ.get("GEND_REALM", "gend")
self.client_id = os.environ["GEND_CLIENT_ID"]
self.client_secret = os.environ["GEND_CLIENT_SECRET"]
self._token: str | None = None
self._exp: float = 0

def _ensure_token(self) -> None:
if self._token and time.time() < self._exp - 60:
return
r = httpx.post(
f"{self.base}/auth/realms/{self.realm}/protocol/openid-connect/token",
data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret,
},
timeout=10,
)
r.raise_for_status()
body = r.json()
self._token = body["access_token"]
self._exp = time.time() + body["expires_in"]

def _headers(self) -> dict[str, str]:
self._ensure_token()
return {"Authorization": f"Bearer {self._token}"}

def get_catalogs(self) -> list[dict]:
return httpx.get(
f"{self.base}/api/v1/catalog/catalogs",
headers=self._headers(), timeout=30,
).json()

401 자동 retry

토큰이 회전되거나 만료된 직후 호출하면 401. 한 번 재발급 후 재시도하는 패턴:

def _call_with_retry(self, method, url, **kw):
r = httpx.request(method, url, headers=self._headers(), **kw)
if r.status_code == 401:
self._token = None
self._exp = 0
r = httpx.request(method, url, headers=self._headers(), **kw)
return r

API 스펙 받기

OpenAPI JSON 을 프로젝트에 다운받아 코드젠하거나 직접 파싱하세요:

curl -sS https://gend.genon.ai/openapi.json -o gend-openapi.json

# Python httpx 클라이언트 자동 생성 예 (openapi-python-client 등 활용)
openapi-python-client generate --path gend-openapi.json

핵심 라우터 그룹(자세한 스펙은 OpenAPI 참조):

  • catalog — 데이터 카탈로그 조회 (catalogs / schemas / tables / columns / sample / metadata)
  • query — Trino SQL 실행 (POST /api/v1/query/execute, sync/async)
  • ai — NL2SQL (POST /api/v1/ai/ask, POST /api/v1/ai/ask/execute)
  • rag — RAG 검색 (POST /api/v1/rag/query), 컬렉션 관리
  • feature — Feature Store
  • quality / governance — 품질 점수 / 라인이지 / 스키마 변경
  • notification — 알림 채널 등록 / dispatch
  • admin/service-clients — M2M 클라이언트 자체 발급 (별도 문서)

권한 매트릭스 (service 토큰)

라우터별로 필요한 realm role 을 service-account 사용자 (service-account-gend-svc-<suffix>) 에 부여해야 한다. UI 에서 발급 시 viewer / analyst 선택 가능.

라우터필요 role
GET /api/v1/catalog/*viewer
GET /api/v1/quality/*viewer
GET /api/v1/governance/*viewer
GET /api/v1/feature/*viewer
POST /api/v1/query/executeanalyst
POST /api/v1/ai/askanalyst (또는 ai-user, OpenAPI 참조)
POST /api/v1/rag/queryanalyst
POST /api/v1/notification/.../dispatchanalyst 이상
변경 작업 (POST/PUT/DELETE)admin 전용 — service 토큰 자동 거부

서비스 토큰은 admin 으로 자동 승격되지 않습니다. 변경 작업이 필요하면 admin role 이 별도 부여된 클라이언트를 발급하거나, 사용자 JWT 를 사용하세요.

에러 응답 shape (현재 — 변경 예정)

{
"detail": "사용자 친화적 메시지"
}

또는 Pydantic ValidationError (FastAPI 표준):

{
"detail": [
{"loc": ["body", "client_id"], "msg": "...", "type": "value_error"}
]
}

로드맵: 후속 이슈에서 RFC 7807 Problem Details 로 표준화 예정 ({type, title, status, detail, instance, code}). 지금은 detail 이 string 인지 list 인지 분기 처리 필요.

빠른 진단 체크리스트

증상원인 후보
/openapi.json 이 HTML 반환(구버전 ingress) — 본 PR 전 상태. 머지 후 JSON 정상.
/api/v1/health 404의도된 동작 — /health (prefix 없음) 사용
토큰 발급 401client_secret 불일치, secret 회전 후 미반영
API 호출 401 Token expired토큰 만료 (30분) — expires_in 기준으로 캐시 갱신 필요
API 호출 401 Invalid audienceservice client 의 audience mapper 누락 — 신규 발급 시 자동, 수동 추가한 client 면 mapper 확인
API 호출 403 권한 부족service-account 에 viewer/analyst realm role 미부여 — 본 문서의 권한 매트릭스 참조

quant-ai 통합 참조 패턴

quant-ai 가 구현한 GenD 어댑터 모듈 (참고용 외부 구현):

파일역할
src/data/gend/client.pyGendClient — token lifecycle + 401 retry + endpoint wrappers
src/data/gend/models.pyDTO (AskRequest/Response, RagQueryRequest/Response)
src/analysis/tools/gend_tools.pyask_gend (NL2SQL), rag_query — Agent tool
src/data/news/gend_provider.pyRAG 기반 뉴스 provider
src/monitoring/notifications/gend.pyGendChannel — 알림 dispatch wrapper

후속 로드맵

  • Error response 표준화 (RFC 7807) — 후속 이슈
  • M2M client 발급 후 self-test 엔드포인트 — 발급 즉시 토큰 발급 + viewer 호출 테스트 통과 응답 (HI-4)
  • Event polling API — webhook 없는 환경에서 GET /api/v1/events?since=<timestamp> 형태 (P2)
  • Catalog bulk exportGET /api/v1/catalog/export (JSON/Parquet) — 시스템 간 동기화용 (P2)

관련