mcpField
F
fhir-developer-skill

fhir-developer-skill

github.com/anthropics开发431665 次安装9 周前更新
代码仓库

关于 fhir-developer-skill

fhir-developer-skill 为实现 FHIR R4 API 的开发者提供参考规范和代码模式,涵盖资源校验、REST 操作及常见响应约定。还包含 FastAPI 项目脚手架脚本。

主要功能

  1. 01FHIR R4 必填字段与枚举参考
  2. 02REST 状态码和响应规范
  3. 03Coding 与 CodeableConcept 示例
  4. 04FastAPI 项目脚手架脚本

适用场景

  1. 01检查资源字段与枚举校验
  2. 02实现 FHIR 错误响应
  3. 03搭建 FastAPI FHIR 项目

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anthropics/healthcare --skill fhir-developer-skill

安装后在 Claude Code 中输入/fhir-developer-skill确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
bundles.md
pagination.md
resource-examples.md
smart-auth.md
scripts/
setup_fhir_project.py

详细介绍

FHIR 开发者技能

快速参考

HTTP 状态码
代码使用场景
200 OK读取、更新或搜索成功
201 Created创建成功(包含 Location 标头)
204 No Content删除成功
400 Bad RequestJSON 格式错误,或 resourceType 错误
401 Unauthorized缺少、过期、已撤销或格式错误的令牌(RFC 6750)
403 Forbidden令牌有效,但权限范围不足
404 Not Found资源不存在
412 Precondition FailedIf-Match ETag 不匹配(不是 400!)
422 Unprocessable Entity缺少必填字段、枚举值无效或违反业务规则
各资源的必填字段(FHIR R4)
资源必填字段其他所有字段
Patient(无)全部可选
Observationstatus、code可选
Encounterstatus、class可选(包括 subject、period)
Conditionsubject可选(包括 code、clinicalStatus)
MedicationRequeststatus、intent、medication[x]、subject可选
Medication(无)全部可选
Bundletype可选

必填字段与可选字段(重要)

仅将基数以“1”开头的字段视为必填。

基数是否必填?
0..1、0..*否
1..1、1..*是

常见错误:将 subject 或 period 设为 Encounter 的必填字段。它们的基数是 0..1(可选)。


值集(枚举值)

枚举值无效时,必须返回 422 Unprocessable Entity。

Patient.gender

male | female | other | unknown

Observation.status

registered | preliminary | final | amended | corrected | cancelled | entered-in-error | unknown

Encounter.status

planned | arrived | triaged | in-progress | onleave | finished | cancelled | entered-in-error | unknown

Encounter.class(常见代码)
代码显示名称用途
AMB门诊门诊就诊
IMP住院就诊住院治疗
EMER急诊急诊科
VR虚拟远程医疗
Condition.clinicalStatus

active | recurrence | relapse | inactive | remission | resolved

Condition.verificationStatus

unconfirmed | provisional | differential | confirmed | refuted | entered-in-error

MedicationRequest.status

active | on-hold | cancelled | completed | entered-in-error | stopped | draft | unknown

MedicationRequest.intent

proposal | plan | order | original-order | reflex-order | filler-order | instance-order | option

Bundle.type

document | message | transaction | transaction-response | batch | batch-response | history | searchset | collection


验证模式

Python/FastAPI:

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 resource

TypeScript/Express:

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 模型(使用 Literal,不要使用 const=True):

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 = None

编码系统(URL)

系统URL
LOINChttp://loinc.org
SNOMED CThttp://snomed.info/sct
RxNormhttp://www.nlm.nih.gov/research/umls/rxnorm
ICD-10http://hl7.org/fhir/sid/icd-10
v3-ActCodehttp://terminology.hl7.org/CodeSystem/v3-ActCode
Observation Categoryhttp://terminology.hl7.org/CodeSystem/observation-category
Condition Clinicalhttp://terminology.hl7.org/CodeSystem/condition-clinical
Condition Ver Statushttp://terminology.hl7.org/CodeSystem/condition-ver-status
常见 LOINC 代码(生命体征)
代码描述
8867-4心率
8480-6收缩压
8462-4舒张压
8310-5体温
2708-6血氧饱和度(SpO2)

数据类型模式

Coding(直接)与 CodeableConcept(包装)

Coding - 用于 Encounter.class:

{"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB"}

CodeableConcept - 用于 Observation.code、Condition.code:

{"coding": [{"system": "http://loinc.org", "code": "8480-6"}], "text": "Systolic BP"}
参考
{"reference": "Patient/123", "display": "John Smith"}
标识符
{"system": "http://hospital.example.org/mrn", "value": "12345"}

常见错误

错误正确做法
将 Encounter 上的 subject 或 period 设为必填两者均为 0..1(可选)。只有 status 和 class 是必填项
将 CodeableConcept 用于 Encounter.classclass 直接使用 Coding:{"system": "...", "code": "AMB"}
ETag 不匹配时返回 400对 If-Match 失败使用 412 Precondition Failed
枚举值无效时返回 400对验证错误使用 422 Unprocessable Entity
忘记 Content-Type 标头始终设置 Content-Type: application/fhir+json
创建时缺少 Location 标头返回 Location: /Patient/{id},状态为 201 Created

资源结构

如需所有资源的完整 JSON 示例,请参阅 references/resource-examples.md。

错误响应速查:

{
  "resourceType": "OperationOutcome",
  "issue": [{"severity": "error", "code": "not-found", "diagnostics": "Patient/123 not found"}]
}

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/batch

条件操作

If-Match(乐观锁):

  • 客户端发送:If-Match: W/"1"
  • 不匹配时返回 412 Precondition Failed

If-None-Exist(条件创建):

  • 客户端发送:If-None-Exist: identifier=http://mrn|12345
  • 存在匹配项:返回现有资源(200)
  • 无匹配项:创建新资源(201)

参考文件

如需详细指南,请参阅:

  • 资源示例:Patient、Observation、Encounter、Condition、MedicationRequest、OperationOutcome、CapabilityStatement 的完整 JSON 结构
  • SMART on FHIR 授权:OAuth 流程、作用域语法(v1/v2)、后端服务、作用域强制执行
  • 分页:搜索结果分页、_count/_offset 参数、链接关系
  • Bundle 操作:事务与批处理语义、原子性、处理顺序

实现清单

  1. 在所有响应中设置 Content-Type: application/fhir+json
  2. 在资源中返回 meta.versionId 和 meta.lastUpdated
  3. 创建时返回 Location 标头:/Patient/{id}
  4. 返回 ETag 标头:W/"{versionId}"
  5. 对所有错误响应使用 OperationOutcome
  6. 验证必填字段 → 缺失时返回 422
  7. 验证枚举值 → 无效时返回 422
  8. 搜索返回包含 type: "searchset" 的 Bundle

快速启动脚本

如需使用正确的 Pydantic v2 模式搭建新的 FHIR API 项目:

python scripts/setup_fhir_project.py my_fhir_api

创建一个 FastAPI 项目,其中包含正确的模型、OperationOutcome 辅助函数和 Patient CRUD 端点。

评论

支持 Markdown