* 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>
5.1 KiB
| name | description | paths | |||
|---|---|---|---|---|---|
| fetching-webapp-rest-api | REST API usage via the Data SDK fetch method. Use when implementing Chatter, Connect REST, Apex REST, UI API REST, or Einstein LLM calls — only when GraphQL is not sufficient. |
|
Salesforce REST API via Data SDK Fetch
Use sdk.fetch from the Data SDK when GraphQL is not sufficient. The SDK applies authentication, CSRF handling, and base URL resolution. Always use optional chaining (sdk.fetch?.()) and handle the case where fetch is not available.
Invoke this skill when you need to call Chatter, Connect REST, Apex REST, UI API REST, or Einstein LLM endpoints.
API Version
Use the project's API version. It is typically injected as __SF_API_VERSION__; fallback to "65.0":
declare const __SF_API_VERSION__: string;
const API_VERSION = typeof __SF_API_VERSION__ !== "undefined" ? __SF_API_VERSION__ : "65.0";
Base Path
URLs are relative to the Salesforce API base. The SDK prepends the correct base path. Use paths starting with /services/....
Chatter API
User and collaboration data. No GraphQL equivalent.
| Endpoint | Method | Purpose |
|---|---|---|
/services/data/v{version}/chatter/users/me |
GET | Current user (id, name, email, username) |
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 };
Connect REST API
File and content operations.
| Endpoint | Method | Purpose |
|---|---|---|
/services/data/v{version}/connect/file/upload/config |
GET | Upload config (token, uploadUrl) for file uploads |
const sdk = await createDataSDK();
const configRes = await sdk.fetch?.(`/services/data/v${API_VERSION}/connect/file/upload/config`, {
method: "GET",
});
if (!configRes?.ok) throw new Error(`Failed to get upload config: ${configRes?.status}`);
const config = await configRes.json();
const { token, uploadUrl } = config;
Apex REST
Custom Apex REST resources. Requires corresponding Apex classes in the org. CSRF protection is applied automatically for services/apexrest URLs.
| Endpoint | Method | Purpose |
|---|---|---|
/services/apexrest/auth/login |
POST | User login |
/services/apexrest/auth/register |
POST | User registration |
/services/apexrest/auth/forgot-password |
POST | Request password reset |
/services/apexrest/auth/reset-password |
POST | Reset password with token |
/services/apexrest/auth/change-password |
POST | Change password (authenticated) |
/services/apexrest/{resource} |
GET/POST | Custom Apex REST resources |
Example (login):
const sdk = await createDataSDK();
const response = await sdk.fetch?.("/services/apexrest/auth/login", {
method: "POST",
body: JSON.stringify({ email, password, startUrl: "/" }),
headers: { "Content-Type": "application/json", Accept: "application/json" },
});
Apex REST paths do not include the API version.
UI API (REST)
When GraphQL cannot cover the use case. Prefer GraphQL when possible.
| Endpoint | Method | Purpose |
|---|---|---|
/services/data/v{version}/ui-api/records/{recordId} |
GET | Fetch a single record |
const sdk = await createDataSDK();
const response = await sdk.fetch?.(`/services/data/v${API_VERSION}/ui-api/records/${recordId}`);
Einstein LLM Gateway
AI features. Requires Einstein API setup.
| Endpoint | Method | Purpose |
|---|---|---|
/services/data/v{version}/einstein/llm/prompt/generations |
POST | Generate text from Einstein LLM |
const sdk = await createDataSDK();
const response = await sdk.fetch?.(`/services/data/v${API_VERSION}/einstein/llm/prompt/generations`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
additionalConfig: { applicationName: "PromptTemplateGenerationsInvocable" },
promptTextorId: prompt,
}),
});
if (!response?.ok) throw new Error(`Einstein LLM failed (${response?.status})`);
const data = await response.json();
return data?.generations?.[0]?.text ?? "";
General Pattern
import { createDataSDK } from "@salesforce/sdk-data";
const sdk = await createDataSDK();
if (!sdk.fetch) {
throw new Error("Data SDK fetch is not available in this context");
}
const response = await sdk.fetch(url, {
method: "GET", // or POST, PUT, PATCH, DELETE
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: method !== "GET" ? JSON.stringify(payload) : undefined,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
Reference
- Parent:
accessing-data— enforces Data SDK usage for all Salesforce data fetches - GraphQL:
using-graphql— use for record queries and mutations when possible createRecordfrom@salesforce/webapp-experimental/apifor UI API record creation (uses SDK internally)