mcpField
U
using-ui-bundle-salesforce-data

using-ui-bundle-salesforce-data

github.com/forcedotcom開発1.1k3.6k 回インストール1 日前に更新
リポジトリ

using-ui-bundle-salesforce-data について

React UI bundle で `@salesforce/sdk-data` を使った Salesforce データアクセスを構築するスキルです。スキーマで確認した GraphQL によるレコード操作を優先し、REST の利用先を明示された対応エンドポイントに限定します。

主な機能

  1. 01Salesforce Data SDK の利用
  2. 02GraphQL スキーマに基づくフィールド確認
  3. 03GraphQL によるレコードの照会と変更
  4. 04ページネーションと項目アクセスの保護
  5. 05対応済み REST エンドポイントへの限定

活用シーン

  1. 01Salesforce UI bundle のレコードクエリ構築
  2. 02レコードの作成、更新、削除の追加
  3. 03GraphQL で不足する場合のレコードメタデータ取得

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/forcedotcom/sf-skills --skill using-ui-bundle-salesforce-data

インストール後、Claude Code で/using-ui-bundle-salesforce-dataを入力して読み込まれたか確認します。

同梱ファイルscripts/graphql-search.sh

詳細

Salesforce データアクセス

Data SDK の要件

Salesforce データへのアクセスには、必ず Data SDK(@salesforce/sdk-data)を使用してください。 SDK が認証、CSRF、ベース URL の解決を処理します。

import { createDataSDK, gql } from "@salesforce/sdk-data";
import type { ResponseTypeQuery } from "../graphql-operations-types";

const sdk = await createDataSDK();

// GraphQL for record queries/mutations (PREFERRED)
const response = await sdk.graphql?.<ResponseTypeQuery>(query, variables);

// REST for Connect REST, Apex REST, UI API (when GraphQL insufficient)
const res = await sdk.fetch?.("/services/apexrest/my-resource");

常にオプショナルチェーン(sdk.graphql?.()、sdk.fetch?.())を使用してください。サーフェスによっては、これらのメソッドが未定義の場合があります。

前提条件 — 開始前に確認してください

#要件確認方法不足している場合
1@salesforce/sdk-data がインストールされているUI バンドルディレクトリの package.json を確認する続行できません — ユーザーにインストールを依頼してください
2プロジェクトルートに schema.graphql があるファイルが存在するか確認するUI バンドルディレクトリから npm run graphql:schema を実行する
3カスタムオブジェクト/項目がデプロイされているgraphql-search.sh <Entity> を実行する — 出力がなければ未デプロイですユーザーにメタデータのデプロイと権限セットの割り当てを依頼してください

前提条件が満たされていない場合でも、コンポーネント、ルート、レイアウト、UI ロジックのひな型は作成できます。ただし、データには空の配列/null を使用し、クエリの場所に // TODO: add query after schema verification を記して、要件を解決して GraphQL を記述するために戻ることを計画に含めてください。スキーマのワークフローが完了するまでは、GraphQL クエリ文字列を記述しないでください。

サポート対象 API

許可されている API は以下のみです。 ここに記載されていないエンドポイントは使用できません。

APIメソッドエンドポイント/ユースケース
GraphQLsdk.graphqluiapi { } 名前空間を使用したすべてのレコードのクエリとミューテーション
UI API RESTsdk.fetch/services/data/v{ver}/ui-api/records/{id} — GraphQL では不十分な場合のレコードメタデータ
Apex RESTsdk.fetch/services/apexrest/{resource} — カスタムのサーバーサイドロジック、集計、複数ステップのトランザクション
Connect RESTsdk.fetch/services/data/v{ver}/connect/file/upload/config — ファイルアップロードの設定
Einstein LLMsdk.fetch/services/data/v{ver}/einstein/llm/prompt/generations — AI テキスト生成

