afv-library/skills/accessing-webapp-data/SKILL.md
k-j-kim 9ba064174a
feat: syncing webapp skills sync to afv @W-21338965@ (#57)
* feat: removing old webapp skills

* feat: adding sync of skills from webapps to afv

* feat: adding the first iteration of skills

* feat: pin template deps to latest npm versions and flatten skill folders

- Add pin-template-deps.js to resolve "*" deps to exact npm versions
- Integrate pinning into sync-template-skills npm script
- Remove check-template-skills-versions.js (no longer needed)
- Simplify workflow to single sync step
- Flatten skill output: one folder per skill with cleaned names

Made-with: Cursor

* fix: resolve skill validation errors

- Move .template-versions.json from skills/ to root
- Shorten skill names to meet 64-char limit:
  - salesforce-webapp-feature-micro-frontend-generating-micro-frontend-lwc → salesforce-webapp-micro-frontend-lwc
  - salesforce-webapp-feature-react-agentforce-conversation-client-integrating-agentforce-conversation-client → salesforce-webapp-agentforce-conversation-client
  - salesforce-webapp-feature-react-file-upload-implementing-file-upload → salesforce-webapp-react-file-upload
- Expand descriptions to meet 20-word minimum with trigger context

* Add webapp skills from template, sync script updates

- Rename skill folders from salesforce-webapp-* to *-webapp-* convention
- Update sync-template-skills.js: set SKILL.md front matter name to dest folder
- Remove sync-template-skills workflow and pin-template-deps script
- Add .synced-template-skills.json manifest, deploying-webapp-to-salesforce skill
- Replace salesforce-webapp-designing-webapp-ui-ux with designing-webapp-ui-ux

Made-with: Cursor

* Align SKILL.md front matter name with folder for all webapp skills

Made-with: Cursor

* Fix skill validation: description length and trigger context for configuring-webapp-metadata, creating-webapp

Made-with: Cursor

* Rename sync script to sync-webapp-skills, drop manifest file

- Rename sync-template-skills.js to sync-webapp-skills.js
- Update package.json script to sync-webapp-skills
- Remove .synced-template-skills.json creation and add to .gitignore

Made-with: Cursor

* Revert sync-react-b2e-sample and sync-react-b2x-sample to upstream version

Made-with: Cursor

* Sync script: pin b2e and b2x to latest, sync skills from template

- Pin both template packages to latest in sync-webapp-skills.js
- Update package.json / package-lock.json (b2x 1.109.0)
- Sync skills: managing-webapp-agentforce-conversation-client, bar-line-chart,
  remove building-webapp-analytics-charts and integrating-webapp-agentforce-conversation-client
- Minor skill content updates

Made-with: Cursor

* Remove interactive map, weather widget, and Unsplash skills (no longer in template)

Made-with: Cursor

---------

Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com>
2026-03-19 22:46:27 +05:30

6.3 KiB

name description paths
accessing-webapp-data Salesforce data access patterns. Use when adding or modifying any code that fetches data from Salesforce (records, Chatter, Connect API, etc.).
**/*.ts
**/*.tsx
**/*.graphql

Salesforce Data Access

Guidance for accessing Salesforce data from web apps. All Salesforce data fetches MUST use the Data SDK (@salesforce/sdk-data). The SDK provides authentication, CSRF handling, and correct base URL resolution — direct fetch or axios calls bypass these and are not allowed.

Mandatory: Use the Data SDK

Every Salesforce data fetch must go through the Data SDK. Obtain it via createDataSDK(), then use sdk.graphql?.() or sdk.fetch?.(). Never call fetch() or axios directly for Salesforce endpoints.

Optional Chaining and Graceful Handling

Always use optional chaining when calling sdk.graphql or sdk.fetch — these methods may be undefined in some surfaces (e.g., Salesforce ACC, MCP Apps). Handle the case where they are not available gracefully:

const sdk = await createDataSDK();

// ✅ Use optional chaining
const response = await sdk.graphql?.(query);

// ✅ Check before using fetch
if (!sdk.fetch) {
  throw new Error("Data SDK fetch is not available in this context");
}
const res = await sdk.fetch(url);

For GraphQL, if sdk.graphql is undefined, the call returns undefined — handle that in your logic (e.g., throw a clear error or return a fallback). For sdk.fetch, check availability before calling when the operation is required.

Preference: GraphQL First

GraphQL is the preferred method for querying and mutating Salesforce records. Use it when:

  • Querying records (Account, Contact, Opportunity, custom objects)
  • Creating, updating, or deleting records (when GraphQL supports the operation)
  • Fetching related data, filters, sorting, pagination

Use sdk.fetch only when GraphQL is not sufficient. For REST API usage, invoke the fetching-rest-api skill, which documents:

  • Chatter API (e.g., /services/data/v65.0/chatter/users/me)
  • Connect REST API (e.g., /services/data/v65.0/connect/file/upload/config)
  • Apex REST (e.g., /services/apexrest/auth/login)
  • UI API REST (e.g., /services/data/v65.0/ui-api/records/{recordId})
  • Einstein LLM Gateway

Getting the SDK

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

const sdk = await createDataSDK();

Example 1: GraphQL (Preferred)

For record queries and mutations, use GraphQL via the Data SDK. Invoke the using-graphql skill for the full workflow (schema exploration, query authoring, codegen, lint validate).

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 { value }
            }
          }
        }
      }
    }
  }
`;

export async function getAccounts() {
  const sdk = await createDataSDK();
  const response = await sdk.graphql?.<GetAccountsQuery>(GET_ACCOUNTS);

  if (response?.errors?.length) {
    throw new Error(response.errors.map((e) => e.message).join("; "));
  }

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

Example 2: Fetch (When GraphQL Is Not Sufficient)

For REST endpoints that have no GraphQL equivalent, use sdk.fetch. Invoke the fetching-rest-api skill for full documentation of Chatter, Connect REST, Apex REST, UI API REST, and Einstein LLM endpoints.

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

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

export async function getCurrentUser() {
  const sdk = await createDataSDK();
  const response = await sdk.fetch?.(`/services/data/v${API_VERSION}/chatter/users/me`);

  if (!response?.ok) throw new Error(`HTTP ${response?.status}`);
  const data = await response.json();
  return { id: data.id, name: data.name };
}

Anti-Patterns (Forbidden)

Direct fetch to Salesforce

// ❌ FORBIDDEN — bypasses Data SDK auth and CSRF
const res = await fetch("/services/data/v65.0/chatter/users/me");

Direct axios to Salesforce

// ❌ FORBIDDEN — bypasses Data SDK
const res = await axios.get("/services/data/v65.0/chatter/users/me");

Correct approach

// ✅ CORRECT — use Data SDK
const sdk = await createDataSDK();
const res = await sdk.fetch?.("/services/data/v65.0/chatter/users/me");

Clarifying Vague Data Requests

When a user asks about data and the request is vague, clarify before implementing. Ask which of the following they want:

  • Application code — Add or modify code in a specific web app so the app performs the data interaction at runtime (e.g., GraphQL query in the React app)
  • Local SF CLI — Run Salesforce CLI commands locally (e.g., sf data query, sf data import tree) to interact with the org from the terminal
  • Local example data — Update or add local fixture/example data files (e.g., JSON in data/) for development or testing
  • Other — Data export, report generation, setup script, etc.

Do not assume. A request like "fetch accounts" could mean: (1) add a GraphQL query to the app, (2) run sf data query in the terminal, or (3) update sample data files. Confirm the intent before proceeding.


Decision Flow

  1. Need to query or mutate Salesforce records? → Use GraphQL via the Data SDK. Invoke the using-graphql skill.
  2. Need Chatter, Connect REST, Apex REST, UI API REST, or Einstein LLM? → Use sdk.fetch. Invoke the fetching-rest-api skill.
  3. Never use fetch, axios, or similar directly for Salesforce API calls.

Reference

  • GraphQL workflow: invoke the using-graphql skill (.a4drules/skills/using-graphql/)
  • REST API via fetch: invoke the fetching-rest-api skill (.a4drules/skills/fetching-rest-api/)
  • Data SDK package: @salesforce/sdk-data (createDataSDK, gql, NodeOfConnection)
  • createRecord for UI API record creation: @salesforce/webapp-experimental/api (uses Data SDK internally)