fhir-developer-skill
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFHIR Developer Skill
FHIR开发者技能
Quick Reference
快速参考
HTTP Status Codes
HTTP状态码
| Code | When to Use |
|---|---|
| Successful read, update, or search |
| Successful create (include |
| Successful delete |
| Malformed JSON, wrong resourceType |
| Missing, expired, revoked, or malformed token (RFC 6750) |
| Valid token but insufficient scopes |
| Resource doesn't exist |
| If-Match ETag mismatch (NOT 400!) |
| Missing required fields, invalid enum values, business rule violations |
| 状态码 | 适用场景 |
|---|---|
| 读取、更新或搜索操作成功 |
| 创建操作成功(需包含 |
| 删除操作成功 |
| JSON格式错误、resourceType错误 |
| 令牌缺失、过期、已撤销或格式错误(遵循RFC 6750) |
| 令牌有效但权限范围不足 |
| 资源不存在 |
| If-Match ETag不匹配(请勿返回400!) |
| 必填字段缺失、枚举值无效、违反业务规则 |
Required Fields by Resource (FHIR R4)
按资源划分的必填字段(FHIR R4)
| Resource | Required Fields | Everything Else |
|---|---|---|
| Patient | (none) | All optional |
| Observation | | Optional |
| Encounter | | Optional (including |
| Condition | | Optional (including |
| MedicationRequest | | Optional |
| Medication | (none) | All optional |
| Bundle | | Optional |
| 资源类型 | 必填字段 | 其他字段 |
|---|---|---|
| Patient | 无 | 均为可选 |
| Observation | | 可选 |
| Encounter | | 可选(包括 |
| Condition | | 可选(包括 |
| MedicationRequest | | 可选 |
| Medication | 无 | 均为可选 |
| Bundle | | 可选 |
Required vs Optional Fields (CRITICAL)
必填字段与可选字段(重点)
Only validate fields with cardinality starting with "1" as required.
| Cardinality | Required? |
|---|---|
| NO |
| YES |
Common mistake: Making or required on Encounter. They are 0..1 (optional).
subjectperiod仅验证基数以"1"开头的字段为必填项。
| 基数 | 是否必填? |
|---|---|
| 否 |
| 是 |
常见错误:将Encounter的或设为必填项。它们的基数是0..1(可选)。
subjectperiodValue Sets (Enum Values)
值集(枚举值)
Invalid enum values must return .
422 Unprocessable Entity无效的枚举值必须返回。
422 Unprocessable EntityPatient.gender
Patient.gender
male | female | other | unknownmale | female | other | unknownObservation.status
Observation.status
registered | preliminary | final | amended | corrected | cancelled | entered-in-error | unknownregistered | preliminary | final | amended | corrected | cancelled | entered-in-error | unknownEncounter.status
Encounter.status
planned | arrived | triaged | in-progress | onleave | finished | cancelled | entered-in-error | unknownplanned | arrived | triaged | in-progress | onleave | finished | cancelled | entered-in-error | unknownEncounter.class (Common Codes)
Encounter.class(常用编码)
| Code | Display | Use |
|---|---|---|
| ambulatory | Outpatient visits |
| inpatient encounter | Hospital admissions |
| emergency | Emergency department |
| virtual | Telehealth |
| 编码 | 显示名称 | 使用场景 |
|---|---|---|
| ambulatory | 门诊就诊 |
| inpatient encounter | 住院收治 |
| emergency | 急诊科室 |
| virtual | 远程医疗 |
Condition.clinicalStatus
Condition.clinicalStatus
active | recurrence | relapse | inactive | remission | resolvedactive | recurrence | relapse | inactive | remission | resolvedCondition.verificationStatus
Condition.verificationStatus
unconfirmed | provisional | differential | confirmed | refuted | entered-in-errorunconfirmed | provisional | differential | confirmed | refuted | entered-in-errorMedicationRequest.status
MedicationRequest.status
active | on-hold | cancelled | completed | entered-in-error | stopped | draft | unknownactive | on-hold | cancelled | completed | entered-in-error | stopped | draft | unknownMedicationRequest.intent
MedicationRequest.intent
proposal | plan | order | original-order | reflex-order | filler-order | instance-order | optionproposal | plan | order | original-order | reflex-order | filler-order | instance-order | optionBundle.type
Bundle.type
document | message | transaction | transaction-response | batch | batch-response | history | searchset | collectiondocument | message | transaction | transaction-response | batch | batch-response | history | searchset | collectionValidation Pattern
验证模式
Python/FastAPI:
python
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
def operation_outcome(severity: str, code: str, diagnostics: str):
return {
"resourceType": "OperationOutcome",
"issue": [{"severity": severity, "code": code, "diagnostics": diagnostics}]
}
VALID_OBS_STATUS = {"registered", "preliminary", "final", "amended",
"corrected", "cancelled", "entered-in-error", "unknown"}
@app.post("/Observation", status_code=201)
async def create_observation(data: dict):
if not data.get("status"):
return JSONResponse(status_code=422, content=operation_outcome(
"error", "required", "Observation.status is required"
), media_type="application/fhir+json")
if data["status"] not in VALID_OBS_STATUS:
return JSONResponse(status_code=422, content=operation_outcome(
"error", "value", f"Invalid status '{data['status']}'"
), media_type="application/fhir+json")
# ... create resourceTypeScript/Express:
typescript
const VALID_OBS_STATUS = new Set(['registered', 'preliminary', 'final', 'amended',
'corrected', 'cancelled', 'entered-in-error', 'unknown']);
app.post('/Observation', (req, res) => {
if (!req.body.status) {
return res.status(422).contentType('application/fhir+json')
.json(operationOutcome('error', 'required', 'Observation.status is required'));
}
if (!VALID_OBS_STATUS.has(req.body.status)) {
return res.status(422).contentType('application/fhir+json')
.json(operationOutcome('error', 'value', `Invalid status '${req.body.status}'`));
}
// ... create resource
});Pydantic v2 Models (use , not ):
Literalconst=Truepython
from typing import Literal
from pydantic import BaseModel
class Patient(BaseModel):
resourceType: Literal["Patient"] = "Patient"
id: str | None = None
gender: Literal["male", "female", "other", "unknown"] | None = NonePython/FastAPI:
python
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
def operation_outcome(severity: str, code: str, diagnostics: str):
return {
"resourceType": "OperationOutcome",
"issue": [{"severity": severity, "code": code, "diagnostics": diagnostics}]
}
VALID_OBS_STATUS = {"registered", "preliminary", "final", "amended",
"corrected", "cancelled", "entered-in-error", "unknown"}
@app.post("/Observation", status_code=201)
async def create_observation(data: dict):
if not data.get("status"):
return JSONResponse(status_code=422, content=operation_outcome(
"error", "required", "Observation.status is required"
), media_type="application/fhir+json")
if data["status"] not in VALID_OBS_STATUS:
return JSONResponse(status_code=422, content=operation_outcome(
"error", "value", f"Invalid status '{data['status']}'"
), media_type="application/fhir+json")
# ... create resourceTypeScript/Express:
typescript
const VALID_OBS_STATUS = new Set(['registered', 'preliminary', 'final', 'amended',
'corrected', 'cancelled', 'entered-in-error', 'unknown']);
app.post('/Observation', (req, res) => {
if (!req.body.status) {
return res.status(422).contentType('application/fhir+json')
.json(operationOutcome('error', 'required', 'Observation.status is required'));
}
if (!VALID_OBS_STATUS.has(req.body.status)) {
return res.status(422).contentType('application/fhir+json')
.json(operationOutcome('error', 'value', `Invalid status '${req.body.status}'`));
}
// ... create resource
});Pydantic v2模型(使用,而非):
Literalconst=Truepython
from typing import Literal
from pydantic import BaseModel
class Patient(BaseModel):
resourceType: Literal["Patient"] = "Patient"
id: str | None = None
gender: Literal["male", "female", "other", "unknown"] | None = NoneCoding Systems (URLs)
编码系统(URL)
| System | URL |
|---|---|
| LOINC | |
| SNOMED CT | |
| RxNorm | |
| ICD-10 | |
| v3-ActCode | |
| Observation Category | |
| Condition Clinical | |
| Condition Ver Status | |
| 系统 | URL |
|---|---|
| LOINC | |
| SNOMED CT | |
| RxNorm | |
| ICD-10 | |
| v3-ActCode | |
| Observation Category | |
| Condition Clinical | |
| Condition Ver Status | |
Common LOINC Codes (Vital Signs)
常用LOINC编码(生命体征)
| Code | Description |
|---|---|
| Heart rate |
| Systolic blood pressure |
| Diastolic blood pressure |
| Body temperature |
| Oxygen saturation (SpO2) |
| 编码 | 描述 |
|---|---|
| 心率 |
| 收缩压 |
| 舒张压 |
| 体温 |
| 血氧饱和度(SpO2) |
Data Type Patterns
数据类型模式
Coding (direct) vs CodeableConcept (wrapped)
Coding(直接使用)与CodeableConcept(包装使用)
Coding - Used by :
Encounter.classjson
{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB"}CodeableConcept - Used by , :
Observation.codeCondition.codejson
{"coding": [{"system": "http://loinc.org", "code": "8480-6"}], "text": "Systolic BP"}Coding - 用于:
Encounter.classjson
{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB"}CodeableConcept - 用于, :
Observation.codeCondition.codejson
{"coding": [{"system": "http://loinc.org", "code": "8480-6"}], "text": "Systolic BP"}Reference
Reference
json
{"reference": "Patient/123", "display": "John Smith"}json
{"reference": "Patient/123", "display": "John Smith"}Identifier
Identifier
json
{"system": "http://hospital.example.org/mrn", "value": "12345"}json
{"system": "http://hospital.example.org/mrn", "value": "12345"}Common Mistakes
常见错误
| Mistake | Correct Approach |
|---|---|
Making | Both are 0..1 (optional). Only |
Using CodeableConcept for | |
| Returning 400 for ETag mismatch | Use |
| Returning 400 for invalid enum values | Use |
| Forgetting Content-Type header | Always set |
| Missing Location header on create | Return |
| 错误做法 | 正确做法 |
|---|---|
将Encounter的 | 两者基数均为0..1(可选)。仅 |
为 | |
| ETag不匹配时返回400 | If-Match失败时返回 |
| 无效枚举值返回400 | 验证错误返回 |
| 忘记设置Content-Type请求头 | 始终设置 |
| 创建操作时缺少Location请求头 | 返回 |
Resource Structures
资源结构
For complete JSON examples of all resources, see references/resource-examples.md.
Quick reference for error responses:
json
{
"resourceType": "OperationOutcome",
"issue": [{"severity": "error", "code": "not-found", "diagnostics": "Patient/123 not found"}]
}所有资源的完整JSON示例,请查看**references/resource-examples.md**。
错误响应快速参考:
json
{
"resourceType": "OperationOutcome",
"issue": [{"severity": "error", "code": "not-found", "diagnostics": "Patient/123 not found"}]
}RESTful Endpoints
RESTful端点
POST /[ResourceType] # Create (returns 201 + Location header)
GET /[ResourceType]/[id] # Read
PUT /[ResourceType]/[id] # Update
DELETE /[ResourceType]/[id] # Delete (returns 204)
GET /[ResourceType]?param=value # Search (returns Bundle)
GET /metadata # CapabilityStatement
POST / # Bundle transaction/batchPOST /[ResourceType] # 创建(返回201 + Location请求头)
GET /[ResourceType]/[id] # 读取
PUT /[ResourceType]/[id] # 更新
DELETE /[ResourceType]/[id] # 删除(返回204)
GET /[ResourceType]?param=value # 搜索(返回Bundle)
GET /metadata # CapabilityStatement
POST / # Bundle事务/批量操作Conditional Operations
条件操作
If-Match (optimistic locking):
- Client sends:
If-Match: W/"1" - Mismatch returns
412 Precondition Failed
If-None-Exist (conditional create):
- Client sends:
If-None-Exist: identifier=http://mrn|12345 - Match exists: return existing (200)
- No match: create new (201)
If-Match(乐观锁):
- 客户端发送:
If-Match: W/"1" - 不匹配时返回
412 Precondition Failed
If-None-Exist(条件创建):
- 客户端发送:
If-None-Exist: identifier=http://mrn|12345 - 存在匹配项:返回现有资源(200)
- 无匹配项:创建新资源(201)
Reference Files
参考文档
For detailed guidance, see:
- Resource Examples: Complete JSON structures for Patient, Observation, Encounter, Condition, MedicationRequest, OperationOutcome, CapabilityStatement
- SMART on FHIR Authorization: OAuth flows, scope syntax (v1/v2), backend services, scope enforcement
- Pagination: Search result pagination, /
_countparameters, link relations_offset - Bundle Operations: Transaction vs batch semantics, atomicity, processing order
如需详细指导,请查看:
- 资源示例:Patient、Observation、Encounter、Condition、MedicationRequest、OperationOutcome、CapabilityStatement的完整JSON结构
- SMART on FHIR授权:OAuth流程、权限范围语法(v1/v2)、后端服务、权限范围强制执行
- 分页:搜索结果分页、/
_count参数、链接关系_offset - Bundle操作:事务与批量操作语义、原子性、处理顺序
Implementation Checklist
实施检查清单
- Set on all responses
Content-Type: application/fhir+json - Return and
meta.versionIdon resourcesmeta.lastUpdated - Return header on create:
Location/Patient/{id} - Return header:
ETagW/"{versionId}" - Use OperationOutcome for all error responses
- Validate required fields → 422 for missing
- Validate enum values → 422 for invalid
- Search returns Bundle with
type: "searchset"
- 所有响应设置
Content-Type: application/fhir+json - 资源返回和
meta.versionIdmeta.lastUpdated - 创建操作返回Location请求头:
/Patient/{id} - 返回ETag请求头:
W/"{versionId}" - 所有错误响应使用OperationOutcome
- 验证必填字段 → 缺失时返回422
- 验证枚举值 → 无效时返回422
- 搜索操作返回的Bundle
type: "searchset"
Quick Start Script
快速启动脚本
To scaffold a new FHIR API project with correct Pydantic v2 patterns:
bash
python scripts/setup_fhir_project.py my_fhir_apiCreates a FastAPI project with correct models, OperationOutcome helpers, and Patient CRUD endpoints.
使用正确的Pydantic v2模式搭建新的FHIR API项目:
bash
python scripts/setup_fhir_project.py my_fhir_api创建一个FastAPI项目,包含正确的模型、OperationOutcome辅助工具和Patient CRUD端点。