サポート対象外:

  • Enterprise REST クエリエンドポイント(SOQL を使用する /services/data/v*/query)— プロキシレベルでブロックされています。レコードの読み取りには GraphQL を使用してください。サーバーサイドの SOQL 集計が必要な場合は Apex REST を使用してください。
  • Aura 対応 Apex(@AuraEnabled)— React UI バンドルから呼び出す手段のない LWC/Aura パターンです。
  • Chatter API(/chatter/users/me)— 代わりに GraphQL クエリで uiapi { currentUser { ... } } を使用してください。
  • 上記のサポート対象テーブルに記載されていない、その他すべての Salesforce REST エンドポイント。

選択方法:GraphQL と REST

必要な処理メソッド例
レコードのクエリ/変更sdk.graphqlAccount、Contact、カスタムオブジェクト
現在のユーザー情報sdk.graphqluiapi { currentUser { Id Name { value } } }
UI API のレコードメタデータsdk.fetch/ui-api/records/{id}
Connect RESTsdk.fetch/connect/file/upload/config
Apex RESTsdk.fetch/services/apexrest/auth/login
Einstein LLMsdk.fetch/einstein/llm/prompt/generations

レコード操作には GraphQL を優先してください。 ユースケースを GraphQL で処理できない場合に限り、REST を使用してください。


GraphQL の譲れないルール

これらのルールは、Salesforce GraphQL には標準の GraphQL とは異なるプラットフォーム固有の動作があるために設けられています。違反すると、実行時にエラーが発生しても通知されないことがあります。

  1. HTTP 200 は成功を意味しません — Salesforce は操作が失敗しても HTTP 200 を返します。レスポンス本文の errors 配列を必ず解析してください。

  2. スキーマを唯一の信頼できる情報源とする — クエリで使用する各エンティティ名、フィールド名、型は、スキーマ検索スクリプトで確認する必要があります。推測は禁物です。Salesforce のフィールド名では大文字と小文字が区別され、リレーションシップはポリモーフィックである場合があり、カスタムオブジェクトにはサフィックス(__c、__e)が付けられます。v60 以降で UI API に追加されたオブジェクトには、_Record サフィックスが付く場合があります(例:FeedItem ではなく FeedItem_Record)。

  3. すべてのレコードフィールド(読み取りクエリ)に @optional を付ける — Salesforce の項目レベルセキュリティ(FLS)により、ユーザーがフィールドに 1 つでもアクセスできない場合、クエリ全体が失敗します。@optional ディレクティブ(v65 以降)を使うと、サーバーはアクセスできないフィールドを省略し、失敗を回避できます。すべてのスカラー項目、親リレーションシップ、子リレーションシップに適用してください。値を使用するコードでは、オプショナルチェーン(?.)と Null 合体演算子(??)を使用する必要があります。

  4. 正しいミューテーション構文を使う — ミューテーションは uiapi(input: { allOrNone: true/false }) の下に記述します。uiapi { ... } とだけ記述してはいけません。allOrNone は必ず明示的に設定してください。出力フィールドには、子リレーションシップや参照フィールドをたどったフィールドを含められません。

  5. ページネーションを明示する — すべてのクエリに first: を必ず含めてください。省略すると、サーバーは通知せずにデフォルトで 10 件のレコードを返します。ページネーションが必要になる可能性のあるクエリには、pageInfo { hasNextPage endCursor } を含めてください。前方へのみページネーションできます(first/after)。last/before はサポートされていません。

  6. SOQL に基づく実行制限 — 1 リクエストあたりのサブクエリは最大 10 件、子から親へのたどりは最大 5 レベル、親から子へのたどりは最大 1 レベル(孫は不可)、サブクエリあたりのレコード数は最大 2,000 件です。クエリがこれらの制限を超える場合は、複数のリクエストに分割してください。

  7. 要求されたフィールドのみを使う — ユーザーが明示的に求めたフィールドのみを生成してください。追加のフィールドを加えてはいけません。

  8. 複合フィールド — フィルタリングまたは並べ替えでは、複合フィールドのラッパー(BillingAddress)ではなく、構成フィールド(例:BillingCity、BillingCountry)を使用してください。複合フィールドのラッパーは選択にのみ使用できます。


