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. 02FHIR エラーレスポンスの実装
  3. 03FastAPI 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..*はい

よくある誤り:Encounter の subject または period を必須にすること。これらは 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 モデル(const=True ではなく Literal を使用):

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 のみです
Encounter.class に CodeableConcept を使用するclass は Coding を直接使用します:{"system": "...", "code": "AMB"}
ETag の不一致に対して 400 を返すIf-Match の失敗には 412 Precondition Failed を使用します
無効な enum 値に対して 400 を返す検証エラーには 422 Unprocessable Entity を使用します
Content-Type ヘッダーを忘れる常に Content-Type: application/fhir+json を設定します
作成時に Location ヘッダーがない201 Created とともに Location: /Patient/{id} を返します

リソース構造

すべてのリソースの完全な 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. enum 値を検証します → 無効な場合は 422
  8. 検索では type: "searchset" を含む Bundle を返します

クイックスタートスクリプト

正しい Pydantic v2 のパターンを使用して、新しい FHIR API プロジェクトをスキャフォールディングするには:

python scripts/setup_fhir_project.py my_fhir_api

正しいモデル、OperationOutcome ヘルパー、Patient CRUD エンドポイントを備えた FastAPI プロジェクトを作成します。

コメント