jpskill.com
🎨 デザイン コミュニティ

canvas-data-fetching

JSON:APIとSWRパターンを用いて、DrupalのコンテンツをCanvasコンポーネントで取得・表示し、コンテンツリストの作成や関連エンティティの検索を効率的に行うための、データ取得と連携処理を支援するSkill。

📜 元の英語説明(参考)

Fetch and render Drupal content in Canvas components with JSON:API and SWR patterns. Use when building content lists, integrating with SWR, or querying related entities. Covers JsonApiClient, DrupalJsonApiParams, relationship handling, and filter patterns.

🇯🇵 日本人クリエイター向け解説

一言でいうと

JSON:APIとSWRパターンを用いて、DrupalのコンテンツをCanvasコンポーネントで取得・表示し、コンテンツリストの作成や関連エンティティの検索を効率的に行うための、データ取得と連携処理を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o canvas-data-fetching.zip https://jpskill.com/download/9235.zip && unzip -o canvas-data-fetching.zip && rm canvas-data-fetching.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/9235.zip -OutFile "$d\canvas-data-fetching.zip"; Expand-Archive "$d\canvas-data-fetching.zip" -DestinationPath $d -Force; ri "$d\canvas-data-fetching.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して canvas-data-fetching.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → canvas-data-fetching フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

データ取得

SWR を使用したデータ取得

すべてのデータ取得には SWR を使用してください。これは、キャッシュ、再検証、およびクリーンなフックベースの API を提供します。

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function Profile() {
  const { data, error, isLoading } = useSWR(
    "https://my-site.com/api/user",
    fetcher,
  );

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;
  return <div>Hello, {data.name}!</div>;
}

JSON:API を使用した Drupal コンテンツの取得

Drupal からコンテンツ(例:記事、イベント、またはその他のコンテンツタイプ)を取得するには、drupal-canvas パッケージから自動構成された JsonApiClient を、クエリ構築のために DrupalJsonApiParams と組み合わせて使用します。

重要: Storybook ストーリーで JSON:API リソースをモックしないでください。データを取得するコンポーネントは、Storybook でロード中または空の状態を表示します。

import { getNodePath, JsonApiClient } from "drupal-canvas";
import { DrupalJsonApiParams } from "drupal-jsonapi-params";
import useSWR from "swr";

const Articles = () => {
  const client = new JsonApiClient();
  const { data, error, isLoading } = useSWR(
    [
      "node--article",
      {
        queryString: new DrupalJsonApiParams()
          .addSort("created", "DESC")
          .getQueryString(),
      },
    ],
    ([type, options]) => client.getCollection(type, options),
  );

  if (error) return "An error has occurred.";
  if (isLoading) return "Loading...";
  return (
    <ul>
      {data.map((article) => (
        <li key={article.id}>
          <a href={getNodePath(article)}>{article.title}</a>
        </li>
      ))}
    </ul>
  );
};

export default Articles;

addInclude を使用したリレーションシップの含める

関連エンティティ(例:画像、タクソノミー用語)が必要な場合は、addInclude を使用して、単一のリクエストでそれらを取得します。

JSON:API レスポンスで循環参照を避けてください。 SWR は、キャッシュされたデータを比較するためにディープイコールチェックを使用しますが、レスポンスに循環参照が含まれている場合、「再帰が多すぎます」というエラーで失敗します。

自己参照フィールドを含めないでください。 クエリされている同じエンティティタイプを参照するフィールド(例:記事クエリの field_related_articles)は、循環参照を作成します。記事 A は記事 B を参照し、記事 B は記事 A を参照し返します。同じタイプの関連コンテンツが必要な場合は、別のクエリで取得してください。

addFields を使用してレスポンスを制限します。 常に必要なフィールドのみを指定してください。これにより、パフォーマンスが向上し、循環参照の問題を回避できます。

const params = new DrupalJsonApiParams();
params.addSort("created", "DESC");
params.addInclude(["field_category", "field_image"]);

// Limit fields for each entity type
params.addFields("node--article", [
  "title",
  "created",
  "field_category",
  "field_image",
]);
params.addFields("taxonomy_term--categories", ["name"]);
params.addFields("file--file", ["uri", "url"]);

コンテンツリストコンポーネントの作成

