mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-02 13:25:16 +08:00
* 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>
179 lines
6.3 KiB
Markdown
179 lines
6.3 KiB
Markdown
---
|
|
name: accessing-webapp-data
|
|
description: Salesforce data access patterns. Use when adding or modifying any code that fetches data from Salesforce (records, Chatter, Connect API, etc.).
|
|
paths:
|
|
- "**/*.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:
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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).
|
|
|
|
```typescript
|
|
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.
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
// ❌ FORBIDDEN — bypasses Data SDK auth and CSRF
|
|
const res = await fetch("/services/data/v65.0/chatter/users/me");
|
|
```
|
|
|
|
### Direct axios to Salesforce
|
|
|
|
```typescript
|
|
// ❌ FORBIDDEN — bypasses Data SDK
|
|
const res = await axios.get("/services/data/v65.0/chatter/users/me");
|
|
```
|
|
|
|
### Correct approach
|
|
|
|
```typescript
|
|
// ✅ 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)
|