GraphQL のワークフロー

手順アクション主な出力
1スキーマを取得するschema.graphql が存在する
2エンティティを検索するフィールド名、型、リレーションシップを確認する
3クエリを生成する.graphql ファイルまたはインラインの gql タグ
4型を生成するgraphql-operations-types.ts
5検証するLint + codegen に合格する
手順 1:スキーマを取得する

schema.graphql ファイル(265K 行以上)が信頼できる唯一の情報源です。ファイルを直接開いたり解析したりしてはいけません。cat、less、head、tail、エディター、プログラムによるパーサーのいずれも使用しないでください。

前提条件 1~3(前提条件を参照)を確認してから、手順 2 に進んでください。

手順 2:エンティティのスキーマを検索する

ユーザーの意図を PascalCase の名前に対応付け(「accounts」→ Account)、sfdx-project フォルダー(プロジェクトルート)から検索スクリプトを実行してください。

bash scripts/graphql-search.sh Account
# Multiple entities:
bash scripts/graphql-search.sh Account Contact Opportunity

スクリプトはエンティティごとに、次の 7 つのセクションを出力します。

  1. 型定義 — クエリ可能なすべてのフィールドとリレーションシップ
  2. フィルターオプション — where: 条件で使用できるフィールド
  3. 並べ替えオプション — orderBy: で使用できるフィールド
  4. 作成ミューテーションラッパー — <Entity>CreateInput
  5. 作成ミューテーションフィールド — <Entity>CreateRepresentation(作成ミューテーションで受け付けられるフィールド)
  6. 更新ミューテーションラッパー — <Entity>UpdateInput
  7. 更新ミューテーションフィールド — <Entity>UpdateRepresentation(更新ミューテーションで受け付けられるフィールド)

スクリプトは最大 2 回まで実行できます。 それでもエンティティが見つからない場合はユーザーに確認してください。オブジェクトがデプロイされていない可能性があります。

エンティティの識別

候補が一致しない場合:

  • カスタムオブジェクトには __c サフィックス、プラットフォームイベントには __e を試してください
  • _Record サフィックスを試してください — v60+ で追加されたオブジェクトは <EntityName>_Record を使用する場合があります
  • それでも解決しない場合は、ユーザーに確認してください — 推測しないでください
反復的なイントロスペクション (最大 3 サイクル)
  1. イントロスペクション — 未解決の各エンティティに対してスクリプトを実行します
  2. フィールド — 型定義から要求されたフィールド名と型を抽出します
  3. 参照 — 参照フィールドを識別します。ポリモーフィック (複数の型) の場合は、インラインフラグメントを使用します。新たに発見されたエンティティ型を作業リストに追加します。
  4. 子リレーションシップ — Connection 型を識別します。子エンティティ型を作業リストに追加します。
  5. 未解決のエンティティが残っている場合は繰り返します (最大 3 サイクル)

強制終了: エンティティに対してデータが返されなかった場合は、停止してください — そのエンティティはデプロイされていない可能性があります。3 サイクル後も未知のエンティティが残っている場合は、ユーザーに確認してください。未確認のエンティティやフィールドを含むクエリを生成しないでください。

ステップ 3: クエリの生成

すべてのフィールド名は、ステップ 2 のスクリプト出力から必ず検証する必要があります。

読み取りクエリテンプレート
query QueryName($after: String) {
  uiapi {
    query {
      EntityName(
        first: 10
        after: $after
        where: { ... }
        orderBy: { ... }
      ) {
        edges {
          node {
            Id
            FieldName @optional { value }
            # Parent relationship (non-polymorphic)
            Owner @optional { Name { value } }
            # Parent relationship (polymorphic — use fragments)
            What @optional {
              ...WhatAccount
              ...WhatOpportunity
            }
            # Child relationship — max 1 level, no grandchildren
            Contacts @optional(first: 10) {
              edges { node { Name @optional { value } } }
            }
          }
        }
        pageInfo { hasNextPage endCursor }
      }
    }
  }
}