コンテンツアイテムのリストを表示するコンポーネント(例:ニュースリスト、イベントカレンダー、またはリソースライブラリ)を構築する場合は、次のワークフローに従ってください。

セットアップゲート

JSON:API の検出またはコンテンツタイプのチェックを行う前に、ローカルセットアップを確認します。

  1. プロジェクトルートに .env ファイルが存在することを確認します。
  2. .env が存在する場合は、CANVAS_SITE_URL が設定されていることを確認します。CANVAS_JSONAPI_PREFIX が存在する場合はそれを読み取り、存在しない場合は jsonapi を使用します。
  3. HTTP リクエストを {CANVAS_SITE_URL}/{CANVAS_JSONAPI_PREFIX} に送信します。成功とは、HTTP 200 を意味します。
  4. リクエストが成功した場合は、Drupal データ取得を続行します。
  5. リクエストが失敗した場合(または必要な .env 値が欠落している場合)、ユーザーに次のことを確認します。
    • 今すぐ Drupal 接続を構成するか、
    • Drupal 取得の代わりに静的コンテンツで続行するか。
  6. ユーザーが接続を構成することを選択した場合は、.env の手順を提供します。
    • CANVAS_SITE_URL=<Drupal サイトの URL>
    • CANVAS_JSONAPI_PREFIX=jsonapi (オプション; デフォルトは jsonapi) 次に、ユーザーが .env を更新したことを確認するのを待ってから、リクエストを再度テストします。
  7. ユーザーが接続を構成しないことを選択した場合は、静的コンテンツで続行します。
  8. 接続のトラブルシューティングのために Vite 構成 (vite.config.*) を更新しないでください。接続の問題は、ビルドツールの変更ではなく、正しい .env 値と Drupal サイトの可用性によって解決する必要があります。

ステップ 1: リスト構造の分析

デザインを調べて、各リストアイテムに必要なデータを理解します。

  • どのフィールドが表示されますか(タイトル、日付、画像、カテゴリなど)?
  • アイテムはどのようにソートされますか(最新順、アルファベット順など)?
  • フィルターまたはページネーションはありますか?

ステップ 2: コンテンツタイプの特定またはリクエスト

コードを記述する前に、適切なコンテンツタイプが Drupal に存在することを確認します。

  1. ローカルの Drupal サイトの JSON:API エンドポイント(CANVAS_SITE_URL および CANVAS_JSONAPI_PREFIX 環境変数で構成)をチェックして、必要な構造に一致するコンテンツタイプを見つけます。セットアップゲートを通過した後、このチェックにはプレーンな fetch リクエストを使用します。

  2. 一致するコンテンツタイプが存在する場合は、それを使用し、どのフィールドが利用可能かをメモします。

  3. 一致するコンテンツタイプが存在しない場合は、停止してユーザーに作成を促します。以下を提供します。

    • 推奨されるコンテンツタイプ名
    • リストのデザインに基づく必要なフィールド構造

ステップ 3: コンポーネントの構築

JSON:API を使用してコンテンツを取得するコンテンツリストコンポーネントを作成します。コンテンツタイプに実際に存在するフィールドのみを使用してください。フィールドが存在することを確認せずに、存在すると想定しないでください。

フィルターの処理

リストにエンティティ参照フィールドに基づくフィルターが含まれている場合(例:カテゴリでフィルター、作成者でフィルター):

  • フィルターオプションをハードコードしないでください。 フィルターオプションは、JSON:API を使用して動的に取得する必要があります。
  • 各フィルターで使用可能なオプション(例:語彙のすべてのタクソノミー用語)を取得し、そのデータからフィルター UI を設定します。

これにより、フィルターが Drupal の実際のコンテンツと同期し、新しい op

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Data fetching

Data fetching with SWR

Use SWR for all data fetching. It provides caching, revalidation, and a clean hook-based API.

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function Profile() {
  const { data, error, isLoading } = useSWR(
    "https://my-site.com/api/user",
    fetcher,
  );

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;
  return <div>Hello, {data.name}!</div>;
}

Fetching Drupal content with JSON:API

To fetch content from Drupal (e.g., articles, events, or other content types), use the autoconfigured JsonApiClient from the drupal-canvas package combined with DrupalJsonApiParams for query building.

Important: Do not mock JSON:API resources in Storybook stories. Components that fetch data will display their loading or empty states in Storybook.

