skills/forcedotcom/afv-library/accessing-webapp-data

accessing-webapp-data

Installation
SKILL.md

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)
Weekly Installs
1
GitHub Stars
212
First Seen
Mar 23, 2026