제5장

Phase 2 - API 인터페이스

Phase 2는 Phase 1에서 확립한 표준화된 데이터 형식을 토대로, 생물다양성 데이터를 실제로 활용할 수 있게 하는 연산 서비스와 API를 제공한다. 이 장에서는 원시 관측 자료를 의미 있는 보전 통찰로 바꾸는 RESTful 및 GraphQL API, 다양성 계산 엔진, 통합 서비스, 실시간 분석 기능을 상세히 설명한다.

API 아키텍처

WIA API는 현대적인 REST 원칙을 따르면서 복잡한 질의를 위해 GraphQL도 제공한다. 이 이중 접근 방식은 기본 작업의 단순성과 고급 활용 사례에 필요한 강력한 기능 사이의 균형을 맞춘다.

RESTful 엔드포인트

REST API는 리소스를 계층적으로 구성하고 표준 HTTP 메서드를 사용한다. 이 장의 예시에 쓰인 호스트 이름(api.biodiversity.wia.org 등)과 SDK 패키지 이름은 참조 구현을 설명하기 위한 예시 명칭이며, 현재 공개 운영 중인 서비스나 배포된 패키지가 아니다.

Base URL: https://api.biodiversity.wia.org/v1/

# 출현 기록 엔드포인트
GET    /occurrences                    # 출현 기록 목록 조회(페이지 단위)
POST   /occurrences                    # 새 출현 기록 생성
GET    /occurrences/{id}              # 특정 출현 기록 조회
PUT    /occurrences/{id}              # 출현 기록 수정
DELETE /occurrences/{id}              # 출현 기록 삭제

# 다양성 지수
POST   /indices/calculate              # 다양성 지수 계산
GET    /indices/{calculation_id}       # 계산된 지수 조회
GET    /indices/trends                 # 시간적 추세 분석

# 종 엔드포인트
GET    /species                        # 종 목록 조회
GET    /species/{taxon_id}            # 종 상세 정보 조회
GET    /species/{taxon_id}/occurrences # 해당 종의 출현 기록
GET    /species/search?q={query}      # 종 검색

# 공간 질의
GET    /spatial/region/{polygon}       # 다각형 내 출현 기록
GET    /spatial/proximity              # 좌표 인근의 종
POST   /spatial/hotspots              # 생물다양성 핫스팟 식별

# 데이터 검증
POST   /validate/occurrence            # 출현 기록 데이터 검증
POST   /validate/batch                # 일괄 검증

# 통합
POST   /export/gbif                    # GBIF 형식으로 내보내기
POST   /export/geojson                # GeoJSON으로 내보내기
GET    /taxonomy/resolve              # 분류학적 학명 확인

인증 및 권한 부여

API는 안전한 무상태(stateless) 인증을 위해 JWT 토큰 기반의 OAuth 2.0을 사용한다.

# 액세스 토큰 발급
POST https://auth.biodiversity.wia.org/oauth/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "scope": "read:occurrences write:occurrences calculate:indices"
}

# 응답
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read:occurrences write:occurrences calculate:indices"
}

# 요청에 토큰 사용
GET https://api.biodiversity.wia.org/v1/occurrences
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

다양성 지수 계산 API

핵심 분석 기능은 출현 기록 데이터로부터 생물다양성 지수를 계산하는 것이다.

다양성 지수 계산

POST /v1/indices/calculate
Content-Type: application/json
Authorization: Bearer {token}

{
  "dataset_id": "DS-AMAZON-2025",
  "spatial_filter": {
    "type": "polygon",
    "coordinates": [[[-60.5, -3.5], [-60.0, -3.5], [-60.0, -3.0], [-60.5, -3.0], [-60.5, -3.5]]]
  },
  "temporal_filter": {
    "start_date": "2025-01-01",
    "end_date": "2025-12-31"
  },
  "indices": [
    "species_richness",
    "shannon_diversity",
    "simpson_index",
    "pielou_evenness"
  ],
  "rarefaction": {
    "enabled": true,
    "target_n": 1000
  },
  "bootstrap": {
    "enabled": true,
    "iterations": 1000,
    "confidence_level": 0.95
  }
}