import { getNodePath, JsonApiClient } from "drupal-canvas";
import { DrupalJsonApiParams } from "drupal-jsonapi-params";
import useSWR from "swr";

const Articles = () => {
  const client = new JsonApiClient();
  const { data, error, isLoading } = useSWR(
    [
      "node--article",
      {
        queryString: new DrupalJsonApiParams()
          .addSort("created", "DESC")
          .getQueryString(),
      },
    ],
    ([type, options]) => client.getCollection(type, options),
  );

  if (error) return "An error has occurred.";
  if (isLoading) return "Loading...";
  return (
    <ul>
      {data.map((article) => (
        <li key={article.id}>
          <a href={getNodePath(article)}>{article.title}</a>
        </li>
      ))}
    </ul>
  );
};

export default Articles;

Including relationships with addInclude

When you need related entities (e.g., images, taxonomy terms), use addInclude to fetch them in a single request.

Avoid circular references in JSON:API responses. SWR uses deep equality checks to compare cached data, which fails with "too much recursion" errors when the response contains circular references.

Do not include self-referential fields. Fields that reference the same entity type being queried (e.g., field_related_articles on an article query) create circular references: Article A references Article B, which references back to Article A. If you need related content of the same type, fetch it in a separate query.

Use addFields to limit the response. Always specify only the fields you need. This improves performance and helps avoid circular reference issues:

const params = new DrupalJsonApiParams();
params.addSort("created", "DESC");
params.addInclude(["field_category", "field_image"]);

// Limit fields for each entity type
params.addFields("node--article", [
  "title",
  "created",
  "field_category",
  "field_image",
]);
params.addFields("taxonomy_term--categories", ["name"]);
params.addFields("file--file", ["uri", "url"]);

Creating content list components

When building a component that displays a list of content items (e.g., a news listing, event calendar, or resource library), follow this workflow:

Setup gate

Before any JSON:API discovery or content-type checks, verify local setup:

  1. Check that a .env file exists in the project root.
  2. If .env exists, verify CANVAS_SITE_URL is set. Read CANVAS_JSONAPI_PREFIX if present; otherwise, use jsonapi.
  3. Send an HTTP request to {CANVAS_SITE_URL}/{CANVAS_JSONAPI_PREFIX}. Success means HTTP 200.
  4. If the request is successful, continue with Drupal data fetching.
  5. If the request is unsuccessful (or required .env values are missing), ask the user whether they want to:
    • Configure Drupal connectivity now, or
    • Continue with static content instead of Drupal fetching.
  6. If the user chooses to configure connectivity, provide .env instructions:
    • CANVAS_SITE_URL=<their Drupal site URL>
    • CANVAS_JSONAPI_PREFIX=jsonapi (optional; defaults to jsonapi) Then wait for the user to confirm they updated .env, and test the request again.
  7. If the user chooses not to configure connectivity, proceed with static content.
  8. Do not update Vite config (vite.config.*) to troubleshoot connectivity. Connectivity issues must be resolved via correct .env values and Drupal site availability, not build tooling changes.

Step 1: Analyze the list structure

Examine the design to understand what data each list item needs:

  • What fields are displayed (title, date, image, category, etc.)?
  • How are items sorted (newest first, alphabetical, etc.)?
  • Are there filters or pagination?

Step 2: Identify or request the content type

Before writing code, verify that an appropriate content type exists in Drupal:

  1. Check the JSON:API endpoint of your local Drupal site (configured via CANVAS_SITE_URL and CANVAS_JSONAPI_PREFIX environment variables) to find a content type that matches the required structure. Use a plain fetch request for this check, after passing the Setup gate.

  2. If a matching content type exists, use it and note which fields are available.

  3. If no matching content type exists, stop and prompt the user to create one. Provide:

    • A suggested content type name
    • The required field structure based on the list design

Step 3: Build the component

Create the content list component using JSON:API to fetch content. Only use fields that actually exist on the content type—do not assume fields exist without verifying.

Handling filters

If the list includes filters based on entity reference fields (e.g., filter by category, filter by author):

  • Do not hardcode filter options. Filter options should be fetched dynamically using JSON:API.
  • Fetch the available options for each filter (e.g., all taxonomy terms in a vocabulary) and populate the filter UI from that data.

This ensures filters stay in sync with the actual content in Drupal and new options appear automatically without code changes.