fragment WhatAccount on Account {
  Id
  Name @optional { value }
}
fragment WhatOpportunity on Opportunity {
  Id
  Name @optional { value }
}

消費側のコードは、欠落したフィールドに対して防御する必要があります:

const name = node.Name?.value ?? "";
const relatedName = node.Owner?.Name?.value ?? "N/A";
フィルタリング
# Implicit AND
Account(where: { Industry: { eq: "Technology" }, AnnualRevenue: { gt: 1000000 } })

# Explicit OR
Account(where: { OR: [{ Industry: { eq: "Technology" } }, { Industry: { eq: "Finance" } }] })

# NOT
Account(where: { NOT: { Industry: { eq: "Technology" } } })

# Date literal
Opportunity(where: { CloseDate: { eq: { value: "2024-12-31" } } })

# Relative date
Opportunity(where: { CloseDate: { gte: { literal: TODAY } } })

# Relationship filter (nested objects, NOT dot notation)
Contact(where: { Account: { Name: { like: "Acme%" } } })

# Polymorphic relationship filter
Account(where: { Owner: { User: { Username: { like: "admin%" } } } })

文字列の等価比較 (eq) は大文字と小文字を区別しません。15 文字と 18 文字のレコード ID の両方が受け付けられます。

並べ替え
Account(
  first: 10,
  orderBy: { Name: { order: ASC }, CreatedDate: { order: DESC } }
) { ... }

並べ替えでサポートされていない項目: 複数選択ピックリスト、リッチテキスト、長テキストエリア、暗号化フィールド。確定的な並べ替えのために、タイブレーカーとして Id を追加してください。

UpperBound ページネーション (v59+)

1 ページあたり 200 件を超える場合、または合計 4,000 件を超えるレコードの場合は、upperBound を使用します。設定する場合、first は 200~2000 でなければなりません。

Account(first: 2000, after: $cursor, upperBound: 10000) {
  edges { node { Id Name @optional { value } } }
  pageInfo { hasNextPage endCursor }
}
セミジョインとアンチジョイン

親の Id に対して inq (セミジョイン) または ninq (アンチジョイン) を使用して、子エンティティの条件で親エンティティをフィルタリングします。唯一の条件が子の存在である場合は、Id: { ne: null } を使用します。

query SemiJoinExample {
  uiapi {
    query {
      Account(where: {
        Id: {
          inq: {
            Contact: { LastName: { like: "Smith%" } }
            ApiName: "AccountId"
          }
        }
      }, first: 10) {
        edges { node { Id Name @optional { value } } }
      }
    }
  }
}

アンチジョインの場合は inq を ninq に置き換えます。制限事項: サブクエリに OR を含めることはできません、サブクエリに orderBy を含めることはできません、ジョインを互いにネストすることはできません。

現在のユーザー

標準のクエリパターンの代わりに、uiapi.currentUser (引数なし) を使用します:

query CurrentUser {
  uiapi { currentUser { Id Name { value } } }
}
フィールド値ラッパー

スキーマフィールドは型付きラッパーを使用します — .value 経由でアクセスします:

ラッパー型基になる型ラッパー型基になる型
StringValueStringBooleanValueBoolean
IntValueIntDoubleValueDouble
CurrencyValueCurrencyPercentValuePercent
DateTimeValueDateTimeDateValueDate
PicklistValuePicklistLongValueLong
IDValueIDTextAreaValueTextArea
EmailValueEmailPhoneNumberValuePhoneNumber
UrlValueUrl

すべてのラッパーは displayValue: String (toLabel()/format() を介してサーバー側でレンダリング) も公開します — クライアント側でフォーマットする代わりに UI 表示に使用してください。

Mutation テンプレート

API v66+ でミューテーションが GA になりました。操作は 作成、更新、削除 の 3 種類です。

# Create
mutation CreateAccount($input: AccountCreateInput!) {
  uiapi(input: { allOrNone: true }) {
    AccountCreate(input: $input) {
      Record { Id Name { value } }
    }
  }
}

