2026/06/14

CSVダウンロードを列順に依存させない設計

CSVAPI設計データ設計

2026/06/14 · CSV / API設計 / データ設計

CSVダウンロードを列順に依存させない設計

CSVの値は列位置に依存します。だからこそ、UIやAPIの契約を列番号にせず、安定したプロパティIDとヘッダー名を境界に置くのが扱いやすい設計です。

結論

「CSVを完全に順序非依存にする」という表現は正確ではありません。CSVは行内の値を区切り文字で並べる形式なので、最終的なファイル上では列順が意味を持ちます。

ただし、アプリケーション設計としては列順への依存を境界の外へ追いやれます。ユーザーには nameemailcreated_at のような安定したプロパティIDで項目を選ばせ、CSVを書き出す直前にだけ列順へ変換します。CSVの1行目には必ずヘッダーを出し、取り込み側は列番号ではなくヘッダー名でマッピングします。

言い方としては、「CSVの列順を契約にしない」よりも、「API/UI上の契約はプロパティID、CSV上の契約はヘッダー名、列順はユーザー指定の表示順」とするほうが誤解が少ないです。

設計の境界

UI ユーザーは安定したプロパティIDで出力項目を選ぶ。並び順は表示上の希望として扱う。
サーバー 選択IDを検証し、出力直前に列定義へ変換する。表示名と内部キーを分ける。
CSV 1行目にヘッダーを出す。以降の行は、そのヘッダー順に値を並べる。

なぜ列番号を契約にしないのか

列番号を契約にすると、出力項目の追加、削除、並び替え、表示名変更がすぐに破壊的変更になります。とくに「3列目がメールアドレス」のような暗黙の取り決めは、UIの改善やユーザーごとの出力項目選択と相性が悪いです。

一方で、プロパティIDを契約にすると、表示上の順序は自由に変えられます。CSVへ落とす段階で fieldnames のような列順リストを作り、そこに辞書形式のデータを流し込むモデルにできます。

name email created_at
サンプル利用者A user-a@example.com 2026-06-14
サンプル利用者B user-b@example.com 2026-06-15

この例ではCSVの列順自体は存在します。しかし、再利用側が email というヘッダーで値を読むなら、メールアドレス列が2列目か3列目かは本質的な契約ではなくなります。

契約を3つに分ける

API / UI

プロパティID

nameemail のような内部キーを保存する。表示名が変わっても壊れにくい。

CSV

ヘッダー名

ファイルの1行目に項目名または項目IDを出す。取り込み側は列番号ではなくヘッダーで対応付ける。

表示

列順

列順はユーザーが見たい順番として扱う。契約ではなく、書き出し時の表現に寄せる。

実装方針

  1. 出力可能な項目を、内部キー、表示名、型、権限、CSVヘッダー名を持つ列定義として管理する。
  2. UIでは列定義の内部キーだけを選択状態として保存する。
  3. サーバーでは受け取った内部キーを許可リストで検証する。
  4. CSV出力直前に、選択された内部キーの順番から fieldnames 相当の列順を作る。
  5. 1行目にはヘッダーを必ず出す。ヘッダーに表示名を使う場合でも、内部処理のキーとは分ける。
  6. インポートや再利用の処理では、列番号ではなくヘッダー名で値を取得する。

ポイントは、CSVの制約をなくそうとしないことです。CSVは最後に「順番を持つ表現」へ変換されます。その手前の設計をプロパティID中心にしておけば、変更に強いダウンロード機能になります。

根拠として使いやすい資料

この設計の説明には、次の公開資料が使いやすいです。

設計チェックリスト

  • ユーザーの選択値は表示名ではなく安定したプロパティIDで保存する。
  • CSVの1行目には項目名または項目IDを必ず出す。
  • 取り込み側は列番号ではなくヘッダー名でマッピングする。
  • 表示名変更に備えて、内部キー、CSVヘッダー名、画面表示名を分ける。
  • 列順は契約ではなく、ユーザー指定の表示順として扱う。
  • 未知のプロパティIDや権限外の項目はサーバー側で拒否する。

まとめ

CSVそのものは順序を持つ形式です。したがって、「順序非依存なCSV」を作るのではなく、「列順に依存しない利用契約」を設計するのが現実的です。

API/UIではプロパティIDを使い、CSVではヘッダー名を出し、列順はユーザーが指定する表示順として扱う。この分離をしておくと、柔軟なCSVダウンロードを実装しても、後続の取り込みや再利用が壊れにくくなります。