# 응답
{
  "calculation_id": "CALC-2025-AZ-1234",
  "status": "completed",
  "execution_time_ms": 2847,
  "results": {
    "species_richness": {
      "observed": 156,
      "rarefied": 142.7,
      "ci_lower": 138.2,
      "ci_upper": 147.3
    },
    "shannon_diversity": {
      "value": 4.127,
      "ci_lower": 3.982,
      "ci_upper": 4.268
    },
    "simpson_index": {
      "value": 0.0234,
      "diversity_1_minus_d": 0.9766,
      "inverse": 42.74
    },
    "pielou_evenness": {
      "value": 0.817,
      "interpretation": "high_evenness"
    }
  },
  "metadata": {
    "input_occurrences": 4523,
    "unique_species": 156,
    "total_individuals": 8947,
    "calculation_date": "2025-12-26T10:30:00Z"
  }
}

GraphQL 인터페이스

서로 연관된 여러 리소스가 필요한 복잡한 질의에서는 GraphQL이 단일 요청으로 효율적인 접근을 제공한다.

POST https://api.biodiversity.wia.org/graphql
Content-Type: application/json

{
  "query": "{
    species(scientificName: \"Panthera tigris\") {
      taxonId
      commonNames
      conservationStatus {
        category
        populationTrend
      }
      occurrences(limit: 10, year: 2025) {
        occurrenceId
        location {
          latitude
          longitude
          protectedArea
        }
        observationDate
        individualCount
      }
      diversityIndices(region: \"India\") {
        shannonIndex
        simpsonIndex
      }
    }
  }"
}

# 응답은 요청한 데이터 구조를 정확히 그대로 제공한다
{
  "data": {
    "species": {
      "taxonId": "WIA-TAX-001200",
      "commonNames": ["Tiger", "बाघ"],
      "conservationStatus": {
        "category": "EN",
        "populationTrend": "Increasing"
      },
      "occurrences": [
        {
          "occurrenceId": "OCC-2025-IN-78945",
          "location": {
            "latitude": 27.5142,
            "longitude": 88.7597,
            "protectedArea": true
          },
          "observationDate": "2025-11-15",
          "individualCount": 1
        }
        // ... 추가 출현 기록
      ],
      "diversityIndices": {
        "shannonIndex": 3.45,
        "simpsonIndex": 0.0412
      }
    }
  }
}

실시간 분석

WebSocket 연결을 통해 실시간 생물다양성 모니터링과 경보가 가능하다.

// WebSocket 연결
const ws = new WebSocket('wss://stream.biodiversity.wia.org/v1/live');

// 멸종위기종 탐지 구독
ws.send(JSON.stringify({
  "action": "subscribe",
  "channels": ["endangered_detections"],
  "filters": {
    "region": "Southeast_Asia",
    "iucn_categories": ["CR", "EN"]
  }
}));

// 실시간 경보 수신
ws.onmessage = (event) => {
  const alert = JSON.parse(event.data);
  console.log('멸종위기종 탐지:', alert);
  /*
  {
    "event_type": "endangered_detection",
    "timestamp": "2025-12-26T14:23:15Z",
    "species": {
      "scientific_name": "Dicerorhinus sumatrensis",
      "common_name": "Sumatran Rhino",
      "iucn_status": "CR"
    },
    "location": {
      "latitude": -4.9300,
      "longitude": 105.7800,
      "protected_area": "Way Kambas National Park"
    },
    "detection_method": "camera_trap",
    "confidence": 0.96
  }
  */
};

데이터 검증 서비스

자동 검증은 제출 전에 데이터 품질을 보장한다.

POST /v1/validate/occurrence

{
  "occurrence_id": "OCC-2025-TEST-001",
  "species": {
    "scientific_name": "Panthera tigris",
    "taxon_id": "GBIF:5219416"
  },
  "location": {
    "latitude": 27.5142,
    "longitude": 88.7597,
    "country": "India"
  },
  "temporal": {
    "observation_date": "2025-11-15T09:30:00Z"
  }
}