# Update — must include Id
mutation UpdateAccount {
  uiapi(input: { allOrNone: true }) {
    AccountUpdate(input: { Id: "001xx000003GYkZAAW", Account: { Name: "New Name" } }) {
      Record { Id Name { value } }
    }
  }
}

入力制約:

  • 作成:必須フィールド(defaultedOnCreate の場合を除く)のみ。createable フィールドのみ指定でき、子リレーションは指定できません。参照フィールドは ApiName で設定します(例:AccountId)。
  • 更新:Id が必須です。updateable フィールドのみ指定でき、子リレーションは指定できません。
  • 削除:Id のみ指定します。
  • IdOrRef 型:更新と削除の入力における Id フィールドは IdOrRef 型を使用します。この型では、レコード ID のリテラル(例:"001xx...")またはミューテーションの連鎖参照("@{Alias}")を指定できます。作成入力の参照フィールド(例:AccountId)も、連鎖に @{Alias} を指定できます。
  • 生の値:カンマ、通貨記号、ロケール形式の書式設定は使用しないでください(例:"$80,000" ではなく 80000)。

出力制約:

  • 作成/更新:子リレーションと、ナビゲートした参照フィールド(ApiName メンバーのみ許可)を除外します。出力フィールド名は常に Record です。
  • 削除:Id のみです。

allOrNone のセマンティクス:

  • true(デフォルト)— すべての操作が成功するか、すべてロールバックされます。
  • false — 各操作は個別に成功しますが、依存する操作(@{alias} を使用する操作)は引き続きまとめてロールバックされます。
ミューテーションの連鎖

先行するミューテーションの Id を参照する @{alias} を使って、関連するミューテーションを連鎖させます。親子の作成には必須です(子のネストした作成はサポートされていません)。

mutation CreateAccountAndContact {
  uiapi(input: { allOrNone: true }) {
    AccountCreate(input: { Account: { Name: "Acme" } }) {
      Record { Id }
    }
    ContactCreate(input: { Contact: { LastName: "Smith", AccountId: "@{AccountCreate}" } }) {
      Record { Id }
    }
  }
}

ルール:クエリでは A が B より前にある必要があります。@{A} は常にミューテーション A の Id を参照します。連鎖元にできるのは Create または Delete のみです(Update は不可)。

削除ミューテーション

削除では汎用の RecordDeleteInput を使用します(エンティティ固有ではありません)。出力は Id のみで、Record フィールドはありません。

mutation DeleteAccount($id: ID!) {
  uiapi(input: { allOrNone: true }) {
    AccountDelete(input: { Id: $id }) {
      Id
    }
  }
}
オブジェクトのメタデータと選択リスト値

フィールドのメタデータまたは選択リスト値を取得するには、uiapi { objectInfos(...) } を使用します。apiNames または objectInfoInputs のどちらか一方を渡してください。両方を渡すことはできません。

// Object metadata
const GET_OBJECT_INFO = gql`
  query GetObjectInfo($apiNames: [String!]!) {
    uiapi {
      objectInfos(apiNames: $apiNames) {
        ApiName
        label
        labelPlural
        fields { ApiName label dataType updateable createable }
      }
    }
  }
`;

// Picklist values (use objectInfoInputs + inline fragment)
const GET_PICKLIST_VALUES = gql`
  query GetPicklistValues($objectInfoInputs: [ObjectInfoInput!]!) {
    uiapi {
      objectInfos(objectInfoInputs: $objectInfoInputs) {
        ApiName
        fields {
          ApiName
          ... on PicklistField {
            picklistValuesByRecordTypeIDs {
              recordTypeID
              picklistValues { label value }
            }
          }
        }
      }
    }
  }
`;
ステップ 4:型を生成する(codegen)

.graphql ファイルにクエリを記述した場合も、gql を使ってインラインで記述した場合も、クエリの作成後に TypeScript の型を生成します。

# Run from UI bundle dir
npm run graphql:codegen

