요약
EHR API는 Epic, Cerner, Athenahealth 같은 시스템에 저장된 환자 건강 기록에 접근할 수 있는 표준화된 방법을 제공합니다. 대부분의 최신 EHR은 의료 데이터 표준인 FHIR(Fast Healthcare Interoperability Resources)를 지원하며, 인증에는 SMART on FHIR 확장 기능을 사용하는 OAuth 2.0이 사용됩니다. 실제 프로덕션 환경에 연결하기 전에, Apidog를 활용해 FHIR 리소스 구조를 검증하고 샌드박스 환경에서 통합 동작을 사전에 테스트하세요.
서론
전자의무기록(EHR)에는 진단, 약물, 검사 결과, 알레르기, 치료 계획 등 환자 진료에 관한 모든 정보가 저장됩니다. 병원, 의원, 의료 시스템은 이 데이터를 Epic, Cerner, Athenahealth와 같은 EHR 플랫폼에 보관합니다.
의료 애플리케이션을 개발할 때는 이 시스템들과의 실시간 데이터 연동이 필수입니다. CSV 파일 수동 추출 방식은 적합하지 않으므로, 직접 API 연동이 필요합니다. 하지만 의료 API는 보호 대상 건강 정보(PHI)를 다루므로, HIPAA 등 각종 규정 준수와 함께 인증, 권한 부여, 데이터 매핑이 복잡하게 얽혀 있습니다.
대부분의 EHR 공급업체가 FHIR 표준을 지원하지만, 실제 연동 과정에서는 인증 흐름과 데이터 구조 검증 등 까다로운 요소가 많습니다. Apidog 같은 도구를 통해 FHIR 리소스를 직접 테스트하고, 샌드박스 환경에서 문제를 사전에 잡을 수 있습니다.
이 가이드에서는 다음을 실습할 수 있습니다.
- FHIR 리소스 유형 및 구조 이해
- SMART on FHIR 인증 실습
- 환자 인구 통계 및 임상 데이터 쿼리
- 환자 리소스 생성 및 업데이트
- 샌드박스 환경에서의 기능 테스트
FHIR 이해하기
FHIR (Fast Healthcare Interoperability Resources)는 최신 의료 데이터 연동 표준입니다. 주요 특징은 다음과 같습니다.
- 리소스: 의료 데이터 단위(환자, 관찰, 약물 등)
- REST API: 표준 HTTP 메서드로 리소스 관리
- 형식: JSON 및 XML 지원
기본 URL 구조
https://ehr.example.com/fhir/r4/{resource-type}/{id}
예시:
GET https://ehr.example.com/fhir/r4/Patient/123
FHIR 버전
대부분의 EHR은 FHIR R4(릴리스 4)를 사용합니다. 일부 구형 시스템은 DSTU2를 사용할 수 있지만, 실무에서는 R4를 기준으로 구현하면 됩니다.
리소스 유형
| 리소스 | 목적 |
|---|---|
| Patient | 인구 통계 및 관리 데이터 |
| Practitioner | 의료 제공자 |
| Organization | 병원, 의원 |
| Observation | 검사 결과, 활력 징후 |
| MedicationRequest | 처방전 |
| Condition | 진단, 문제 |
| Encounter | 방문, 입원 |
| DocumentReference | 임상 문서 |
| AllergyIntolerance | 알레르기 및 부작용 |
FHIR 리소스 구조
환자 리소스 예시
{
"resourceType": "Patient",
"id": "123",
"active": true,
"name": [
{
"use": "official",
"family": "Smith",
"given": ["John", "Michael"]
}
],
"gender": "male",
"birthDate": "1985-03-15",
"address": [
{
"use": "home",
"line": ["123 Main St"],
"city": "Boston",
"state": "MA",
"postalCode": "02101",
"country": "USA"
}
],
"telecom": [
{
"system": "phone",
"value": "555-123-4567",
"use": "home"
},
{
"system": "email",
"value": "john.smith@example.com"
}
],
"identifier": [
{
"system": "http://hospital.example.org/mrn",
"value": "MRN-123456"
}
]
}
관찰 리소스 예시
{
"resourceType": "Observation",
"id": "obs-123",
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs",
"display": "Vital Signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8480-6",
"display": "Systolic blood pressure"
}
]
},
"subject": {
"reference": "Patient/123"
},
"effectiveDateTime": "2026-03-24T09:30:00Z",
"valueQuantity": {
"value": 120,
"unit": "mmHg",
"system": "http://unitsofmeasure.org",
"code": "mm[Hg]"
}
}
SMART on FHIR을 이용한 인증
SMART on FHIR은 의료 인증을 위한 OAuth 2.0 확장입니다. 환자 컨텍스트와 EHR별 권한 범위(Scope)를 처리합니다.
환자 접근을 위한 OAuth 흐름
1단계: 인가(Authorization) URL 확인
GET https://ehr.example.com/fhir/r4/.well-known/smart-configuration
응답 예시:
{
"authorization_endpoint": "https://ehr.example.com/oauth2/authorize",
"token_endpoint": "https://ehr.example.com/oauth2/token",
"scopes_supported": [
"patient/*.read",
"patient/*.write",
"user/*.read",
"launch/patient"
]
}
2단계: 사용자 브라우저 리디렉션
https://ehr.example.com/oauth2/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
scope=patient/*.read&
state=random_state_value
3단계: 인가 코드로 토큰 요청
curl -X POST "https://ehr.example.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
응답 예시:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "patient/*.read",
"patient": "123"
}
patient 필드는 환자 ID 컨텍스트입니다.
SMART 스코프
| 스코프 | 접근 권한 |
|---|---|
patient/*.read |
모든 환자 데이터 읽기 |
patient/Patient.read |
환자 인구 통계만 읽기 |
patient/Observation.read |
관찰 데이터만 읽기 |
user/*.read |
승인 사용자 데이터 전체 읽기 |
launch/patient |
EHR이 환자 컨텍스트로 앱 실행 |
환자 데이터 쿼리
환자 인구 통계 가져오기
curl -X GET "https://ehr.example.com/fhir/r4/Patient/123" \
-H "Authorization: Bearer ACCESS_TOKEN"
관찰 데이터 검색
curl -X GET "https://ehr.example.com/fhir/r4/Observation?patient=123&category=vital-signs" \
-H "Authorization: Bearer ACCESS_TOKEN"
응답은 번들(Bundle) 형태입니다.
{
"resourceType": "Bundle",
"type": "searchset",
"total": 5,
"entry": [
{
"resource": { ... Observation resource ... }
}
]
}
일반적인 검색 매개변수
# 날짜 범위별 검사 결과
GET /Observation?patient=123&category=laboratory&date=gt2026-01-01
# 특정 LOINC 코드
GET /Observation?patient=123&code=http://loinc.org|8480-6
# 약물
GET /MedicationRequest?patient=123&status=active
# 상태 (진단)
GET /Condition?patient=123&clinical-status=active
# 진료
GET /Encounter?patient=123&type=AMB
페이지 매김
GET /Observation?patient=123&_count=20
응답 예시:
{
"link": [
{
"relation": "next",
"url": "https://ehr.example.com/fhir/r4/Observation?patient=123&_count=20&page=2"
}
]
}
리소스 생성 및 업데이트
관찰 생성
curl -X POST "https://ehr.example.com/fhir/r4/Observation" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "8480-6",
"display": "Systolic blood pressure"
}]
},
"subject": {
"reference": "Patient/123"
},
"effectiveDateTime": "2026-03-24T09:30:00Z",
"valueQuantity": {
"value": 118,
"unit": "mmHg",
"system": "http://unitsofmeasure.org",
"code": "mm[Hg]"
}
}'
환자 업데이트
curl -X PUT "https://ehr.example.com/fhir/r4/Patient/123" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "Patient",
"id": "123",
"name": [{
"family": "Smith",
"given": ["John", "Michael"]
}],
"telecom": [{
"system": "phone",
"value": "555-999-8888",
"use": "home"
}]
}'
EHR 공급업체별 세부 사항
Epic
- 기본 URL:
https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/ - 샌드박스:
https://fhir.epic.com/test/api/FHIR/R4/ - 문서: https://fhir.epic.com
- 프로덕션 접근에는 Epic App Market 등록 필요
Cerner
- 기본 URL:
https://fhir-myrecord.cerner.com/r4/{tenant-id} - 샌드박스:
https://fhir-deprecated.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d - 문서: https://docs.oracle.com/en/health/health-cerner/
Athenahealth
- 기본 URL:
https://api.platform.athenahealth.com/fhir/r4/{practice-id} - 샌드박스: 개발자 프로그램 가입 필요
- 문서: https://docs.athenahealth.com
Apidog로 테스트하기
의료 API 테스트는 환자 데이터 보호를 위해 매우 중요합니다.
1. 공개 샌드박스 사용
공개 FHIR 샌드박스를 대상으로 테스트하세요.
# HAPI FHIR (오픈 소스)
https://hapi.fhir.org/baseR4
# SMART Health IT 샌드박스
https://launch.smarthealthit.org
2. FHIR 리소스 검증
pm.test('Resource is valid Patient', () => {
const response = pm.response.json()
pm.expect(response.resourceType).to.eql('Patient')
pm.expect(response.id).to.exist
pm.expect(response.name).to.be.an('array')
})
pm.test('Observation has required fields', () => {
const resource = pm.response.json()
pm.expect(resource.status).to.exist
pm.expect(resource.code).to.exist
pm.expect(resource.subject).to.exist
})
3. 인증 흐름 테스트
SMART 환경 변수 예시:
AUTHORIZATION_ENDPOINT: https://ehr.example.com/oauth2/authorize
TOKEN_ENDPOINT: https://ehr.example.com/oauth2/token
CLIENT_ID: your_client_id
CLIENT_SECRET: your_client_secret
SCOPE: patient/*.read
Apidog로 FHIR API를 무료로 테스트하세요.
규정 준수 고려사항
HIPAA
미국 내 의료 앱에서는 다음을 준수해야 합니다.
- 데이터 전송: TLS 1.2 이상 사용
- 데이터 저장: 미사용 데이터 암호화
- 접근 제어: 감사 로깅 및 최소 권한 원칙
- 사업 제휴 계약(BAA): EHR 공급업체와 체결 필요
SMART on FHIR 보안
- 토큰 만료(일반적으로 1시간)
- 새로 고침 토큰 지원
- 환자 컨텍스트는 토큰 스코프에 바인딩
- 로그아웃 시 토큰 폐기 필요
데이터 최소화
필요한 스코프만 요청하세요.
- 권장:
patient/Observation.read - 비권장:
patient/*.read(필요하지 않은 경우)
일반적인 오류 및 해결 방법
401 권한 없음
- 원인: 토큰 만료 또는 유효하지 않음
- 해결: 새로 고침 토큰으로 재발급
403 금지됨
- 원인: 스코프 부족
- 해결: 인가 요청 시 더 넓은 권한의 스코프 사용
404 찾을 수 없음
- 원인: 잘못된 리소스 ID 또는 접근 불가
- 해결: 리소스 ID 및 환자 컨텍스트 확인
422 처리할 수 없는 엔티티
- 원인: FHIR 리소스 유효성 검사 실패
- 해결: 필수 필드/용어 누락 여부 확인
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "required",
"details": {
"text": "Observation.status is required"
}
}]
}
대안 및 비교
| 기능 | Epic | Cerner | Athenahealth | OpenEMR |
|---|---|---|---|---|
| FHIR R4 | ✓ | ✓ | ✓ | 부분적 |
| SMART on FHIR | ✓ | ✓ | ✓ | 아니오 |
| 샌드박스 접근 | ✓ | ✓ | 제한적 | 자체 호스팅 |
| API 문서 | 우수 | 좋음 | 좋음 | 기본 |
| 시장 점유율 | 대형 병원 | 의료 시스템 | 소규모 병원 | 오픈 소스 |
Epic, Cerner가 대규모 의료 시스템에서 주로 사용되며, Athenahealth는 소규모 병원에 강점이 있습니다. OpenEMR은 오픈 소스이지만 API 지원에 한계가 있습니다.
실제 사용 사례
- 환자 포털: 의료기관이 Epic에서 데이터를 연동하여 환자가 검사 결과, 약물, 예약 정보를 확인하는 웹 포털을 개발. FHIR API와 SMART on FHIR 인증 활용.
- 임상 연구: 제약사가 여러 병원 시스템의 FHIR API를 쿼리해 임상시험 대상 환자 식별(적절한 동의 포함).
- 원격 모니터링: 원격 의료 회사가 환자 리포트 활력 징후를 FHIR Observation 리소스로 생성, Epic 등 EHR과 실시간 연동.
마무리
요약
- FHIR은 의료 API의 표준입니다.
- 리소스는 환자, 관찰 등 의료 개념을 구조화합니다.
- SMART on FHIR은 환자 컨텍스트 기반 OAuth 인증을 제공합니다.
- 각 EHR 공급업체별 구현 세부 사항을 반드시 확인해야 합니다.
- 실서비스 전 샌드박스 환경에서 충분히 테스트하세요.
다음 단계
- HAPI FHIR 공개 샌드박스를 실습해보세요.
- 자신의 사용 사례에 맞는 FHIR 리소스 구조를 파악하세요.
- EHR 개발자 프로그램에 등록하세요.
- 모의 환자 데이터로 Apidog에서 시나리오를 테스트하세요.
- HIPAA 등 규정 준수 데이터 처리를 구현하세요.
Apidog로 FHIR API를 무료로 테스트하세요.
자주 묻는 질문
FHIR과 HL7 v2의 차이점은?
HL7 v2는 레거시 병원 시스템에서 사용하는 메시징 표준이고, FHIR은 최신 REST 기반 표준입니다. 신규 통합은 FHIR을 권장하지만, HL7 v2는 여전히 일부 환경에서 사용됩니다.
EHR API 사용 시 BAA(사업 제휴 계약)가 필요한가요?
PHI 데이터를 처리한다면 반드시 필요합니다. EHR 공급업체의 규정 준수팀에 문의하세요.
Epic의 FHIR API 접근 방법은?
Epic App Orchard 마켓플레이스에 등록이 필요합니다. 샌드박스 테스트는 별도의 공개 샌드박스에서 가능합니다. 프로덕션 접근은 병원 승인 필수입니다.
환자 컨텍스트란?
SMART on FHIR 인증 토큰에는 환자 ID가 포함됩니다. API 쿼리는 해당 환자의 데이터로 제한되어, 안전한 데이터 접근이 보장됩니다.
EHR에 데이터를 쓸 수 있나요?
일부 리소스(Observation, Patient)는 쓰기가 가능하지만, 진단, 약물 등 민감 데이터는 추가 승인 필요합니다.
용어 코드 관리는 어떻게?
- 검사/관찰: LOINC
- 임상 개념: SNOMED CT
- 진단: ICD-10
- 약물: RxNorm 리소스 생성 시 표준 용어 사용이 필수입니다.
국제 적용은?
FHIR은 글로벌 표준입니다. 각 국가별 구현 가이드(예: 미국 US Core 등)를 반드시 확인하세요.

Top comments (0)