4. FHIR 资源模型与 RESTful API
FHIR 之所以能成为跨机构医疗数据交换的主流标准,核心在于它把医疗数据抽象为“资源(Resource)”,并用一套统一的 RESTful 接口来读写这些资源。理解 FHIR,本质上要同时理解两件事:资源模型描述“数据长什么样”,RESTful API 描述“数据怎么被访问和交换”。两者缺一不可。
一、资源模型:FHIR 的数据基本单元
在 FHIR 中,一切可独立交换的数据都是资源。每个资源都有统一的骨架:resourceType 标识资源类型,id 是资源在某个服务器内的唯一标识,meta 记录版本与最后更新时间,text 可存放供人阅读的叙述性内容。除此之外,资源通过 Reference 相互引用,形成一张可导航的数据网络,而不是一棵封闭的树。
跨机构交换中最常用的核心资源包括:
- Patient(患者):描述接受医疗服务的个体,包含姓名、性别、出生日期、标识符(如身份证号、医保号、院内病案号)等。它是几乎所有临床资源的“锚点”。
- Encounter(就诊):描述一次具体的医疗服务接触,如门诊、住院、急诊。它把某段时间内发生的观察、诊断、用药等事件聚合在一起,是临床时间线的组织者。
- Observation(观察):描述对患者某项指标的测量或判断,如血压、血糖、体温、检验结果。它通常包含编码(code)、值(valueQuantity 或 valueCodeableConcept)、状态(status)和发生时间(effectiveDateTime)。
- Condition(病情/诊断)、MedicationRequest(用药请求)、DiagnosticReport(诊断报告) 等,则分别承载诊断、医嘱和报告类信息。
这些资源之间通过引用连接:Observation 通过 subject 指向 Patient,通过 encounter 指向 Encounter;Encounter 通过 subject 指向 Patient。这种引用关系决定了数据交换时的“抓取路径”——拿到一个患者,就能顺着引用拉取其全部就诊与观察记录。
二、RESTful API:资源的访问方式
FHIR 定义了一套基于 HTTP 的交互风格,核心操作与 HTTP 方法一一对应:
| 操作 | HTTP 方法 | 典型 URL | 说明 |
|---|---|---|---|
| 读取 | GET | /Patient/123 | 按 id 读取单个资源 |
| 搜索 | GET | /Observation?patient=123&code=8867-4 | 按条件查询资源集合 |
| 创建 | POST | /Patient | 提交新资源,服务器分配 id |
| 更新 | PUT | /Patient/123 | 整体替换指定资源 |
| 删除 | DELETE | /Patient/123 | 删除或标记资源 |
搜索是跨机构交换中使用最频繁的交互。FHIR 为每种资源定义了标准搜索参数,例如 Patient 支持 identifier、name、birthdate;Observation 支持 patient、code、date。搜索返回的是一个 Bundle 资源,类型为 searchset,其中 entry 数组承载匹配结果,total 表示总数,link 中的 next 用于分页。
三、交互设计:从单次调用到完整交换
实际工程中,一次跨机构数据交换往往不是单次请求,而是一组有依赖关系的调用。以“从协作医院拉取某患者近一个月的血糖观察记录”为例,典型交互链如下:
- 用患者标识符搜索:
GET /Patient?identifier=医保号,从返回 Bundle 中取出 Patient.id。 - 用 Patient.id 搜索观察:
GET /Observation?patient=Patient.id&code=2339-0&date=ge2024-05-01。 - 若需要就诊上下文,再按
encounter引用回查 Encounter 资源。
这条链的关键在于:每一步的输入来自上一步的输出,且必须处理“未找到”“多条匹配”“分页未取完”等边界情况。设计时通常要求:搜索命中多条时按 meta.lastUpdated 或业务规则选定主记录;分页时循环跟随 next 链接直到取完。
identifier 搜索而非姓名,因为姓名在不同机构间重名率高,而医保号、身份证号等标识符具有更强的唯一性。四、资源引用与数据完整性
FHIR 资源之间的引用有两种常见形态:相对引用(如 Patient/123)和绝对引用(如 https://hospital-a.example/fhir/Patient/123)。跨机构交换时,绝对引用能明确指向数据来源,但会暴露内部地址;相对引用更简洁,但需要交换双方约定基础 URL。工程上常采用“相对引用 + 交换时重写”的策略,在网关层统一替换为对端可解析的地址。
此外,资源中的 status 字段不可忽视。Observation 的 status 可为 registered、preliminary、final、amended、cancelled,只有 final 或 amended 的结果才应被视为可用于临床决策。交换时若忽略状态过滤,可能把未审核的中间结果当作最终结论,造成误判。
五、工程实现要点
在真实网关或集成引擎中实现上述交互时,需要关注以下几点。第一,认证与授权:FHIR 服务器通常要求 OAuth 2.0 的 Bearer Token,跨机构场景还需 SM 2 或 TLS 双向认证保障传输安全。第二,版本与并发:更新资源时可通过 If-Match 携带 ETag,避免覆盖他人修改。第三,Bundle 批处理:当需要一次提交多个资源时,可使用 Bundle.type=batch 或 transaction,服务器按条目逐一处理并返回结果,减少往返次数。第四,错误处理:FHIR 用 OperationOutcome 资源描述错误,包含 issue.severity、issue.code 和 diagnostics,调用方应解析该资源而非仅看 HTTP 状态码。
GET /Observation?patient=123&code=2339-0&date=ge2024-05-01
Accept: application/fhir+json
Authorization: Bearer <token>
HTTP/1.1 200 OK
Content-Type: application/fhir+json
{
"resourceType": "Bundle",
"type": "searchset",
"total": 2,
"entry": [
{
"resource": {
"resourceType": "Observation",
"id": "obs-001",
"status": "final",
"code": { "coding": [{ "system": "http://loinc.org", "code": "2339-0" }] },
"subject": { "reference": "Patient/123" },
"effectiveDateTime": "2024-05-10T08:30:00+08:00",
"valueQuantity": { "value": 6.1, "unit": "mmol/L" }
}
}
]
}
这段示例展示了搜索返回的 Bundle 结构:total 为 2 表示共两条匹配,entry 中每条包含一个 Observation 资源,其 status 为 final,code 使用 LOINC 编码,valueQuantity 给出数值与单位。调用方应遍历 entry,提取所需字段,并检查 link 中是否存在 next 以决定是否继续分页。
CodeableConcept 的多编码能力同时携带本地码与标准码。总结来看,FHIR 资源模型提供了标准化的数据结构和引用关系,RESTful API 提供了统一的访问方式,而交互设计则决定了这些能力能否在跨机构场景中稳定落地。掌握 Patient、Encounter、Observation 三类核心资源的字段含义、引用方向和搜索参数,是构建任何 FHIR 交换链路的基础。