出力先:src/api/graphql-operations-types.ts

生成される型の命名規則:

  • <OperationName>Query / <OperationName>Mutation — レスポンス型
  • <OperationName>QueryVariables / <OperationName>MutationVariables — 変数型

sdk.graphql を呼び出す際は、必ず生成された型をインポートして使用してください。

import type { GetAccountsQuery, GetAccountsQueryVariables } from "../graphql-operations-types";

const response = await sdk.graphql?.<GetAccountsQuery, GetAccountsQueryVariables>(GET_ACCOUNTS, variables);

Connection からノード型を抽出して型をすっきり記述するには、NodeOfConnection<T> を使用します。

import { type NodeOfConnection } from "@salesforce/sdk-data";

type AccountNode = NodeOfConnection<GetAccountsQuery["uiapi"]["query"]["Account"]>;
ステップ 5:検証とテスト
  1. Lint:UI バンドルディレクトリで npx eslint <file> を実行します
  2. codegen:UI バンドルディレクトリで npm run graphql:codegen を実行します
よくあるエラーパターン
エラーに含まれる文字列解決方法
Cannot query field / ValidationErrorフィールド名が誤っています — graphql-search.sh <Entity> を再実行します
Unknown type型名が誤っています — スクリプトを使ってエンティティ名が PascalCase であることを確認します
Unknown argument引数が誤っています — スクリプト出力の Filter/OrderBy セクションを確認します
invalid syntax / InvalidSyntaxエラーメッセージに従って構文を修正します
VariableTypeMismatch / UnknownTypeスキーマから正しい引数の型を確認します
invalid cross reference idエンティティが削除されています — 有効な Id を確認します
OperationNotSupportedオブジェクトの利用可否と API バージョンを確認します
is not currently available in mutation resultsミューテーション出力からフィールドを削除します
Cannot invoke JsonElement.isJsonObject()更新ミューテーションの Record 選択には API バージョン 64+ を使用します

PARTIAL の場合 ミューテーションがデータとエラーの両方を返す(部分的な成功)場合:アクセスできないフィールドを報告し、ミューテーション出力に含められないことを説明して、削除を提案します。変更前にユーザーの同意を待ってください。


UI バンドルへの統合(React)

統合パターンは 2 つあります。

パターン 1 — 外部の .graphql ファイル(複雑なクエリ)

.graphql ファイルごとに操作は 1 つです。 各ファイルには、query または mutation を 1 つだけ(フラグメントを含む)記述します。1 つのファイルに複数の操作をまとめないでください。

import { createDataSDK, type NodeOfConnection } from "@salesforce/sdk-data";
import MY_QUERY from "./query/myQuery.graphql?raw"; // ?raw suffix required
import type { GetMyDataQuery, GetMyDataQueryVariables } from "../graphql-operations-types";

const sdk = await createDataSDK();
const response = await sdk.graphql?.<GetMyDataQuery, GetMyDataQueryVariables>(MY_QUERY, variables);

.graphql ファイルを作成または変更した後、npm run graphql:codegen を実行して、型を src/api/graphql-operations-types.ts に生成します。

パターン 2 — インラインの gql タグ(シンプルなクエリ)

gql を使用する必要があります — 通常のテンプレート文字列では、ESLint のスキーマ検証を回避してしまいます。

import { createDataSDK, gql } from "@salesforce/sdk-data";
import type { GetAccountsQuery } from "../graphql-operations-types";

const GET_ACCOUNTS = gql`
  query GetAccounts {
    uiapi {
      query {
        Account(first: 10) {
          edges { node { Id Name @optional { value } } }
        }
      }
    }
  }
`;

const sdk = await createDataSDK();
const response = await sdk.graphql?.<GetAccountsQuery>(GET_ACCOUNTS);
エラー処理
// Strict (default) — any errors = failure
if (response?.errors?.length) {
  throw new Error(response.errors.map(e => e.message).join("; "));
}

// Tolerant — log errors, use available data
if (response?.errors?.length) {
  console.warn("GraphQL partial errors:", response.errors);
}