# 응답
{
  "valid": true,
  "quality_score": 0.94,
  "checks": [
    {
      "check": "coordinate_validity",
      "status": "passed",
      "message": "좌표가 유효 범위 안에 있음"
    },
    {
      "check": "country_match",
      "status": "passed",
      "message": "좌표가 기재된 국가(India)와 일치함"
    },
    {
      "check": "species_range",
      "status": "passed",
      "message": "위치가 알려진 종 분포 범위 안에 있음"
    },
    {
      "check": "taxonomy_valid",
      "status": "passed",
      "message": "분류군 ID가 유효한 GBIF 항목으로 확인됨"
    },
    {
      "check": "date_reasonable",
      "status": "passed",
      "message": "날짜가 미래가 아니며 합리적인 과거 범위 안에 있음"
    }
  ],
  "warnings": [],
  "errors": []
}

통합 서비스

GBIF 업로드 서비스

세계생물다양성정보기구(GBIF, Global Biodiversity Information Facility)에 직접 제출한다.

POST /v1/export/gbif

{
  "dataset_id": "DS-AMAZON-2025",
  "gbif_dataset_key": "50c9509d-22c7-4a22-a47d-8c48425ef4a7",
  "filters": {
    "date_range": {
      "start": "2025-01-01",
      "end": "2025-12-31"
    }
  },
  "mapping_profile": "darwin_core_v1.0",
  "validate_before_upload": true
}

# 응답
{
  "export_id": "EXP-GBIF-2025-1234",
  "status": "processing",
  "records_to_export": 4523,
  "validation_results": {
    "valid": 4498,
    "warnings": 25,
    "errors": 0
  },
  "estimated_completion": "2025-12-26T15:00:00Z"
}

IUCN 적색 목록 통합

보전 상태와 위협 정보를 조회한다. 아래 응답의 평가 기준, 개체군 추세, 위협 항목, 보전 조치, 평가 일자는 응답 형식을 보여 주기 위한 예시 값이며, 실제 값은 IUCN 적색 목록의 최신 평가를 따른다.

GET /v1/integration/iucn/species/Panthera%20tigris

# 응답
{
  "scientific_name": "Panthera tigris",
  "category": "EN",
  "criteria": "A2abcd+3cd+4abcd",
  "population_trend": "Increasing",
  "systems": ["Terrestrial"],
  "threats": [
    {
      "code": "5.1.1",
      "title": "Intentional use (species is the target)",
      "timing": "Ongoing",
      "scope": "Minority (<50%)",
      "severity": "Rapid Declines",
      "score": "Medium Impact: 6"
    },
    {
      "code": "2.1.2",
      "title": "Small-holder farming",
      "timing": "Ongoing",
      "scope": "Majority (50-90%)",
      "severity": "Slow, Significant Declines",
      "score": "Medium Impact: 7"
    }
  ],
  "conservation_actions": [
    {
      "code": "2.1",
      "title": "Site/area management"
    },
    {
      "code": "4.3",
      "title": "Awareness & communications"
    }
  ],
  "source": "IUCN Red List API v3",
  "assessment_date": "2023-06-15"
}

요청 속도 제한 및 성능

공정한 접근과 시스템 안정성을 보장하기 위해 API는 요청 속도 제한(rate limiting)을 적용한다.

등급 속도 제한 순간 최대(버스트) 제한 활용 사례
무료(Free) 1,000 요청/시간 50 요청/분 개인 연구자, 소규모 프로젝트
연구(Research) 10,000 요청/시간 200 요청/분 학술 기관, NGO
엔터프라이즈(Enterprise) 100,000 요청/시간 1,000 요청/분 정부 기관, 대형 보전 단체
맞춤(Custom) 협의 협의 글로벌 이니셔티브, 장기 파트너십

SDK 및 클라이언트 라이브러리

공식 SDK는 여러 프로그래밍 언어에서 API 통합을 간소화한다.

Python SDK 예제

from wia_biodiversity import BiodiversityAPI

# 클라이언트 초기화
client = BiodiversityAPI(api_key='your_api_key')

# 출현 기록 조회
occurrences = client.occurrences.list(
    species='Panthera tigris',
    country='India',
    year=2025,
    limit=100
)

# 다양성 지수 계산
results = client.indices.calculate(
    dataset_id='DS-INDIA-2025',
    indices=['shannon', 'simpson', 'richness'],
    spatial_filter=client.geo.polygon([
        [88.0, 27.0], [89.0, 27.0], [89.0, 28.0], [88.0, 28.0]
    ]),
    bootstrap_iterations=1000
)

