はじめに
医療情報システムの相互運用性規格として注目される HL7 FHIR。日本では JAMI(日本医療情報学会)から JP Core 実装ガイドが公開されています。
しかし、いざ仕様書を開いてみると
- ページが大量にあって、どこから読めばいいか分からない
- プロファイル詳細の表が出てきても、何を意味するのか分からない
- リンクをクリックしても、さらに別の表が出てきて迷子になる
必要があってFHIRを勉強しようと思いましたが完全に迷子です。本記事は、AIの力を借りて何をどう読めばよいかを、最小限の範囲で整理したものです。
対象読者:
- FHIR/JP Core の存在は知っているが、仕様書を開いて挫折した人
取り扱う範囲:
- 総合ガイダンス
- Patient プロファイル(1つだけ)
- REST API の基本的な GET/POST サンプル
全体を網羅することよりも、「次に自分で読み進められる足場」を作ることを目的にしています。
1. 結論: 最初に読むべき順番
仕様書全体は膨大ですが、初心者が最初に読むべきはこの順番です。
| 順番 | ページ | 所要時間の目安 |
|---|---|---|
| 1 | 総合ガイダンス | 30分 |
| 2 | JP_Patient プロファイル | 1〜2時間 |
| 3 | MustSupport と Cardinality | 30分 |
| 4 | 欠損値の扱い | 30分 |
とりあえずPatient を先に読むことができればいいでしょう。MustSupport/Cardinality は抽象的なルールなので、Patient で具体例に触れれば後の理解が深まります。
2. 総合ガイダンス: 30分で読み終わる前提知識
URL: https://jpfhir.jp/fhir/core/1.2.0-a/guide-general.html
ここは2つのセクションだけ読めば十分ではないかと思います。
2-1. JP Core の立ち位置
JP Core は、HL7 FHIR R4 をベースに、日本国内向けの最小限の適合性要件を定めたものです。重要な性質が3つあります:
- 「最小限」がキーワード: JP Core 自体の制約は緩い。各病院・ベンダーは JP Core から派生したプロファイルを作って、自社向けに厳格化することが想定されている
- HL7 v2.5 との後方互換性なし: 既存システムとの連携には変換層が必要
- JAMI の WG が策定: 日本HL7協会の正式承認は得ていない(自己責任で利用)
この性質は頭に入れておくいいと思います。
2-2. SHALL / SHOULD / MAY の定義
仕様書全体で使われるキーワードです。RFC 2119 準拠で厳密に定義されています。読み飛ばさず、必ず押さえておきます。
| キーワード | 意味 |
|---|---|
| SHALL | 必ず実装しなければならない |
| SHALL NOT | 実装してはならない |
| SHOULD | 推奨(外す場合は熟慮必須) |
| SHOULD NOT | 非推奨(採用する場合は熟慮必須) |
| MAY | 任意(実装してもしなくてもよい) |
これ以降のセクション(2.1.3 実装ガイド定義 / 2.1.4 機械翻訳文章 / 2.1.5 質問先 / 2.1.6 主体)は今は保留です。実装フェーズに入ってから必要な部分だけ参照でいいのではないでしょうか。
特に「IP Statements(知的財産権)」のリンクの羅列は索引(リファレンス)であり、通読する場所ではありません。「薬剤コードは何を使うんだっけ?」と思った時に開く辞書として使います。
3. Patient プロファイル: ここから本番
URL: https://jpfhir.jp/fhir/core/1.2.0-a/StructureDefinition-jp-patient.html
3-1. 「プロファイル詳細」とは何か
ページの中ほどに「プロファイル詳細」というセクションがあり、6つのタブがある表が現れます。これがつまずきポイントです。
プロファイル詳細の正体: 「このリソースを送受信する時の契約書 ≒ テーブル定義書」 です。
データベース設計者の感覚で読み替えると、こうなります:
| FHIR 用語 | DB 設計の用語 |
|---|---|
| プロファイル詳細 | テーブル定義書(CREATE TABLE文 + 制約) |
| Patient リソース | テーブル(例: 患者テーブル) |
| 各要素(name, gender 等) | カラム |
| Cardinality(0..1 等) | NULL許容 / NOT NULL |
| Type(string, code 等) | データ型 |
| Binding | CHECK 制約 / 外部マスタ参照 |
| Flags(?!, Σ, C) | 特殊な制約や挙動のメモ |
3-2. 6つのタブの使い分け
| タブ | 何が見える | いつ使うか |
|---|---|---|
| Differential Table | FHIR 標準からの差分だけ | JP Core が標準から何を変えたか知りたい時 |
| Key Elements Table | 重要な要素だけ | 全体像を素早く掴みたい時 |
| Snapshot Table | 全要素の完全な一覧 | 実装時に一番よく使う |
| Terminology Bindings | コードセットのバインディング | マスタ設計時 |
| Constraints | 追加の制約 | バリデーション実装時 |
| Statistics/References | 統計情報 | あまり使わない |
とりあえず Snapshot Table だけ見ればOKだと思います。これが「テーブル定義」に相当します。
3-3. Cardinality の読み方
Snapshot Table に出てくる 0..1 1..* などの記法:
| 記法 | 意味 | DB での例え |
|---|---|---|
0..1 |
任意の単一値 | NULL 許容カラム |
1..1 |
必須の単一値 | NOT NULL カラム |
0..* |
任意の複数値 | 0〜N 件の子テーブル |
1..* |
1件以上必須の複数値 | 1件以上必須の子テーブル |
ただし、FHIR 特有の落とし穴があります:
最小 Cardinality が 1 であることは、要素が存在することのみを要求しており、例えば、その要素は DataAbsentReason 拡張のみを持つかもしれない
つまり 1..1 でも、「値不明(unknown)」を示す dataAbsentReason 拡張だけが入っているケースがあり得ます。RDB の NOT NULL 感覚で設計すると事故になります。業務上の必須チェックはアプリ層で別途実装する必要があります。
3-4. Flags の意味
Snapshot Table の Flags 列に出てくる記号:
| 記号 | 意味 |
|---|---|
?! |
is-modifier(これを無視すると意味が変わる要素。無視禁止) |
Σ |
サマリ表示対象 |
C |
Constraint(追加制約あり) |
特に ?! は重要で、active=false の患者を active 無視で「アクティブ」として扱うと重大事故になります。
3-5. 共通基盤項目とリソース固有項目
Snapshot Table の最初の方に出てくる以下の要素は、FHIR の全リソース共通の基盤項目です:
id / meta / implicitRules / language / text / contained / extension
これらは Patient 固有ではなく、Encounter でも Observation でも同じです。Patient で一度理解すれば、他のリソースでも同じです。
「Patient 固有の項目」は、identifier name gender birthDate address などスクロールした先に出てきます。ここが本番です。
3-6. 読む時の3つの問い
各要素について、以下を意識すると整理しやすいです:
- 自社システムのどのテーブルのどのカラムに対応するか
- データ型・制約は一致しているか。ズレている場合は変換が必要か
-
この要素は連携で使うか、使わないか(例:
religionは日本では使わないことが多い)
4. サンプルJSONとプロファイル定義の違い
JP Core サイトには Patient のサンプル JSON もあります:
URL: https://jpfhir.jp/fhir/core/1.2.0-a/Patient-jp-patient-example-1.json.html
サンプル JSON の例
{
"resourceType": "Patient",
"id": "jp-patient-example-1",
"identifier": [{
"system": "urn:oid:1.2.392.100495.20.3.51.11311011",
"value": "00000010"
}],
"name": [{
"use": "official",
"text": "山田 太郎",
"family": "山田",
"given": ["太郎"]
}],
"gender": "male",
"birthDate": "1990-05-10"
}
→ gender というキーに "male" という値が入っている。普通の JSON です。
補足:StructureDefinition XML
<element id="Patient.gender">
<path value="Patient.gender"/>
<min value="0"/>
<max value="1"/>
<type>
<code value="code"/>
</type>
</element>
→ これはメタデータ。「Patient.gender というパスの要素は、最小0個・最大1個、型は code 型」という定義そのものを表現する XML。
5. FHIR サーバとのやり取り: 普通の REST API です
最後に「実際の通信」を見てみます。FHIR の本質はとてもシンプルで、HTTP メソッド + URL + JSON Body だけです。
5-1. URL の基本フォーマット
[ベースURL] / [リソースタイプ] / [リソースID] ? [検索条件]
例:
https://example-fhir.jp/fhir / Patient / jp-patient-example-1
↑ベースURL ↑リソース ↑リソースID
5-2. 5つの基本操作
| FHIR 操作 | HTTP メソッド + URL | SQL での例え |
|---|---|---|
| Read(1件取得) | GET /Patient/{id} |
SELECT * FROM patient WHERE id = ? |
| Search(検索) | GET /Patient?name=山田 |
WHERE name LIKE '%山田%' |
| Create(新規) |
POST /Patient (Body: JSON) |
INSERT |
| Update(更新) |
PUT /Patient/{id} (Body: JSON) |
UPDATE |
| Delete(削除) | DELETE /Patient/{id} |
DELETE |
5-3. 実例: Read
GET https://example-fhir.jp/fhir/Patient/jp-patient-example-1
Accept: application/fhir+json
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/fhir+json
{
"resourceType": "Patient",
"id": "jp-patient-example-1",
"identifier": [{ "system": "urn:oid:...", "value": "00000010" }],
"name": [{ "text": "山田 太郎", "family": "山田", "given": ["太郎"] }],
"gender": "male",
"birthDate": "1990-05-10"
}
5-4. 実例: Search
GET https://example-fhir.jp/fhir/Patient?name=山田
レスポンスは、**Bundle という「複数件結果ラッパー」**で返ります。これも FHIR リソースの1つ。
{
"resourceType": "Bundle",
"type": "searchset",
"total": 2,
"entry": [
{
"fullUrl": "https://example-fhir.jp/fhir/Patient/jp-patient-example-1",
"resource": { "resourceType": "Patient", "id": "...", "name": [...] }
},
{
"fullUrl": "https://example-fhir.jp/fhir/Patient/jp-patient-example-2",
"resource": { "resourceType": "Patient", "id": "...", "name": [...] }
}
]
}
検索パラメータは強力で、SQL を書かずに複雑な検索ができます:
GET /Patient?birthdate=ge1980-01-01&birthdate=le1989-12-31
GET /Patient?name=山田&gender=male
GET /Patient?_count=20&_offset=40
5-5. 実例: Create
POST https://example-fhir.jp/fhir/Patient
Content-Type: application/fhir+json
{
"resourceType": "Patient",
"identifier": [{ "system": "urn:oid:...", "value": "00000099" }],
"name": [{ "text": "佐藤 花子", "family": "佐藤", "given": ["花子"] }],
"gender": "female",
"birthDate": "1985-03-15"
}
レスポンス:
HTTP/1.1 201 Created
Location: https://example-fhir.jp/fhir/Patient/12345
{
"resourceType": "Patient",
"id": "12345",
"meta": {
"versionId": "1",
"lastUpdated": "2026-04-23T15:30:00+09:00"
},
"identifier": [{...}],
"name": [{...}],
"gender": "female",
"birthDate": "1985-03-15"
}
POST で送った JSON に、サーバが id と meta を付けて返してくるのが特徴です。
5-6. ステータスコードとエラー
| コード | 意味 |
|---|---|
| 200 OK | 取得・更新成功 |
| 201 Created | 新規作成成功 |
| 400 Bad Request | リクエスト JSON の形式エラー |
| 404 Not Found | リソースが存在しない |
| 422 Unprocessable Entity | プロファイル違反(必須項目欠損等) |
エラー時は OperationOutcome という専用リソースが返ります:
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "required",
"diagnostics": "Patient.identifier is required (1..*)"
}]
}
5-7. 公開テストサーバで実際に試せる
HAPI FHIR が無料で公開しているテストサーバがあります。ブラウザで開くだけで動きます:
このURLを叩いてみると、普通のREST APIで動くことがわかります。
まとめ
FHIR JP Core 仕様書の最初の壁を越えるための要点は以下の通りです:
- 最初に読むのは「総合ガイダンス」と「Patient プロファイル」だけでOK
- 総合ガイダンスは「JP Core の立ち位置」と「SHALL/SHOULD/MAY の定義」を押さえれば十分
- プロファイル詳細は 「テーブル定義書」 と読み替える
- Snapshot Table だけ見ればよく、
id〜extensionは共通基盤項目として読み飛ばせる - Cardinality は基本 NULL/NOT NULL と同じだが、
1..1でもdataAbsentReasonで空が許される点に注意 - FHIR API は普通の REST API。HTTP メソッド + URL + JSON Body