• #nuxt
  • #routing
  • #spa
  • #url-design
開発未分類メモ

URLルーティング設計:クエリパラメータとパスベースの使い分け

結論

「同じデータの異なるビュー」を表現するならクエリパラメータ、「別々のコンテンツ」を表現するならパスベースを使う。

背景

人生計画シミュレーターを開発中、ナビゲーション状態をURLで共有できるようにしたいという要件が出た。

現在の画面構成:

  • 表示タブ > サマリー
  • 表示タブ > 支出詳細 > 生活費
  • 入力タブ > 家族構成 > 子ども1 > 教育方針

これをURLでどう表現するか?

2つの選択肢

パスベース

/life-plan/display/summary
/life-plan/display/expense-detail/living
/life-plan/input/family/child1/education

クエリパラメータ

/life-plan?tab=display&l1=summary
/life-plan?tab=display&l1=expense-detail&l2=living
/life-plan?tab=input&l1=family&l2=child1&l3=education

使い分けの基準

観点パスベースクエリパラメータ
意味別のページ・リソース同じページの状態
SEO個別にインデックスされる同一ページとして扱われる
適した用途ブログ記事、商品ページフィルター、ソート、ビュー切替
実装ファイル構造が複雑になりがち1コンポーネントで完結

パスベースが適しているケース

  • ブログの各記事(/blog/article-slug
  • ECサイトの商品ページ(/products/12345
  • 検索エンジンに個別にインデックスさせたいページ
  • それぞれが独立したコンテンツを持つ場合

クエリパラメータが適しているケース

  • 検索結果のフィルタリング(/search?category=books&sort=price
  • ダッシュボードの表示切替(/dashboard?view=chart
  • 同じデータを異なる角度から見るツール
  • アプリケーションの「状態」を共有したい場合

今回の判断

人生計画シミュレーターではクエリパラメータを採用した。

理由:

  1. サマリー、年次収支、支出詳細は「別々のコンテンツ」ではなく「同じライフプランデータの異なるビュー」
  2. 検索エンジンに個別ページとしてインデックスさせる必要がない
  3. 実装がシンプル(1つのページコンポーネントで状態管理)

実装方針

// Nuxtでの実装例
const route = useRoute()
const router = useRouter()

// URLからナビゲーション状態を復元
onMounted(() => {
  if (route.query.tab) activeTab.value = route.query.tab
  if (route.query.l1) selectedL1.value = route.query.l1
  // ...
})

// ナビゲーション変更時にURLを更新
watch([activeTab, selectedL1, selectedL2, selectedL3], () => {
  router.replace({
    query: {
      tab: activeTab.value,
      l1: selectedL1.value,
      l2: selectedL2.value || undefined,
      l3: selectedL3.value || undefined,
    }
  })
})

想定ユースケース:家族でのURL共有

今回の設計で想定しているシナリオを補足しておく。

現在の状態

  • クエリパラメータで表示状態(どのタブ・カテゴリを見ているか)を共有できる
  • 入力データ(収入額、生活費設定など)はURLには含まれない
  • データの永続化は未実装(将来的にはlocalStorageまたはサーバー保存)

想定シナリオ

  1. 夫がシミュレーターで自分の家族データを入力
  2. 「サマリー > 可処分所得」の画面を妻に見せたい
  3. URLをコピーして妻に送る
  4. 妻が同じ画面位置で開ける

ただし現状では、妻側にはデータがないため数値は表示されない。あくまで「どの画面を見ているか」だけが共有される。

将来の拡張

将来的にユーザー登録機能を実装する場合:

  1. ユーザー登録 → 家族データをサーバーに保存
  2. 家族招待 → 妻をユーザーとして招待し、同じ家族データを共有
  3. URL共有 → クエリパラメータで「どの画面を見ているか」を伝える

この構成でも、クエリパラメータによるナビゲーション状態の共有は有効。データの永続化とビュー状態の共有は別の問題であり、今回のクエリパラメータ設計は将来の拡張と矛盾しない。

まとめ

URLルーティングの設計は「このURLが何を表しているか」で決める。

  • リソース(記事、商品、ユーザーページ)→ パスベース
  • 状態(フィルター、ビュー、ナビゲーション位置)→ クエリパラメータ

迷ったら「検索エンジンにこのURLを個別ページとしてインデックスさせたいか?」と問いかけてみるとよい。