print(f"섀넌 다양성: {results.shannon.value:.3f}")
print(f"종 풍부도: {results.richness.observed}")

TypeScript SDK 예제

import { BiodiversityClient } from '@wia/biodiversity-sdk';

const client = new BiodiversityClient({
  apiKey: process.env.WIA_API_KEY
});

// 실시간 종 탐지 모니터링
const stream = client.stream.subscribe({
  channels: ['endangered_detections'],
  filters: {
    region: 'Southeast_Asia',
    iucnCategories: ['CR', 'EN']
  }
});

stream.on('detection', (event) => {
  console.log(`${event.species.commonName} 탐지됨!`);
  console.log(`위치: ${event.location.protectedArea}`);
  console.log(`신뢰도: ${event.confidence}`);
});

오류 처리

API는 표준 HTTP 상태 코드와 구조화된 오류 응답을 사용한다.

# 오류 응답 형식
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "종 학명 형식이 올바르지 않음",
    "details": {
      "field": "species.scientific_name",
      "value": "panthera tigris",  // 소문자 - 유효하지 않음
      "expected": "첫 글자를 대문자로 쓴 이명법 학명"
    },
    "documentation_url": "https://docs.biodiversity.wia.org/errors/VALIDATION_ERROR"
  },
  "request_id": "req_abc123def456"
}
상태 코드 오류 코드 설명
400 VALIDATION_ERROR 요청 데이터가 검증 규칙을 통과하지 못함
401 UNAUTHORIZED 인증 정보가 없거나 유효하지 않음
403 FORBIDDEN 인증은 유효하나 권한이 부족함
404 NOT_FOUND 요청한 리소스가 존재하지 않음
429 RATE_LIMIT_EXCEEDED 요청이 너무 많음
500 INTERNAL_ERROR 서버 측 처리 오류

장 요약

핵심 요점

  • 이중 API 접근 방식 - 단순한 작업에는 RESTful 엔드포인트를, 복잡한 질의에는 GraphQL을 사용하여 사용 편의성과 강력한 기능을 모두 제공한다.
  • 포괄적인 분석 서비스 - 부트스트랩 신뢰구간과 희박화(rarefaction)를 지원하는 다양성 지수 자동 계산을 제공한다.
  • 실시간 기능 - WebSocket 스트리밍으로 보전 우선 대상에 대한 실시간 모니터링과 즉각적인 경보가 가능하다.
  • 매끄러운 통합 - GBIF, IUCN 및 기타 주요 생물다양성 플랫폼용 내장 커넥터가 수작업 데이터 전송을 없앤다.
  • 프로덕션 수준의 기능 - OAuth 2.0 인증, 요청 속도 제한, 오류 처리, 공식 SDK가 엔터프라이즈급 신뢰성을 보장한다.

복습 문제

  1. WIA API의 REST 방식과 GraphQL 방식을 비교하라. 생물다양성 모니터링 애플리케이션에서 각각을 언제 선택하겠는가?
  2. 다양성 지수 계산 API가 부트스트랩과 희박화 방법을 통해 통계적 불확실성을 어떻게 다루는지 설명하라.
  3. OAuth 2.0을 이용한 인증 흐름을 설명하라. 이 방식이 API 키만 사용하는 인증보다 더 안전한 이유는 무엇인가?
  4. WebSocket 스트림은 기존 폴링 방식으로는 불가능한 실시간 보전 대응을 어떻게 가능하게 하는가?
  5. 데이터 제출 전에 어떤 검증 항목이 수행되는가? 이것이 후속 단계의 데이터 품질 문제를 어떻게 예방하는가?
  6. 요청 속도 제한 등급에 대해 논하라. 이 등급들은 개방형 접근 원칙과 시스템 지속가능성 사이의 균형을 어떻게 맞추는가?

다음 장 예고: 제6장에서는 Phase 3: 프로토콜을 다루며, 수집 시점부터 데이터 품질을 보장하는 표준화된 현장 조사 방법론, 품질 보증 절차, 인증 프로그램을 상세히 설명한다.