Use a GraphQL query to retrieve Salesforce data, such as from an Account or Contact record.
To access Salesforce data via GraphQL:
- Define TypeScript interfaces for the response shape.
- Write the GraphQL query using
uiapisyntax. - Use
createDataSDK()anddataSdk.graphql?.()with proper typing. - Extract and return the data from the response.
import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
const dataSdk = await createDataSDK();
// For queries: use dataSdk.graphql?.query() or dataSdk.fetch?() for API calls
const result = await dataSdk.graphql?.query<ResponseType, VariablesType>({
query: QUERY_STRING,
variables: { ... },
operationName?: "...",
cacheControl?: "no-cache" | "only-if-cached" | { type: "max-age", maxAge: 60 }
});
const QUERY_STRING = gql`
query MyQuery {
uiapi {
...
}
}
`;
For more information about GraphQL usage, see the GraphQL API Developer Guide.
Use one of these patterns for defining GraphQL queries.
Inline gql Tag
This pattern is useful for simple queries without variables or fragments.
- Use the gql template tag (never plain template literals)
- Ensure the query operation name matches what codegen expects
- Import generated types from graphql-operations-types.ts
import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
import type { CurrentUserQuery } from "../graphql-operations-types";
const CURRENT_USER_QUERY = gql`
query CurrentUser {
uiapi {
currentUser {
Id
Name {
value
}
}
}
}
`;
interface User {
id: string;
name: string;
}
export async function getCurrentUser(): Promise<User | null> {
const dataSdk = await createDataSDK();
const result =
(await dataSdk.graphql?.query) <
CurrentUserQuery >
{
query: CURRENT_USER_QUERY,
};
if (result?.errors?.length) {
throw new Error(result.errors.map((e) => e.message).join("; "));
}
const userData = result?.data?.uiapi.currentUser;
if (!userData) {
throw new Error("No user data found");
}
return {
id: userData.Id,
name: userData.Name?.value || "User",
};
}
External .graphql File
This pattern is useful for complex queries with variables, fragments, or queries shared across files.
- Import
.graphqlfiles with the?rawsuffix - Import generated types from
graphql-operations-types.ts - Provide response and variables type generics to
dataSdk.graphql?.query<T, V>() - Use optional chaining for nested response data
To implement a query using a .graphql external file:
- Create a
.graphqlfile undersrc/api/utils/query/
# src/api/utils/query/myQuery.graphql
query GetMyData($myVariable: String) {
uiapi {
query {
MyObject(first: 10, where: { Field: { eq: $myVariable } }) {
edges {
node {
Id
Name {
value
}
}
}
}
}
}
}
- Generate the types using
npm run graphql:codegen. The command generates the types insrc/api/graphql-operations-types.ts. For example:- Response type:
GetMyDataQuery - Variables type:
GetMyDataQueryVariables
- Response type:
- Implement the data access function.
import { createDataSDK, type NodeOfConnection } from "@salesforce/platform-sdk/data";
import MY_QUERY from "./query/myQuery.graphql?raw";
import type { GetMyDataQuery, GetMyDataQueryVariables } from "../graphql-operations-types";
type MyNode = NodeOfConnection<GetMyDataQuery["uiapi"]["query"]["MyObject"]>;
export async function getMyData(variables: GetMyDataQueryVariables): Promise<MyNode[]> {
const dataSdk = await createDataSDK();
const result = await dataSdk.graphql?.query<GetMyDataQuery, GetMyDataQueryVariables>({
query: MY_QUERY,
variables,
});
if (result?.errors?.length) {
const errorMessages = result.errors.map((e) => e.message).join("; ");
throw new Error(`GraphQL Error: ${errorMessages}`);
}
return result?.data?.uiapi?.query?.MyObject?.edges?.map((edge) => edge?.node) || [];
}
Export the GraphQL Return Type
To provide type safety for GraphQL operations, define your return type. These TypeScript interfaces define the shape of data flowing in (query variables) and out (query results) of your GraphQL operations.
export interface Account {
id: string;
name: string;
industry: string | null;
type: string | null;
annualRevenue: number | null;
numberOfEmployees: number | null;
billingCity: string | null;
billingState: string | null;
billingCountry?: string | null;
phone: string | null;
website: string | null;
description?: string | null;
}
export interface AccountsResult {
accounts: Account[];
pageInfo: {
hasNextPage: boolean;
endCursor: string | null;
};
}
export interface GetAccountsQueryVariables {
first?: number | null;
after?: string | null;
}
Export the interfaces so they can be imported and reused across components. You can also use graphql-codegen to generate the interfaces for the interfaces to stay in sync with your schema. Use the return types in your methods and variables.
export async function getAccounts(first = 20, after?: string): Promise<AccountsResult> {
const variables: GetAccountsQueryVariables = { first };
if (after) variables.after = after;
const dataSdk = await createDataSDK();
const result = await dataSdk.graphql?.query<GetAccountsQuery, GetAccountsQueryVariables>({
query: GET_ACCOUNTS,
variables,
});
if (result?.errors?.length) {
throw new Error(result.errors.map((e) => e.message).join("; "));
}
GraphQL Fragments
GraphQL fragments are reusable units of query logic that are used to define a set of fields.
This example uses GraphQL fragments and directives to keep one query reusable while conditionally including fields.
FinancialFieldsandContactFieldsare reusable field groups forAccount.- In the main query, each fragment is attached with
@include(if: $...):...FinancialFields @include(if: $includeFinancials)...ContactFields @include(if: $includeContacts)
- At runtime, variables (
includeFinancials, includeContacts) decide whether those field blocks are fetched.
query GetAccountDetails($id: ID!, $includeFinancials: Boolean!, $includeContacts: Boolean!) {
uiapi {
query {
Account(where: { Id: { eq: $id } }) {
edges {
node {
Id
Name {
value
}
...FinancialFields @include(if: $includeFinancials)
...ContactFields @include(if: $includeContacts)
}
}
}
}
}
}
fragment FinancialFields on Account {
AnnualRevenue {
value
}
NumberOfEmployees {
value
}
}
fragment ContactFields on Account {
Phone {
value
}
Website {
value
}
}
dataSdk.graphql?.query<Response, Variables>({ query, variables }) executes the query with:
- explicit response type (
GetAccountDetailsQuery) - explicit variables type (
GetAccountDetailsQueryVariables) - runtime variables object (
id, includeFinancials, includeContacts)
import { createDataSDK } from "@salesforce/platform-sdk/data";
import QUERY from "./query/getAccountDetails.graphql?raw";
import type {
GetAccountDetailsQuery,
GetAccountDetailsQueryVariables,
} from "../graphql-operations-types";
const dataSdk = await createDataSDK();
const result = await dataSdk.graphql?.query<
GetAccountDetailsQuery,
GetAccountDetailsQueryVariables
>({
query: QUERY,
variables: {
id: accountId,
includeFinancials: userWantsFinancials,
includeContacts: userWantsContacts,
},
});
GraphQL Usage Considerations
When using GraphQL via the Data SDK, consider these usage patterns.
Direct API calls aren't supported. Always use the Data SDK to make your API calls.
// Don't do this: Direct axios/fetch for Salesforce APIs
const result = await axios.post("/graphql", { query });
const result = await fetch("/services/data/v{version}/...");
// Do this: Use the DataSDK
const dataSdk = await createDataSDK();
const result = await dataSdk.graphql?.query<ResponseType>({ query, variables });
const result = await dataSdk.fetch?.("/services/data/v{version}/...");
Provide the response type instead of making untyped GraphQL calls.
// Don't do this: Untyped GraphQL calls
await dataSdk.graphql?.query({ query });
// Do this: Provide response type generic
await dataSdk.graphql?.query<GetAccountsQuery>({ query });
Use the gql template tag or an external .graphql file instead of plain string queries.
// Don't do this: Plain string queries
const query = `query { ... }`;
// Do this: Use gql tag or .graphql file
const query = gql`query { ... }`;
// or do this: Import the query from an external .graphql file
import QUERY from "./query/myQuery.graphql?raw";
Use optional chaining instead of non-null assertion on a GraphQL call.
// Don't do this: Non-null assertion on graphql
await dataSdk.graphql!.query<T>({ query });
// Do this: Optional chaining
await dataSdk.graphql?.query<T>({ query });