// Discriminated — fail only when no data returned
if (!response?.data && response?.errors?.length) {
  throw new Error(response.errors.map(e => e.message).join("; "));
}

const accounts = response?.data?.uiapi?.query?.Account?.edges?.map(e => e.node) ?? [];

REST API のパターン

GraphQL では不十分な場合は、sdk.fetch を使用します。許可リストの全容については、サポート対象の API テーブルを参照してください。

declare const __SF_API_VERSION__: string;
const API_VERSION = typeof __SF_API_VERSION__ !== "undefined" ? __SF_API_VERSION__ : "65.0";

// Connect — file upload config
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/connect/file/upload/config`);

// Apex REST (no version in path)
const res = await sdk.fetch?.("/services/apexrest/auth/login", {
  method: "POST",
  body: JSON.stringify({ email, password }),
  headers: { "Content-Type": "application/json" },
});

// UI API — record with metadata (prefer GraphQL for simple reads)
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/ui-api/records/${recordId}`);

// Einstein LLM
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/einstein/llm/prompt/generations`, {
  method: "POST",
  body: JSON.stringify({ promptTextorId: prompt }),
});

現在のユーザー:Chatter(/chatter/users/me)は使用しないでください。代わりに GraphQL を使用します。

const GET_CURRENT_USER = gql`
  query CurrentUser {
    uiapi { currentUser { Id Name { value } } }
  }
`;
const response = await sdk.graphql?.(GET_CURRENT_USER);

ディレクトリ構成

<project-root>/                              ← SFDX project root
├── schema.graphql                           ← grep target (lives here)
├── sfdx-project.json
├── scripts/graphql-search.sh                ← schema lookup script
└── force-app/main/default/uiBundles/<app-name>/  ← UI bundle dir
    ├── package.json                         ← npm scripts
    └── src/
コマンド実行場所理由
npm run graphql:schemaUI バンドルディレクトリUI バンドルの package.json にスクリプトがあるため
npm run graphql:codegenUI バンドルディレクトリGraphQL の型を生成するため
npx eslint <file>UI バンドルディレクトリeslint.config.js を読み込むため
bash scripts/graphql-search.sh <Entity>プロジェクトルートスキーマを検索するため

クイックリファレンス

スキーマの検索(プロジェクトルートから)

検索スクリプトを実行すると、関連するスキーマ情報をすべて 1 回で取得できます。

bash scripts/graphql-search.sh <EntityName>
スクリプトの出力セクション用途
型定義フィールド名、親子関係
フィルターオプションwhere: 条件
並べ替えオプションorderBy:
CreateRepresentation作成ミューテーションのフィールド一覧
UpdateRepresentation更新ミューテーションのフィールド一覧
エラーのカテゴリ
エラーに含まれる文字列解決方法
Cannot query fieldフィールド名が誤っています — graphql-search.sh <Entity> を実行し、型定義セクションに記載された正確な名前を使用してください
Unknown type型名が誤っています — graphql-search.sh <Entity> を実行し、正しいパスカルケースのエンティティ名を確認してください
Unknown argument引数名が誤っています — graphql-search.sh <Entity> を実行し、Filter または OrderBy セクションを確認してください
invalid syntaxエラーメッセージに従って構文を修正してください
validation errorフィールド名が誤っています — graphql-search.sh <Entity> を実行して確認してください
VariableTypeMismatchスキーマに従って引数の型を修正してください
invalid cross reference idエンティティが削除されています — 有効な Id を確認してください
チェックリスト
  • すべてのフィールド名を検索スクリプトで確認済み(ステップ 2)
  • すべてのレコードフィールド(読み取り)に @optional を適用済み
  • ミューテーションで uiapi(input: { allOrNone: ... }) ラッパーを使用
  • すべてのクエリで first: を指定
  • 使用側のコードでオプショナルチェーンを使用
  • レスポンス処理で errors 配列を確認
  • Lint が成功:npx eslint <file>

コメント