외부 연동 가이드
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 | ❌ public | prefix 없음. JSON 반환. |
| 메트릭 | GET /metrics | ❌ public | Prometheus 텍스트 |
| OpenAPI 스펙 | GET /openapi.json | ❌ public | 외부 클라이언트가 스펙 파싱용. #661 부터 외부 노출 |
| Swagger UI | GET /docs | ❌ public | 브라우저용 인터랙티브 docs |
| ReDoc UI | GET /redoc | ❌ public | 정적 docs |
| API 라우터 | GET/POST /api/v1/... | ✅ Bearer JWT | catalog, query, ai, rag, notification, feature, quality, governance, ingestion 등 |
| Keycloak 토큰 | POST /auth/realms/gend/protocol/openid-connect/token | client_credentials | 토큰 발급용 |
주의:
GET /api/v1/health는 404 입니다 — health 는 prefix 없이/health. ingress 설정상 의도된 분리이며 변경 예정 없음.
인증 — 토큰 라이프사이클
Realm 설정
| 항목 | 값 |
|---|---|
| Realm | gend |
| Issuer URL | https://gend.genon.ai/auth/realms/gend |
| Token endpoint | https://gend.genon.ai/auth/realms/gend/protocol/openid-connect/token |
| JWKS | https://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/execute | analyst |
POST /api/v1/ai/ask | analyst (또는 ai-user, OpenAPI 참조) |
POST /api/v1/rag/query | analyst |
POST /api/v1/notification/.../dispatch | analyst 이상 |
| 변경 작업 (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 없음) 사용 |
| 토큰 발급 401 | client_secret 불일치, secret 회전 후 미반영 |
API 호출 401 Token expired | 토큰 만료 (30분) — expires_in 기준으로 캐시 갱신 필요 |
API 호출 401 Invalid audience | service client 의 audience mapper 누락 — 신규 발급 시 자동, 수동 추가한 client 면 mapper 확인 |
API 호출 403 권한 부족 | service-account 에 viewer/analyst realm role 미부여 — 본 문서의 권한 매트릭스 참조 |
quant-ai 통합 참조 패턴
quant-ai 가 구현한 GenD 어댑터 모듈 (참고용 외부 구현):
| 파일 | 역할 |
|---|---|
src/data/gend/client.py | GendClient — token lifecycle + 401 retry + endpoint wrappers |
src/data/gend/models.py | DTO (AskRequest/Response, RagQueryRequest/Response) |
src/analysis/tools/gend_tools.py | ask_gend (NL2SQL), rag_query — Agent tool |
src/data/news/gend_provider.py | RAG 기반 뉴스 provider |
src/monitoring/notifications/gend.py | GendChannel — 알림 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 export —
GET /api/v1/catalog/export(JSON/Parquet) — 시스템 간 동기화용 (P2)
관련
- M2M 서비스 계정 인증 — 클라이언트 발급/회전 UI 사용법
- Roles & Permissions — realm role 권한 모델