# developer Graphql Api - Full Documentation # Aggregate Examples | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | Use aggregate functions to analyze your query results. Aggregate functions include `avg`, `count`, `countDistinct`, `min`, `max`, and `sum`. ## Get Average Opportunity Amount Return the average amount on all opportunities. You can use aggregate functions without a `groupBy` argument, such as using `totalCount` to find the total number of query results or using the `avg` function to find the average amount for all opportunities. ``` query AvgOpportunityExample { uiapi { aggregate { Opportunity { edges { node { aggregate { Amount { avg { value displayValue } } } } } totalCount } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT AVG(Amount) FROM Opportunity ``` ## Get Average Amount of Opportunities By Campaign Using the `groupBy` argument with aggregation functions enables you to perform further analysis on your results, like finding the average amount of all opportunities by campaign. ``` query AvgAmountPerCampaign { uiapi { aggregate { Opportunity (groupBy: { CampaignId: { group: true } } ) { edges { node { aggregate { CampaignId { value } Amount { avg { value } } } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT CampaignId, AVG(Amount) FROM Opportunity GROUP BY CampaignId ``` ## Get Total Count of Records Return the total number of account records. ``` query AccountsCount { uiapi { aggregate { Account { edges { node { aggregate { Id { count { value } } } } } } } } } ``` ### Example Response for Total Count of Records The previous query returns this response. ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Id": { "count": { "value": 29 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT COUNT(Id) FROM Account ``` ## Get Total Count of Records with Grouping To use the `count` function and group by a field, use `Id { count { value } }` on the `aggregate` field. ``` query AccountsCountGroupBy { uiapi { aggregate { Account ( groupBy: { Industry: { group: true } } ) { edges { node { aggregate { Industry { value } Id { count { value } } } } } } } } } ``` ### Example Response for Total Count of Records with Grouping The previous query returns this response. ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "value": null }, "Id": { "count": { "value": 18 //number of accounts without an Industry specified } } } } }, { "node": { "aggregate": { "Industry": { "value": "Apparel" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Biotechnology" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Construction" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Consulting" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Education" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Electronics" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Energy" }, "Id": { "count": { "value": 3 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Hospitality" }, "Id": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Transportation" }, "Id": { "count": { "value": 1 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT Industry, COUNT(Id) FROM Account GROUP BY Industry ``` ## Get Accounts and Average Revenue of All Accounts Return all accounts and their average annual revenue. You can't simultaneously query both the `record` and `aggregate` fields within `RecordAggregate`. Query the records and aggregation separately like this. ``` query accounts { uiapi { query { Account { edges { node { Name { value } } } } } aggregate { Account { edges { node { aggregate { AnnualRevenue { avg { displayValue } } } } } } } } } ``` ## Get Average Annual Revenue of Accounts Return the average annual revenue of account records. ``` query AvgRevenueAccountsExample { uiapi { aggregate { Account { edges { node { aggregate { AnnualRevenue { avg { value displayValue } } } } } totalCount } } } } ``` ### Example Response for Average Annual Revenue The previous query returns this response. ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "AnnualRevenue": { "avg": { "value": 1071125000, "displayValue": "$1,071,125,000" } } } } } ], "totalCount": 24 } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT AVG(AnnualRevenue), FORMAT(AVG(AnnualRevenue)) From Account ``` ## Get Distinct Number of Industries Return the number of industries. To return the number of distinct non-null field values matching the query criteria, use the `countDistinct` function. ``` query accounts { uiapi { aggregate { Account { edges { node { aggregate { Industry { countDistinct{ value } } } } } totalCount } } } } ``` ### Example Response for Distinct Count The previous query returns this response. ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "countDistinct": { "value": 9 } } } } } ], "totalCount": 24 } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT COUNT_DISTINCT(Industry) From Account ``` ## Get Maximum Value of a Field To return the maximum value of a field, use the `max` function. ``` query MaxFieldGroupBy { uiapi { aggregate { Campaign (groupBy: { Name: { group: true } } ) { edges { node { aggregate { Name { value } BudgetedCost { max { value } } } } } } } } } ``` ### Example Response for Maximum Value of a Field ```json { "data": { "uiapi": { "aggregate": { "Campaign": { "edges": [ { "node": { "aggregate": { "Name": { "value": "DM VIP Campaign" }, "BudgetedCost": { "max": { "value": 25000 } } } } }, { "node": { "aggregate": { "Name": { "value": "GC Product Webinar" }, "BudgetedCost": { "max": { "value": 10000 } } } } }, { "node": { "aggregate": { "Name": { "value": "International Engineers Trade Show" }, "BudgetedCost": { "max": { "value": 50000 } } } } }, { "node": { "aggregate": { "Name": { "value": "User Conference" }, "BudgetedCost": { "max": { "value": 100000 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT Name, MAX(BudgetedCost) FROM Campaign GROUP BY Name ``` ## Get Sum of Open Opportunities with More Than 60% Probability To return the sum of a numeric field, use the `sum` function. This example returns the opportunity amount sum grouped by name. ``` query SumAmountGroupBy { uiapi { aggregate { Opportunity ( where: { and: [{ IsClosed: { eq: false }}, { Probability: { gt: 60 } }] }, groupBy: { Name: { group: true } } ) { edges { node { aggregate { Name { value } Amount { sum { value } } } } } } } } } ``` ### Example Response of Open Opportunities Sum ```json { "data": { "uiapi": { "aggregate": { "Opportunity": { "edges": [ { "node": { "aggregate": { "Name": { "value": "Express Logistics SLA" }, "Amount": { "sum": { "value": 120000 } } } } }, { "node": { "aggregate": { "Name": { "value": "United Oil Installations" }, "Amount": { "sum": { "value": 270000 } } } } }, { "node": { "aggregate": { "Name": { "value": "United Oil Office Portable Generators" }, "Amount": { "sum": { "value": 125000 } } } } }, { "node": { "aggregate": { "Name": { "value": "United Oil Refinery Generators" }, "Amount": { "sum": { "value": 270000 } } } } }, { "node": { "aggregate": { "Name": { "value": "University of AZ Installations" }, "Amount": { "sum": { "value": 100000 } } } } } ], "totalCount": 5 } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT SUM(Amount), Name FROM Opportunity WHERE IsClosed = false AND Probability > 60 GROUP BY Name ``` ## See Also [Grouping Examples](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-groupby-examples.md) [SOQL and SOSL Reference: Aggregate Functions](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_agg_functions.htm) # Aggregate Functions for Field Types | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | Aggregate functions are supported for primitive data types and field types, in addition to an extended set of field types for object fields. The following tables show how GraphQL field types relate to the aggregate functions. Although `format` and `label` can be queried as part of aggregation, they cannot be used for aggregation and are excluded from the tables. ## Primitive Data Type Support This table lists primitive data type support, such as for Int and String. | | avg | count | countDistinct | grouping | max | min | sum | | ------- | :-: | :---: | :-----------: | :------: | :-: | :-: | :-: | | Int | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | String | | ✅ | ✅ | ✅ | ✅ | ✅ | | | Boolean | | | | ✅ | | | | | Id | | ✅ | ✅ | ✅ | ✅ | ✅ | | | Double | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | Long | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ## Date and Time Support Date and Time field types support a combination of the functions in the previous section in addition to date and time-specific functions. The rows and columns have been switched around for readability. `grouping` can't be used with DateTime or Time although it's supported within rollup and cube types when used within a Date or Time function. | | Date | DateTime | Time | | :-------------: | :--: | :------: | :--: | | calendarMonth | ✅ | ✅ | | | calendarQuarter | ✅ | ✅ | | | calendarYear | ✅ | ✅ | | | count | ✅ | ✅ | | | countDistinct | ✅ | ✅ | | | dayInMonth | ✅ | ✅ | | | dayInWeek | ✅ | ✅ | | | dayInYear | ✅ | ✅ | | | dayOnly | | ✅ | | | fiscalMonth | ✅ | ✅ | | | fiscalQuarter | ✅ | ✅ | | | fiscalYear | ✅ | ✅ | | | grouping | ✅ | | | | hourInDay | | ✅ | ✅ | | max | ✅ | ✅ | | | min | ✅ | ✅ | | | weekInMonth | ✅ | ✅ | | | weekInYear | ✅ | ✅ | | See the [GroupByFunction Type](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-groupby-schema.md#groupbyfunction-type). ## Additional Field Type Support The following table lists additional field type support, such as for Currency and Email field types. | | avg | count | countDistinct | grouping | max | min | sum | | ----------- | :-: | :---: | :-----------: | :------: | :-: | :-: | :-: | | Currency | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | Email | | ✅ | ✅ | ✅ | ✅ | ✅ | | | Latitude | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | Longitude | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | Percent | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | | PhoneNumber | | ✅ | ✅ | ✅ | ✅ | ✅ | | | Picklist | | ✅ | ✅ | ✅ | ✅ | ✅ | | | TextArea | | ✅ | ✅ | ✅ | ✅ | ✅ | | | Url | | ✅ | ✅ | ✅ | ✅ | ✅ | | ## Aggregate Function Considerations Consider these guidelines when working with aggregate functions. - `label` is supported for Picklist and String field types but it's not available with aggregation. - `format` is supported for the following types but it's not available with aggregation. - Int - Long - Double - Date - DateTime - Time - Currency - Percent - Fields of the following types cannot be grouped and don't support aggregation. - LongTextArea - RichTextArea - EncryptedString - MultiPicklist - Base64 - JSON - Converting date or time fields to a user's time zone isn't currently supported. - Converting currency fields to a user's currency isn't currently supported. # Aggregate Queries with GraphQL | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | Aggregating queries enables you to analyze the records in your result. The `uiapi` field includes the [`query`](https://developer.salesforce.com/docs/platform/graphql/schema-conventions.md) and `aggregate` field. The `aggregate` field of `RecordQueryAggregate` type performs queries that group and aggregate over records. ``` { uiapi { aggregate { # fields } } } ``` You can roll up and summarize your results with aggregate functions, such as returning your data with these functions: - Average - Count - Distinct count - Grouping - Ordering - Minimum - Maximum - Sum **note:** The aggregate functions don’t apply to all field types. For example, average and sum apply to currency and numeric values but not to string values. See [Aggregate Functions for Field Types](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-support.md). ## See Also - [Feature Limitations of Offline GraphQL](https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_graphql_limitations.htm) # Aggregate Schema | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | Like the [`Record` interface](https://developer.salesforce.com/docs/platform/graphql/query/query-record-objects.md), the `RecordQueryAggregate` type corresponds to Salesforce fields, in addition to aggregation functions available on the fields. ``` type UIAPI { query: RecordQuery aggregate: RecordQueryAggregate! } ``` **note:** To view the GraphQL API schema via introspection, use the [Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md). ## RecordQueryAggregate Type The `RecordQueryAggregate` type allows for querying, filtering, and grouping of aggregations on records. `RecordQueryAggregate` has one field for each object type. The schema applies to all Salesforce objects. `Account` is shown here for brevity. ``` type RecordQueryAggregate { Account( after: String first: Int groupBy: Account_GroupBy orderBy: Account_OrderBy scope: ACCOUNT_SCOPE where: Account_Filter ): AccountAggregateConnection } ``` The `RecordQueryAggregate` type contains these fields. - `after` - Returns the results after the given cursor. - `first` - Returns the first n results. - `groupBy` - Groups results according to the field values within the record, with a specified grouping function. Accepts a list of fields. See [Group Results](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-groupby.md). - `orderBy` - Orders the results using a specified field. See [Order Aggregate Results](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-orderby.md). - `scope` - An enumeration of the possible [scopes](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_using_scope.htm) that are defined for the object type. Provide this argument to filter the result set to records that have the specified scope. - `where` - Filters the query with an argument. See [Field Operators](https://developer.salesforce.com/docs/platform/graphql/filter/filter-fields.md). ## RecordAggregateConnection Type Every object type corresponds to an `AggregateConnection` type, for example, `AccountAggregateConnection`, or `RecordAggregateConnection` as a representation for Salesforce objects. The `RecordAggregateConnection` type allows for paging through result sets of records. For example, the `Account` field returns the `AccountAggregateConnection` type. `AccountAggregateConnection` can be embedded in other types to allow for both regular and aggregate queries across records from a single field. ``` type AccountAggregateConnection { edges: [AccountAggregateEdge] pageInfo: PageInfo! totalCount: Int! } ``` The `RecordAggregateConnection` type contains these fields. - `edges` - A list of RecordAggregateEdge types. - `pageInfo` - Information on the relative location in the result set. - `totalCount` - The number of record aggregates as a result of the query. Aggregate queries can be paged using the `RecordAggregateConnection` and `RecordAggregateEdge` types. ## RecordAggregateEdge Type The `RecordAggregateEdge` type connects the record aggregation and its cursor. ``` type AccountAggregateEdge { cursor: String! node: AccountResult } ``` The `RecordAggregateEdge` type contains these fields. - `cursor` - An opaque string used to page directly to this aggregate item in the result set. - `node` - The GraphQL object equivalent for the Salesforce object. ## RecordResult Type The `RecordResult` type represents a Salesforce object type and aggregates on those object types. ``` type AccountResult { aggregate: AccountAggregate } ``` `RecordResult` has an `aggregate` field of `RecordAggregate` type. - `aggregate` - The record aggregate, for example, `AccountAggregate`. Use `aggregate` with the `groupBy` argument or to query an aggregation field. ## RecordAggregate Type `RecordAggregate` has field categories for `FieldAggregate` types such as `StringAggregate` or `CurrencyAggregate`. ``` type RecordAggregate { Id: IDAggregate ApiName: String! IntAggregate?: IntAggregate StringAggregate?: StringAggregate BooleanAggregate?: BooleanAggregate IDAggregate?: IDAggregate DateTimeAggregate?: DateTimeAggregate TimeAggregate?: TimeAggregate DateAggregate?: DateAggregate TextAreaAggregate?: TextAreaAggregate PhoneNumberAggregate?: PhoneNumberAggregate EmailAggregate?: EmailAggregate UrlAggregate?: UrlAggregate EncryptedStringAggregate?: EncryptedStringAggregate CurrencyAggregate?: CurrencyAggregate LongitudeAggregate?: LongitudeAggregate LatitudeAggregate?: LatitudeAggregate PicklistAggregate?: PicklistAggregate LongAggregate?: LongAggregate DoubleAggregate?: DoubleAggregate PercentAggregate?: PercentAggregate } ``` Here's an example schema for `AccountAggregate`. ``` type AccountAggregate { Id: IDAggregate ApiName: String! AnnualRevenue: CurrencyAggregate Name: StringAggregate BillingCity: StringAggregate BillingCountry: StringAggregate BillingGeocodeAccuracy: PicklistAggregate BillingLatitude: LatitudeAggregate BillingLongitude: LongitudeAggregate BillingPostalCode: StringAggregate BillingState: StringAggregate BillingStreet: TextAreaAggregate CreatedById: IDAggregate CreatedDate: DateAggregate } ``` **note:** For a complete view of the `RecordAggregate` type schema in your Salesforce org, use the [Altair GraphQL client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md). Consider these guidelines for `RecordAggregate` types. - The `Id` field is of `IDAggregate` type and is nullable. - LastModifiedById, LastModifiedDate, SystemModstamp, and RecordTypeId are queryable but not supported for aggregation. - LongTextArea, RichTextArea, MultiPicklist, Base64, and JSON can't be grouped and don't support aggregate functions. See [Aggregate Functions for Field Types](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-support.md). Certain field categories aren't supported: - Polymorphic parent relationships - Child relationships Additionally, polymorphic parent relationships aren't queryable from `RecordAggregate`. Only root queries support aggregate expressions. Grouped queries can't use child relationships in the SELECT list. ## FieldAggregate Types `RecordAggregate` contains field categories for `FieldAggregate` types, in comparison to FieldValue types on [`RecordRepresentation`](https://developer.salesforce.com/docs/platform/graphql/query/query-record-objects.md#mapping-sobjects-to-graphql-objects). `FieldAggregate` types provide the `value`, `format`, `label` and `displayValue` fields, in addition to fields for the functions that the data type supports. Only `StringAggregate` and `CurrencyAggregate` are listed here for brevity. The aggregate functions don't apply to all field types. For example, `grouping` applies to `StringAggregate` but not `CurrencyAggregate`. Also, `avg` and `sum` apply to `CurrencyAggregate` but not `StringAggregate`. See [Aggregate Functions for Field Types](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-support.md). ### StringAggregate Type While the `max` and `min` fields on `StringAggregate` are of `StringValue` type, the `label` field is not currently supported for `max` or `min` aggregation. ``` type StringAggregate { count: LongValue countDistinct: LongValue displayValue: String grouping: IntValue label: String max: StringValue min: StringValue value: String } ``` The `StringAggregate` type contains these fields. - `count` - The number of results that matches the query criteria. - `countDistinct` - The number of distinct non-null field values matching the query criteria. - `displayValue` - The displayable value for a field. - `grouping` - Specifies if a field is used when composing the group. Use with the `groupBy` argument and the `ROLLUP` or `CUBE` type. - Returns 0 if the aggregation is applied to the group. - Returns 1 if the field is removed from consideration of the group. - When all groupings return 1, the aggregation is applied to all results. - `label` - The text label for a field. - `max` - The maximum value of a field. - `min` - The minimum value of a field. - `value` - The raw value of a field. ### CurrencyAggregate Type `CurrencyAggregate` provides the same fields as `StringAggregate`, in addition to `avg` and `sum`. ``` CurrencyAggregate Type { avg: DoubleValue count: LongValue countDistinct: LongValue displayValue: String format: String max: CurrencyValue min: CurrencyValue sum: CurrencyValue value: Currency } ``` The `CurrencyAggregate` type contains these fields. - `avg` - The average value of the currency fields. - `count` - The number of results that matches the query criteria. - `countDistinct` - The number of distinct non-null field values matching the query criteria. - `displayValue` - The displayable value for the currency, such as the formatted value of the currency. - `format` - The localized formatting for the currency value. - `max` - The maximum value of a field. - `min` - The minimum value of a field. - `sum` - The total sum of the currency value. - `value` - The raw value of the currency value. # Aggregate Your Results | AVAILABLE API VERSION | | --------------------- | | API v59.0 and later | Analyze your results by using [aggregate functions](https://developer.salesforce.com/docs/platform/graphql/aggregate/aggregate-support.md) like finding the average, maximum, minimum, and sum. ## Send an Aggregate Request from LWC To find the average amount and sum of all opportunities, send an aggregate function using [the `avg` and `sum` functions](https://developer.salesforce.com/docs/platform/graphql/aggregate/aggregate-support.md). ```javascript //simpleAggregate.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class SimpleAggregate extends LightningElement { results; errors; @wire(graphql, { query: gql` query AvgOpportunityExample { uiapi { aggregate { Opportunity { edges { node { aggregate { Amount { avg { displayValue } sum { displayValue } } } } } totalCount } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.aggregate.Opportunity.edges.map((edge) => edge.node); } this.errors = errors; } } ``` The wire adapter returns a JSON response that looks like this. ```json { "data": { "uiapi": { "aggregate": { "Opportunity": { "edges": [ { "node": { "aggregate": { "Amount": { "avg": { "displayValue": "$185,967.74" }, "sum": { "displayValue": "$5,765,000.00" } } } } } ], "totalCount": 31 } } } }, "errors": [] } ``` The data returned from the GraphQL wire adapter has the same structure as the GraphQL query. While this structure works fine for programmatic use, it can be difficult to consume inside your component’s template. This line of code in the example removes extra layers in the response data to make it easier to consume in the template. ```js this.results = data.uiapi.aggregate.Opportunity.edges.map((edge) => edge.node); ``` Your component then renders the results using the `for:each` directive with `aggregate` as the key. ### Display the Average and Sum Results This example uses the `lightning-badge` base component to display the aggregate values. ```html ``` ## Send an Aggregate Request and Group Results Grouping summarizes your data based on a particular field. You can use aggregate functions with [a `groupBy` argument](https://developer.salesforce.com/docs/platform/graphql/aggregate/aggregate-groupby.md) with optional types `CUBE` or `ROLLUP`. Let's say you want to group account by year and get the count for each. ```javascript //aggregateWithGrouping.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AggregateWithGrouping extends LightningElement { results; errors; @wire(graphql, { query: gql` query GroupAccountsByYear { uiapi { aggregate { Account(groupBy: { CreatedDate: { function: CALENDAR_YEAR } }) { edges { node { aggregate { Name { count { value } } CreatedDate { calendarYear { value } } } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.aggregate.Account.edges.map((edge) => edge.node); } this.errors = errors; } } ``` The wire adapter returns a JSON response that looks like this. ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Name": { "count": { "value": 24 } }, "CreatedDate": { "calendarYear": { "value": 2022 } } } } }, { "node": { "aggregate": { "Name": { "count": { "value": 18 } }, "CreatedDate": { "calendarYear": { "value": 2023 } } } } } ] } } } }, "errors": [] } ``` ### Display the Created Date Aggregate Value This example uses the `lightning-badge` base component to display the aggregate values. ```html ``` ## See Also [Aggregate Queries](https://developer.salesforce.com/docs/platform/graphql/aggregate/aggregate.md) [Grouping Examples](https://developer.salesforce.com/docs/platform/graphql/aggregate/aggregate-groupby-examples.md) [Feature Limitations of Offline GraphQL](https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_graphql_limitations.htm) # API End-of-Life Salesforce is committed to supporting each API version for a minimum of three years from the date of first release. To mature and improve the quality and performance of the API, versions that are more than three years old sometimes are no longer supported. Salesforce notifies customers who use an API version scheduled for deprecation at least one year before support for the version ends. # API Request Limits GraphQL API uses the same API limits as other [Connect API limits](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_rate_limits.htm). When you exceed the rate limit, the endpoint returns a 503 Service Unavailable error code. To monitor your org's API calls, go to Setup and review the [system overview page](https://help.salesforce.com/s/articleView?id=xcloud.dev_force_com_system_overview_page.htm). ## See Also [Status Codes and Error Responses](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-status.md) [Connect REST API Limits](https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_chatter_rest.htm) # Authorization GraphQL API auth is the same as other Salesforce REST APIs. For more information, see [OAuth and Connect REST API](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_using_oauth.htm) in _Connect REST API Developer Guide_. To learn how to set up authorization for GraphQL, use a [Quick Start](https://developer.salesforce.com/docs/platform/graphql/guide/get-started.md). **note:** To successfully send requests, GraphQL API requires an access token obtained by authentication. The Quick Starts authenticate via Salesforce CLI. For production apps, we recommend that you use your own [external client app](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm) and an OAuth authorization flow that fits your specific use case. # Boolean Operators | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | To filter the result set, a query combines several predicates. Boolean operators can help you expand or narrow your query within the `where` filter. Use the `OR` function to combine filters. Use the `AND` function to intersect filters. The `NOT` function inverts a filter. The filter types have fields for the `AND`, `OR`, and `NOT` functions. `AND` and `OR` take in a list, while `NOT` takes in a single filter to invert. When combined, the filters allow for arbitrary boolean expressions. ``` input Account_Filter { and: [Account_Filter] or: [Account_Filter] not: Account_Filter } ``` Each filter within the list of filters is joined by the named operator for `AND` or `OR` functions. ## AND Expressions Let’s look at a list of filters with the `and` operator. ``` where: { and: [ {filter1}, {filter2} ] } ``` Each filter is joined with the `AND` SOQL operator. ``` WHERE (filter1) AND (filter2) ``` Here's an example of the previous list of filters. ``` where: { and: [{ AnnualRevenue: { gt: 100000 } }, { AnnualRevenue: { lt: 1000000 } }] } ``` Similarly, consider the following filters. ``` where: { and: [filter1, filter2, filter3] } ``` The implicit filter with the `and` operator is similar to a SOQL statement that looks like this. ``` WHERE (filter1 AND filter2 AND filter3) ``` Whenever two operators have a value on the filter type, the query combines them with an implicit AND operator. ``` Opportunity( where: { NextStep: {eq: "Need estimate"} CloseDate: { CALENDAR_MONTH: { value: { eq: 10 } } } } ) ``` This query is similar to the following SOQL statement. It assumes that `Id` and `Name` are included in a `SELECT` clause. ``` FROM Opportunity WHERE NextStep='Need estimate' AND CALENDAR_MONTH(CloseDate)=10 ``` Similarly, the following query contains multiple operators `eq` and `gt` with a value on the filter type. ``` Account( where: { AnnualRevenue: {gt: 1000000} Ownership: {eq: "Public" } ShippingCity: { eq: "Tokyo" } } ) ``` The previous query is similar to the following SOQL statement. It assumes that `Id` and `Name` are included in a `SELECT` clause. ``` SELECT Id, Name FROM Account WHERE AnnualRevenue>1000000 AND Ownership='Public' AND ShippingCity='Tokyo' ``` ## OR Expressions Similarly, a filter with the `or` operator looks like this. ``` where: { or: [filter1, filter2, filter3] } ``` The `OR` function is similar to the following SOQL statement. ``` WHERE (filter1 OR filter2 OR filter3) ``` Let’s look at how to use the `or` filter type. ``` Account( where: { or: [ { AnnualRevenue: {gt: 10000000} } { Ownership: {eq: "Public"} } ] } ) ``` The previous query is similar to this SOQL statement with the `OR` operator. It assumes that `Id` and `Name` are included in a `SELECT` clause. ``` SELECT Id, Name FROM Account WHERE AnnualRevenue>10000000 OR Ownership='Public' ``` ## NOT Expressions The `NOT` function inverts the predicate within the filter. ``` Account( where: { not: { ShippingCity: { eq: { "Tokyo" } } } } ) ``` The previous query is similar to the following SOQL statement with the `NOT` operator. It assumes that `Id` and `Name` are included in a `SELECT` clause. ``` SELECT Id, Name FROM Account WHERE NOT ShippingCity='Tokyo' ``` The `NOT` function can be used with the binary functions as well. ``` where: { not: { and: [filter1, filter2] } } ``` The previous `NOT` function is similar to the following SOQL statement. ``` WHERE NOT (filter1 AND filter2) ``` This query uses the `not` filter type with multiple `and` filters. ``` Opportunity( where: { not: { Probability: { eq: 100 } StageName: { eq: "Closed Won" } } } ) ``` The previous query is similar to the following SOQL statement with the `WHERE NOT` clause. ``` SELECT Id, Name FROM Opportunity WHERE NOT (Probability=100 AND StageName='Closed Won') ``` ## Filter Nesting Furthermore, we can have arbitrary nesting of filters. ``` where: { and: [ {or: [filter11, filter12]}, {or: [filter21, filter22]} ] } ``` The nesting of filter is similar as follows. ``` WHERE ( (filter11 OR filter12) AND (filter21 OR filter22) ) ``` This query uses nesting of filters. ``` Opportunity( where: { or: [ { Probability: { eq: 100 }, StageName: { eq: "Closed Won" } }, { Type: { eq: "New Customer" }, ExpectedRevenue: { gt: 1000000 } } ] } ) ``` The previous query is similar to the following SOQL statement. ``` SELECT Id, Name FROM Opportunity WHERE (Probability=100 AND StageName='Closed Won') OR (Type='New Customer' AND ExpectedRevenue>1000000) ``` # Chain Mutations by Using Field References | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | Create a mutation request with an operation that references another operation by using field references. You can create a record and a parent or child record in the same transaction. You can also chain operations such as creating a user and then creating an account whose owner is the newly created user. When working with multiple operations in a single mutation request, consider setting the [`allOrNone` boolean](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-use.md) to `false` so that some operations successfully execute even if there are independent unsuccessful operations. ## Chain Operations with Multiple Field Reference Patterns There are multiple ways to reference fields in chained mutations. Assuming `ref` is the name or alias of a previous mutation operation from the same request, supported field reference patterns are: - `@{ref.Record.Id}` - Explicit record ID reference. Available in API v67.0 and later. - `@{ref.Record.FieldName.value}` - GraphQL field reference. For example, `Name { value }` in a GraphQL query is `@{ref.Record.Name.value}`. Available in API v67.0 and later. - `@{ref}` - `IdOrRef` scalar reference that accepts a record ID value or the name or alias of another operation. Available in API v59.0 and later. **note:** When chaining operations, place an operation after the operation it references. If you order an operation that references another operation first, the request fails because the operation can’t find the referenced operation. ## Example: Chain Account, Contact, and Opportunity Creation This example chains the creation of an account, a contact, and an opportunity in a single request and uses multiple field reference patterns. The child contact creation requires the `AccountId` field value from the account creation operation. The contact create operation passes in `@{AccountCreate}` to the `Contact.AccountId` field to reference the `Id` field on the newly created account. The contact creation also requires the `LastName` field value from the account creation operation. The contact create operation passes in `@{AccountCreate.Record.Name.value}` to the `Contact.LastName` field. The opportunity creation also requires the `AccountId` field value from the account creation operation. In this example, the opportunity create operation passes in `@{AccountCreate.Record.Id}` to reference the `Id` of the record explicitly. ``` mutation CreateAccountAndContact { uiapi(input: { allOrNone: false }) { AccountCreate(input: { Account: { Name: "Mutation Fun" } }) { Record { Id # referenced in 'OpportunityCreate' Name { value } # referenced in 'ContactCreate' } } ContactCreate(input: { Contact: { MailingCity: "Paris" LastName: "@{AccountCreate.Record.Name.value}" AccountId: "@{AccountCreate}" # equivalent to AccountCreate.Record.Id } }) { Record { Id LastName { value } # referenced in 'OpportunityCreate' MailingCity { value } # referenced in 'OpportunityCreate' } } OpportunityCreate(input: { Opportunity: { Name: "@{ContactCreate.Record.LastName.value}" # 'ContactCreate' reference Description: "@{ContactCreate.Record.MailingCity.value}" # 'ContactCreate' reference AccountId: "@{AccountCreate.Record.Id}" # 'AccountCreate' reference StageName: "Value Proposition" CloseDate: "2026-12-31" } }) { Record { Id AccountId { value } Name { value } Description { value } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "AccountCreate": { "Record": { "Id": "001LT000011naPRYAY", "Name": { "value": "Mutation Fun" } } }, "ContactCreate": { "Record": { "Id": "003LT00000ArlizYAB", "LastName": { "value": "Mutation Fun" }, "MailingCity": { "value": "Paris" } } }, "OpportunityCreate": { "Record": { "Id": "006LT000005R4HZYA0", "AccountId": { "value": "001LT000011naPRYAY" }, "Name": { "value": "Mutation Fun" }, "Description": { "value": "Paris" } } } } }, "errors": [], "extensions": {} } ``` ## Example: Chain Contact Update and Opportunity Creation This example updates a contact and then creates an opportunity for the related account with the contact’s name. ``` mutation UpdateContactAndCreateOpportunity{ uiapi { contact: ContactUpdate(input: { Contact: { MailingCity: "Paris" }, Id: "003xx000004WjJEAA0" }) { Record { Id Name { value } # referenced in 'oppty' AccountId { value } # referenced in 'oppty' } } oppty: OpportunityCreate(input: { Opportunity: { AccountId: "@{contact.Record.AccountId.value}" # 'contact' field reference ContactId: "@{contact.Record.Id}" # 'contact' field reference Name: "@{contact.Record.Name.value}" # 'contact' field reference StageName: "Value Proposition" CloseDate: "2026-12-31" } }) { Record { Id AccountId { value } ContactId { value } Name { value } Description { value } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "contact": { "Record": { "Id": "003LT00000ArlizYAB", "Name": { "value": "Mutation Fun" }, "AccountId": { "value": "001LT000011naPRYAY" } } }, "oppty": { "Record": { "Id": "006LT000005R5FFYA0", "AccountId": { "value": "001LT000011naPRYAY" }, "ContactId": { "value": "003LT00000ArlizYAB" }, "Name": { "value": "Mutation Fun" }, "Description": null } } } }, "errors": [], "extensions": {} } ``` # Chain Queries by Using Field References | AVAILABLE API VERSION | | --------------------- | | API v67.0 and later | Create a query that uses field references from a previous query. You can chain multiple operations that depend on a previous query’s results in the same transaction. You can reference any field, including fields in result lists, from a previous query. Chained queries can reference any supported objects, including objects that don’t have parent and child relationships. ## Chain Operations with Multiple Field Reference Patterns There are multiple ways to reference fields, including fields in lists, in chained queries. Assuming `ref` is the name or alias of a previous query from the same request, supported field reference patterns are: - `@{ref.FieldName}` - First-level field reference - `@{ref.FieldName.value}` - First-level field value reference - `@{ref.edges[*].node.FieldName}` - Field reference in a list - `@{ref.edges[*].node.FieldName.value}` - Field value reference in a list - `@{ref.edges[ListItemNumber].node.FieldName}` - Field reference with a specific list item number, starting with 0 - `@{ref.edges[ListItemNumber].node.FieldName.value}` - Field value reference with a specific list item number, starting with 0 **note:** When chaining operations, place an operation after the operation it references. If you order an operation that references another operation first, the request fails because the operation can’t find the referenced operation. ## Example: Get Accounts Owned by a User This example chains the query of the current user to the query of all the accounts the user owns. The first query [gets the current user](https://developer.salesforce.com/docs/platform/graphql/guide/query-current-user-record.md). The second query gets the accounts owned by the current user by referencing the current user’s ID with `@{currentUser.Id}`. ``` query queries { uiapi { currentUser { Id Name { value } Username { value } } query { allAccounts: Account( where: { OwnerId: { eq: "@{currentUser.Id}" } } ) { edges { node { Id Name { value } Description { value } Owner { Id Name { value } } } } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "currentUser": { "Id": "005LT00000472u1YAA", "Name": { "value": "Your Name Here" }, "Username": { "value": "yournamehere@yourorg.com" } }, "query": { "allAccounts": { "edges": [ { "node": { "Id": "001LT00000DzUzNYAV", "Name": { "value": "Global Media" }, "Description": { "value": "GBM is the worldwide leader in technology news and information." }, "Owner": { "Id": "005LT00000472u1YAA", "Name": { "value": "Your Name Here" } } } }, { "node": { "Id": "001LT00000DzUzPYAV", "Name": { "value": "Second Account" }, "Description": { "value": "Second account description." }, "Owner": { "Id": "005LT00000472u1YAA", "Name": { "value": "Your Name Here" } } } }, { "node": { "Id": "001LT00000DzUzSYAV", "Name": { "value": "Third Account" }, "Description": { "value": null }, "Owner": { "Id": "005LT00000472u1YAA", "Name": { "value": "Your Name Here" } } } } ] } } } }, "errors": [], "extensions": {} } ``` ## Example: Get Accounts Owned by a List of Users This example chains the query of a list of users to the query of the accounts that the users own. The first query gets a subset of users in a list. The second query gets the accounts by referencing the owners’ IDs with `@{User.edges[*].node.Id}`. It’s possible to rewrite this example as a single query. For illustrative purposes, the example shows how to reference a field in a result list of a previous query. ``` query queries { uiapi { query { User( where: { LastName: { like: "User%" } } ) { edges { node { Id FirstName { value } LastName { value } Email { value } } } } Account( where: { OwnerId: { in: ["@{User.edges[*].node.Id}"] } } ) { edges { node { Id Name { value } Description { value } Owner { Id Name { value } } } } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "query": { "User": { "edges": [ { "node": { "Id": "005LT00000472vhYAA", "FirstName": { "value": "Your Name" }, "LastName": { "value": "User" }, "Email": { "value": "yournameuser@yourorg.com" } } }, { "node": { "Id": "005LT00000472viYAA", "FirstName": { "value": "Another Name" }, "LastName": { "value": "User" }, "Email": { "value": "anothernameuser@yourorg.com" } } }, { "node": { "Id": "005LT00000472vjYAA", "FirstName": { "value": "Third Name" }, "LastName": { "value": "User" }, "Email": { "value": "thirdnameuser@yourorg.com" } } } ] }, "Account": { "edges": [ { "node": { "Id": "001LT000011naPRYAY", "Name": { "value": "Account1" }, "Description": { "value": null }, "Owner": { "Id": "005LT00000472vhYAA", "Name": { "value": "Your Name User" } } } }, { "node": { "Id": "001LT00000DzUzOYAV", "Name": { "value": "Account2" }, "Description": { "value": "Account2 description." }, "Owner": { "Id": "005LT00000472viYAA", "Name": { "value": "Another Name User" } } } }, { "node": { "Id": "001LT00000DzUzQYAV", "Name": { "value": "Account3" }, "Description": { "value": "Account3 description." }, "Owner": { "Id": "005LT00000472vjYAA", "Name": { "value": "Third Name User" } } } } ] } } } }, "errors": [], "extensions": {} } ``` # Connect Altair GraphQL Client to Salesforce [Altair GraphQL Client](https://altairgraphql.dev) is an open-source tool that helps you debug GraphQL queries and implementations. The client provides schema documentation via introspection through a rich interface. To query the API, you need the base URL and an API access token. **note:** Alternatives to Altair GraphQL Client include [GraphiQL](https://github.com/graphql/graphiql) and [Postman](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-postman.md). Use Postman if you want to explore and test GraphQL API without access to schema documentation. ## Prerequisites - [Salesforce Developer Edition](https://developer.salesforce.com/signup) - Install [Altair GraphQL Client](https://altairgraphql.dev/#download) based on your operating system. **tip:** Turn off warning alerts in Altair GraphQL Client. Warnings don’t affect the functionality of GraphQL and can be ignored. Click the Settings icon and select **Settings**. Turn on **Disable warning alerts** and click **Save**. Next, get an API access token so you can send a request to your Salesforce org. ## Step 1: Get an API Access Token GraphQL API uses OAuth 2.0, similar to other Salesforce REST APIs. To get the API access token, follow [the Connect REST API Quick Start](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickstart.htm). **note:** To successfully send requests, GraphQL API requires an access token obtained by authentication. This Quick Start authenticates via Salesforce CLI. For production apps, we recommend that you use your own [external client app](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm) and an OAuth authorization flow that fits your specific use case. After you create an external client app and set up your [OAuth authorization](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_client_credentials_flow.htm), you can use Salesforce CLI or run this `curl` command to get an access token. ```bash curl https://MyDomainName.my.salesforce.com/services/oauth2/token -d 'grant_type=client_credentials' -d 'client_id=consumer-key' -d 'client_secret=consumer-secret' ``` Replace this value: - `MyDomainName`: A custom subdomain specific to a Salesforce org. For example, `companyname` creates the URL `https://companyname.my.salesforce.com`. **note:** The `MyDomainName.lightning.force.com` URL format isn’t supported for OAuth authorization. Use `MyDomainName.my.salesforce.com` instead. The `curl` command returns your API access token in the `access_token` property. You need this access token to send a request via the GraphQL client. ## Step 2: Send a Request from Altair GraphQL Client Now that you have your access token, you’re ready to send a GraphQL API request to Salesforce. **note:** The instructions assume you’re using Altair GraphQL Client on MacOS; steps can vary slightly if you’re using the client on another operating system. To send a request: 1. Open the GraphQL client you installed. 2. Next to the POST option, enter your endpoint using the format `https://{MyDomainName}.my.salesforce.com/services/data/v{version}/graphql`, for example `https://myorg-dev-ed.my.salesforce.com/services/data/v57.0/graphql`. 3. Edit the HTTP headers. 1. Click the Set Headers icon (![Set header icon](https://developer.salesforce.com/docs/media/altair-headers-icon.png)) on the sidebar. The **Headers** prompt appears. 2. For the **Header key** field, enter `Authorization`. 3. For the **Header value** field, enter the access token you generated in [step 1](#step-1-get-an-api-access-token). The format is `Bearer access_token`. For example, `Bearer 00DRM000000LnTv!AREAQN.therestofyourtokenhere`. 4. To ensure proper encoding, click **Add header**. 5. For the **Header key** field, enter `X-Chatter-Entity-Encoding`. 6. For the **Header value** field, enter `false`. 7. Click **Done**. 4. Back in the main client window, enter your query. You can use your own query or this example query. ``` query accounts { uiapi { query { Account { edges { node { Id Name { value } } } } } } } ``` 5. Click **Send Request** or the ▶️ icon to run the GraphQL query. Alternatively, you can press Ctrl + Enter (Windows) or Cmd + Enter (Mac). Altair GraphQL Client includes an editor for your query on the left, and the result window on the right. For more information, see the [Altair GraphQL Client documentation](https://altairgraphql.dev/docs/). ![Work with Altair GraphQL Client](https://developer.salesforce.com/docs/media/altair-graphql-client.png) ## Step 3: Explore the GraphQL API Schema To explore the GraphQL API schema documentation: **note:** The instructions assume you’re using Altair GraphQL Client on MacOS; steps can vary slightly if you’re using the client on another operating system. 1. Click **Docs**. A panel opens to reveal the documentation explorer. 2. If the explorer doesn’t display the types, click the Reload Docs icon (![Reload docs icon](https://developer.salesforce.com/docs/media/altair-reload-docs-icon.png)). When you load the schema, the panel displays the types and queries available in the Salesforce GraphQL API. ![Review the types and queries in the Salesforce GraphQL schema](https://developer.salesforce.com/docs/media/altair-docs-explorer.png) If you receive an error about invalid schema, verify that you set the correct encoding HTML header as described in sub-steps 4–6 in [Step 2: Send a Request from Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-graphql.md#step-2-send-a-request-from-altair-graphql-client). # Connect Postman to Salesforce Directly execute queries using the REST client Postman. Postman replaces the legacy Workbench tool as the recommended solution to explore and test Salesforce APIs. To interact with GraphQL API, use the [Postman Collection](https://www.postman.com/salesforce-developers/workspace/salesforce-developers/folder/12721794-23e285e8-51bd-438a-a130-847f1e3e6d7b?ctx=documentation). The Postman Collection comes with a configurable environment and variables that let you easily authenticate. Send requests to multiple Salesforce orgs with a declarative interface. ## Prerequisites [Salesforce Developer Edition](https://developer.salesforce.com/signup) ## Install Postman Before you can connect Postman to Salesforce, fork and configure the collection. See the [installation instructions](https://github.com/forcedotcom/postman-salesforce-apis#installation). ![Send GraphQL API requests using Postman](https://developer.salesforce.com/docs/media/graphql-postman.png) ## Postman Resources Explore and learn more about interacting with Salesforce APIs using Postman. - [_Trailhead Quick Start_: Connect Postman to Salesforce](https://trailhead.salesforce.com/en/content/learn/projects/quick-start-connect-postman-to-salesforce) - [_Salesforce Developers' Blog_: Explore the Salesforce APIs with a Postman Collection](https://developer.salesforce.com/blogs/2020/03/explore-the-salesforce-apis-with-a-postman-collection) - [_Salesforce Developers' Blog_: Explore the Salesforce APIs with the Upgraded Postman Collection](https://developer.salesforce.com/blogs/2021/01/explore-the-salesforce-apis-with-the-upgraded-postman-collection) # Create a Record | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | Use `mutations` to create a record. Within `mutations`, the [`RecordCreate` field](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-schema.md) enables you to create all object types your Salesforce user has access to. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for mutations. For create mutations, the context user must have read access to the new record. ## Example Account Create Request To create a record, use `RecordCreate` with field values for the record you want to create. A response is returned when record creation is successful. To define the fields you want the response body to return, use the `Record` field. You can return the `Id` and selected fields from your record creation. For example, create an account with the required name field. ``` mutation AccountExample{ uiapi { AccountCreate(input: { Account: { Name: "Trailblazer Express" } }) { Record { Id Name { value } } } } } ``` ## Example Response on Account Record Creation The response body returns the fields you request under `Record`. ``` { "data": { "uiapi": { "AccountCreate": { "Record": { "Id": "001RM000005fdQuYAI", "Name": { "value": "Trailblazer Express" } } } } }, "errors": [] } ``` ## Example Child Contact Create Request Given the account ID returned by the account record creation, create an associated contact for that account. This example uses the record ID from the example, `001RM000005fdQuYAI`. Replace the account ID with your own. ``` mutation ContactExample{ uiapi { ContactCreate(input: { Contact: { FirstName: "Appy" LastName: "Bobcat" Email: "appy@example.com" AccountId: "001RM000005fdQuYAI" } }) { Record { Id Name { value } Email { value } } } } } ``` ## Example Response on Child Record Creation The response body returns the fields you request under `Record`. ``` { "data": { "uiapi": { "ContactCreate": { "Record": { "Id": "003RM000008B7H0YAK", "Name": { "value": "Appy Bobcat" }, "Email": { "value": "appy@example.com" } } } } }, "errors": [] } ``` ## Record Creation Guidelines Consider these guidelines for creating a record. - For compound fields, use the constituent fields. For example use `FirstName` and `LastName` instead of `Name`. - For numerical field values, such as integers or currency, use the raw values. For example, use `80000` instead of `80,000` and don’t include currency symbols. - Sending a create request with field values that don’t match the supported format returns a [`ValidationError`](https://developer.salesforce.com/docs/platform/graphql/query/query-status.md). Use the appropriate format for the field, such as [`YYYY-MM-DD` for date fields](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm). - Sending a create request with duplicate values can return a `DataFetchingException` error. Review your [duplicate rules](https://help.salesforce.com/s/articleView?id=sales.duplicate_rules_create.htm) and make sure you’re not creating a duplicate record. ## See Also [Send Mutation Requests](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-use.md) # Delete a Record | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | Use `mutations` to delete a record. Within `mutations`, the [`RecordDelete` field](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-schema.md) enables you to update all object types your Salesforce user has access to. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for mutations. ## Example Delete Request To delete a record, use `RecordDelete` with the `Id` for the record you want to delete. ``` mutation AccountDeleteExample{ uiapi { AccountDelete(input: { Id: "001RM000005eiZZZZZ" }) { Id } } } ``` ## Example Response on Deletion The response body returns the `Id` value of the record you deleted. ``` { "data": { "uiapi": { "AccountDelete": { "Id": "001RM000005eiZZZZZ" } } }, "errors": [] } ``` ## Record Delete Guidelines Consider these guidelines for deleting a record. - Sending a delete request with an incorrect `Id` value returns a `DataFetchingException` error. - Sending a delete request for a record that’s already deleted returns a `DataFetchingException` error. ## See Also [Send Mutation Requests](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-use.md) # Display Data Using Base Components A common way to display data is to use datatables. LWC provides the [`lightning-datatable`](https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable) base component for displaying large amounts of data. `lightning-datatable` supports a wide range of column types that are ideal for displaying record data, such as currency, date, email, and even a dropdown menu for row-level actions. You can also load more data by implementing pagination or infinite scrolling on the datatable. To display your records using `lightning-datatable`, set `key-field="Id"` and specify the `data` and `column` properties. ```html ``` In your JavaScript, create your columns and define your data using key-value pairs when it’s returned by the GraphQL wire adapter. ```javascript // datatableWithGraphql.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; const columns = [ { label: "Name", fieldName: "Name" }, { label: "Phone", fieldName: "Phone", type: "phone" }, { label: "Website", fieldName: "Website", type: "url" }, { label: "Annual Revenue", fieldName: "AnnualRevenue", type: "currency" }, ]; export default class DatatableWithGraphql extends LightningElement { // Array of accounts to display accounts = undefined; // Errors from the wire adapter errors = undefined; // Columns for datatable columns = columns; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Account { edges { node { Id Name { value } Phone { value } Website { value } AnnualRevenue { displayValue } } } } } } } `, }) gqlQuery({ data, errors }) { if (data) { this.accounts = data.uiapi.query.Account.edges.map((edge) => ({ Id: edge.node.Id, Name: edge.node.Name.value, Phone: edge.node.Phone.value, Website: edge.node.Website.value, AnnualRevenue: edge.node.AnnualRevenue.displayValue, })); } this.errors = errors; } } ``` Add pagination to the datatable with a refresh button and a next button. The refresh button takes users back to the start of the results. The next button becomes disabled when the end of the results is reached. **note:** Backward pagination using `last` and `before` isn’t currently supported. ```html ``` Building on the previous lightning-datatable example, query the `pageInfo` object for cursor and pagination information. ```javascript // datatableWithGraphqlPagination.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; const columns = [ { label: "Name", fieldName: "Name" }, { label: "Phone", fieldName: "Phone", type: "phone" }, { label: "Website", fieldName: "Website", type: "url" }, { label: "Annual Revenue", fieldName: "AnnualRevenue", type: "currency" }, ]; export default class DatatableWithGraphqlPagination extends LightningElement { // Array of accounts to display accounts = undefined; // Errors from the wire adapter errors = undefined; // Columns for datatable columns = columns; // Cursor of the last returned record lastCursor = null; // Cursor for the next page endCursor = null; // Checks if the page is the last page // Disables the next page button if true isFinalPage = false; // Total number of query results totalCount = null; page = 1; totalPages = 1; @wire(graphql, { query: "$accountQuery", variables: "$variables", }) gqlQuery({ data, errors }) { if (data) { this.accounts = data.uiapi.query.Account.edges.map((edge) => ({ Id: edge.node.Id, Name: edge.node.Name.value, Phone: edge.node.Phone.value, Website: edge.node.Website.value, AnnualRevenue: edge.node.AnnualRevenue.displayValue, })); this.isFinalPage = !data.uiapi.query.Account.pageInfo.hasNextPage; this.endCursor = data.uiapi.query.Account.pageInfo.endCursor; this.totalCount = data.uiapi.query.Account.totalCount; this.totalPages = Math.ceil(this.totalCount / 10); } this.errors = errors; } // Define the GraphQL query get accountQuery() { return gql` query AccountWithName($after: String) { uiapi { query { Account(after: $after) { edges { node { Id Name { value } Phone { value } Website { value } AnnualRevenue { displayValue } } } pageInfo { endCursor hasNextPage hasPreviousPage } totalCount } } } } `; } // Define variables for the GraphQL query get variables() { return { after: this.lastCursor, }; } get currentPage() { return this.totalCount === 0 ? 0 : this.page; } // Click handler for the reset button resetPagingCursor(event) { this.lastCursor = null; this.page = 1; } // Click handler for the next page button getNextPage(event) { if (!this.isFinalPage) { this.lastCursor = this.endCursor; this.page++; } } } ``` # Field Operators | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | Each field on the sObject has a corresponding input object field on the `Filter` type. The input object field has an `Operators` type. For example, `Account` has a field `Name` of type `String`, and so the `AccountFilter` input object has an input object field `Name` of type `StringOperators`. ``` type Account { Name: StringValue } input Account_Filter { Name: StringOperators } ``` Each `Operators` type exposes the filtering capabilities of that field type. Each field type that supports filtering has a corresponding `Operators` type. The `Operators` type has one input object field for each filtering capability of the underlying data type. For example, the `StringOperators` type can compare String values based on equality and ordering. **tip:** If multiple operations are specified on an Operator, both operations are included in the query and AND'd together. For example, `where: {AnnualRevenue: {gt: 10000, lt: 100000}}` finds records with an annual revenue of more than 10000 and less than 100000. GraphQL supports multiple operators in queries. See [Boolean Operators](https://developer.salesforce.com/docs/platform/graphql/guide/filter-boolean.md) for more information and examples. ## Field Functions Each field on the `Operators` type corresponds to the following functions. | Function | Description | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `eq` | Equals. The expression is true if the field value equals the value in the expression. String comparisons are case-insensitive. For example, `Name: { eq: "Genepoint" }` returns the same result as `Name: { eq: "GenePoint" }` | | `ne` | Not equals. The expression is true if the field value doesn’t equal the specified value. | | `lt` | Less than. The expression is true if the field value is less than the specified value. | | `gt` | Greater than. The expression is true if the field value is greater than the specified value. | | `lte` | Less than or equal. The expression is true if the field value is less than, or equals, the specified value. | | `gte` | Greater than or equal. The expression is true if the field value is greater than or equal to the specified value. | | `like` | The expression is true if the field value matches the characters of the specified value. Supported for string fields only. | | `in` | Is an element within a static set of items. For example, `Name: { in: ["Genepoint", "Edge Communications"] }` | | `nin` | Is not an element within a static set of items | | `inq` | Is an element in query. Use this function to create a [semi-join filter](https://developer.salesforce.com/docs/platform/graphql/guide/filter-joins.md). | | `ninq` | Is not an element in query. Use this function to create an [anti-join filter](https://developer.salesforce.com/docs/platform/graphql/guide/filter-joins.md). | Fields on sObjects have corresponding mappings to `Operators` types. The main field types are: - [String Field Types](#string-field-types) - String - Email - PhoneNumber - TextArea - LongTextArea - Url - [Number Field Types](#number-field-types) - Double - Int - Long - Currency - Percent - [Date and Time Field Types](#date-datetime-and-time-field-types) - Date - DateTime - Time - [Other Types](#boolean-field-type) - Boolean - ID - Picklist - Multi-picklist - Latitude - Longitude - Geolocation These field types are discussed in the following sections. ## String Field Types Operators for field types Email, TextArea, LongTextArea, Url, and PhoneNumber are similar to `StringOperators`, but they use the appropriate scalar for the input object field type. The `like` operator behaves similarly to the [WHERE SOSL expression](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl_where.htm). ### String Fields String fields map to the `StringOperators` filter type. ``` input StringOperators { eq: String ne: String like: String lt: String gt: String lte: String gte: String in: [String] nin: [String] } ``` ### Email Fields Email fields map to the `EmailOperators` filter type. ``` input EmailOperators { eq: Email ne: Email like: Email lt: Email gt: Email lte: Email gte: Email in: [Email] nin: [Email] } ``` ### PhoneNumber Fields PhoneNumber fields map to the `PhoneNumberOperators` filter type. ``` input PhoneNumberOperators { eq: PhoneNumber ne: PhoneNumber like: PhoneNumber lt: PhoneNumber gt: PhoneNumber lte: PhoneNumber gte: PhoneNumber in: [PhoneNumber] nin: [PhoneNumber] } ``` ### TextArea Fields TextArea fields map to the `TextAreaOperators` filter type. ``` input TextAreaOperators { eq: TextArea ne: TextArea like: TextArea lt: TextArea gt: TextArea lte: TextArea gte: TextArea in: [TextArea] nin: [TextArea] } ``` ### LongTextArea Fields LongTextArea fields map to the `LongTextAreaOperators` filter type. ``` input LongTextAreaOperators { eq: LongTextArea ne: LongTextArea like: LongTextArea lt: LongTextArea gt: LongTextArea lte: LongTextArea gte: LongTextArea in: [LongTextArea] nin: [LongTextArea] } ``` ### Url Fields Url fields map to the `URLOperators` filter type. ``` input URLOperators { eq: Url ne: Url like: Url lt: Url gt: Url lte: Url gte: Url in: Url nin: Url } ``` ## Number Field Types Operators for field types Currency, Percent, Longitude, and Latitude are similar to `DoubleOperators`, but they use the appropriate scalar for the input object field type. The Operator for the Long field type is similar to `IntegerOperators`, but uses Long instead of Int. ### Double Fields Double fields map to the `DoubleOperators` filter type. ``` input DoubleOperators { eq: Double ne: Double lt: Double gt: Double lte: Double gte: Double in: [Double] nin: [Double] } ``` ### Int Fields Int fields map to the `IntegerOperators` filter type. ``` input IntegerOperators { eq: Int ne: Int lt: Int gt: Int lte: Int gte: Int in: [Int] nin: [Int] } ``` ### Long Fields Long fields map to the `LongOperators` filter type. ``` input LongOperators { eq: Long ne: Long lt: Long gt: Long lte: Long gte: Long in: [Long] nin: [Long] } ``` ### Currency Fields Currency fields map to the `CurrencyOperators` filter type. ``` input CurrencyOperators { eq: Currency ne: Currency lt: Currency gt: Currency lte: Currency gte: Currency in: [Currency] nin: [Currency] } ``` ### Percent Fields Percent fields map to the `PercentOperators` filter type. ``` input PercentOperators { eq: Percent ne: Percent lt: Percent gt: Percent lte: Percent gte: Percent in: [Percent] nin: [Percent] } ``` ## Date, DateTime, and Time Field Types Date and DateTime fields support additional filtering criteria beyond the standard set of operators defined on other types. Rather than the input object fields of the Operators type being the scalar type, they are of input object type `DateInput` and `DateTimeInput` respectively. In addition to a different type for the individual operators, Date and DateTime Operators support additional functions related to the relative time of the field value. These input object field types are `DateFunctionInput` and `DateTimeFunctionInput`. ### Date Fields Date fields are mapped to `DateOperators`. ``` input DateOperators { eq: DateInput ne: DateInput lt: DateInput gt: DateInput lte: DateInput gte: DateInput in: [DateInput] nin: [DateInput] CALENDAR_MONTH: DateFunctionInput CALENDAR_QUARTER: DateFunctionInput CALENDAR_YEAR: DateFunctionInput DAY_IN_MONTH: DateFunctionInput DAY_IN_WEEK: DateFunctionInput DAY_IN_YEAR: DateFunctionInput FISCAL_MONTH: DateFunctionInput FISCAL_QUARTER: DateFunctionInput FISCAL_YEAR: DateFunctionInput WEEK_IN_MONTH: DateFunctionInput WEEK_IN_YEAR: DateFunctionInput } ``` `DateInput` facilitates operating on Date fields by more than just the exact value of a particular Date. ``` input DateInput { value: Date # An exact Date value literal: DATE_LITERAL # a literal value for a relative time range: DateRange # a range of Dates } ``` Date literals represent a relative range of time, such as last month, this week, or next year. See [_SOQL and SOSL Reference_: Date Formats and Date Literals in WHERE Clauses](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm). ``` enum DATE_LITERAL { YESTERDAY TODAY TOMORROW LAST_WEEK THIS_WEEK NEXT_WEEK LAST_MONTH THIS_MONTH NEXT_MONTH LAST_QUARTER THIS_QUARTER NEXT_QUARTER LAST_90_DAYS NEXT_90_DAYS LAST_FISCAL_QUARTER THIS_FISCAL_QUARTER NEXT_FISCAL_QUARTER LAST_YEAR THIS_YEAR NEXT_YEAR LAST_FISCAL_YEAR THIS_FISCAL_YEAR NEXT_FISCAL_YEAR } ``` Range values for dates capture dates within a period of time. See [_SOQL and SOSL Reference_: Date Formats and Date Literals in WHERE Clauses](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm). ``` input DateRange { n_days_ago: Int n_weeks_ago: Int n_months_ago: Int n_quarters_ago: Int n_years_ago: Int n_fiscal_quarters_ago: Int n_fiscal_years_ago: Int last_n_days: Int next_n_days: Int last_n_weeks: Int next_n_weeks: Int last_n_months: Int next_n_months: Int last_n_quarters: Int next_n_quarters: Int last_n_years: Int next_n_years: Int last_n_fiscal_quarters: Int next_n_fiscal_quarters: Int last_n_fiscal_years: Int next_n_fiscal_years: Int } ``` Date functions help you convert date values to the default time zone. See [_SOQL and SOSL Reference_: Converting Time Zones in Date Functions](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_convert_time_zone.htm). ``` input DateFunctionInput { value: LongOperators # a value in UTC convertTimezoneValue: LongOperators # convert the value to the default time zone } ``` ### DateTime Fields DateTime fields map to the `DateTimeOperators` filter type. ``` input DateTimeOperators { eq: DateTimeInput ne: DateTimeInput lt: DateTimeInput gt: DateTimeInput lte: DateTimeInput gte: DateTimeInput in: [DateTimeInput] nin: [DateTimeInput] CALENDAR_MONTH: DateFunctionInput CALENDAR_QUARTER: DateFunctionInput CALENDAR_YEAR: DateFunctionInput DAY_IN_MONTH: DateFunctionInput DAY_IN_WEEK: DateFunctionInput DAY_IN_YEAR: DateFunctionInput FISCAL_MONTH: DateFunctionInput FISCAL_QUARTER: DateFunctionInput FISCAL_YEAR: DateFunctionInput WEEK_IN_MONTH: DateFunctionInput WEEK_IN_YEAR: DateFunctionInput DAY_ONLY: DateTimeFunctionInput HOUR_IN_DAY: DateFunctionInput } ``` DateTime fields map to the `DateTimeInput` filter type. ``` input DateTimeInput { value: DateTime # An exact DateTime value literal: DATE_LITERAL # a literal value for a relative time range: DateRange # a range of Dates } ``` DateTime functions help you convert date time values to the default time zone. See [_SOQL and SOSL Reference_: Converting Time Zones in Date Functions](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_convert_time_zone.htm). ``` input DateTimeFunctionInput { value: DateTimePrimitiveOperators # a value in UTC convertTimezoneValue: DateTimePrimitiveOperators # convert the value to the default time zone } ``` DateTime primitive operators allow working with DateTime values directly. ``` input DateTimePrimitiveOperators { eq: DateTime ne: DateTime lt: DateTime gt: DateTime lte: DateTime gte: DateTime in: [DateTime] nin: [DateTime] } ``` ### Time Fields Time fields map to the `TimeOperators` filter type. ``` input TimeOperators { eq: Time ne: Time lt: Time gt: Time lte: Time gte: Time in: [Time] nin: [Time] } ``` ## Boolean Field Type Boolean fields map to the `BooleanOperators` filter type. ``` input BooleanOperators { eq: Boolean ne: Boolean } ``` ## ID Field Type ID fields map to the `IdOperators` filter type. ``` input IdOperators { eq: ID ne: ID lt: ID gt: ID lte: ID gte: ID in: [ID] nin: [ID] inq: JoinInput ninq: JoinInput } ``` Either the 15-character and 18-character ID values is accepted. For example. `Account( where: { Id: { eq: "0011a000005slme" } } )` returns the same result as `Account( where: { Id: { eq: "0011a000005slmeAAA" } } )`. The `inq` and `ninq` operators (in-query and not-in-query) are of the `JoinInput` type. Use these operators to execute [semi-join and anti-join queries](https://developer.salesforce.com/docs/platform/graphql/guide/filter-joins.md). ## Picklist Field Type Picklist fields map to the `PicklistOperators` filter type. ``` input PicklistOperators { eq: Picklist gt: Picklist gte: Picklist in: [Picklist] like: Picklist lt: Picklist lte: Picklist ne: Picklist nin: [Picklist] } ``` ## Multi-Picklist Field Type Multi-picklist fields map to the `MultiPicklistOperators` filter type. ``` input MultiPicklistOperators { eq: MultiPicklist ne: MultiPicklist includes: [MultiPicklist] excludes: [MultiPicklist] } ``` ## Latitude Field Type Latitude fields map to the `LatitudeOperators` filter type. ``` input LatitudeOperators { eq: Latitude ne: Latitude lt: Latitude gt: Latitude lte: Latitude gte: Latitude in: [Latitude] nin: [Latitude] } ``` ## Longitude Field Type Longitude fields map to the `LongitudeOperators` filter type. ``` input LongitudeOperators { eq: Longitude ne: Longitude lt: Longitude gt: Longitude lte: Longitude gte: Longitude in: [Longitude] nin: [Longitude] } ``` ## Geolocation Field Types A compound field of type Geolocation maps to the `GeolocationOperators` filter type. ``` GeolocationOperators { lt: GeolocationInput gt: GeolocationInput } ``` For `GeolocationOperators`, the `lt` and `gt` operators are of the `GeolocationInput` type. ``` GeolocationInput { latitude: Latitude! longitude: Longitude! radius: Float! unit: Unit! # MI or KM } ``` Use the geolocation operators to run [location-based queries](https://developer.salesforce.com/docs/platform/graphql/guide/filter-location.md). ## Example Arguments Here are a few sample arguments to demonstrate how to filter on a field. ``` where: { Id: { eq: "001xx000003GYQxAAO" } } ``` ``` where: { Id: { in: [ "001xx000003GYQxAAO", "001xx000003GYQxAA1" ] } } ``` ``` where: { NextStep: { ne: null } } ``` ``` where: { Name: {like: "%erv" } } ``` ``` where: { SchedStartTime: { gte: { range: { last_n_months: 4 } } } } ``` ``` where: { CreatedDate: { lte: { range: { n_days_ago: 2 } } } } ``` ``` where: { CreatedDate: { eq: { literal: TODAY } } } ``` ``` where: { CreatedDate : { CALENDAR_YEAR: { value: { eq: 2022 } } } } ``` ``` where: { LastModifiedDate: { gte: { value: "2022-06-12T03:29:56.901Z"} } } ``` This example uses multiple operations on a single operator type. The two conditions are AND'd together. ``` where: { AnnualRevenue: { gt: 10000, lt: 100000 } } ``` ## Example Queries This example finds opportunities whose `NextStep` equals "Need estimate". ``` query opportunitiesClosingSoon { uiapi { query { Opportunity( where: { NextStep: { eq: "Need estimate" } } ) { edges { node { Id NextStep { value } CloseDate { value displayValue } } } } } } } ``` This example queries accounts whose names match a given string. ``` query accountsWithFilter($where: Account_Filter = {Name: {like: "Burlington%"}}) { uiapi { query { Account(where: $where) { edges { node { Id Name { value } } } } } } } ``` This example finds accounts with an annual revenue of more than 1 million. ``` query AccountsGTE1M { uiapi { query { Account( where: { AnnualRevenue: { gte: 1000000 } } ) { edges { node { Id Name { value } } } } } } } ``` # Filter Results Filter objects are used to filter the result set of records. All sObjects in the schema have a corresponding `Filter` type created, which combines the object API name with the `_Filter` suffix. For example, `Account` has a corresponding `Account_Filter` type created. ``` Account( first: Int after: String scope: ACCOUNT_SCOPE orderBy: Account_OrderBy where: Account_Filter ): AccountConnection # the "Account" field returns the "AccountConnection" type ``` Filter your results using a combination of [field operators](https://developer.salesforce.com/docs/platform/graphql/guide/filter-fields.md), [boolean operators](https://developer.salesforce.com/docs/platform/graphql/guide/filter-boolean.md), and more. For example, you can filter through a [parent relationship](https://developer.salesforce.com/docs/platform/graphql/guide/filter-parent.md) or use [a semi-join or anti-join](https://developer.salesforce.com/docs/platform/graphql/guide/filter-joins.md). # Get Current User Record | AVAILABLE API VERSION | | --------------------- | | API v66.0 and later | The `currentUser` type returns the currently logged-in user’s User record data, even if the caller doesn’t know the user ID. The response always represents the current user. You can request any fields that are available on the [User](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_user.htm) record. To query or aggregate multiple users or use complex filtering, sorting, or pagination, use the `RecordQuery` type for the User object instead. See [Query Objects](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.md). To get the current user record, use `currentUser` in the `uiapi` field. ``` { uiapi { currentUser{ # User fields } } } ``` ## Current User Schema Query `currentUser` by using this schema. ``` type UIAPI { currentUser: RecordRepresentation } ``` ## Example: Query Current User This example fetches the ID and name for the current user. ``` { uiapi { currentUser{ Id Name { value } } } } ``` The response includes the fields that you request. For example, the previous query returns this response. ``` { "data": { "uiapi": { "currentUser": { "Id": "005xx000001X7sHAAS", "Name": { "value": "User‘s Name" } } } }, "errors": [], "extensions": {} } ``` # Get Lookup Values | AVAILABLE API VERSION | | --------------------- | | API v68.0 and later | The `lookupValues` field of `LookupValues` type provides lookup search for Salesforce lookup and relationship fields. The GraphQL lookup values feature mirrors the UI API [Get Lookup Field Suggestions With POST](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_lookup_post.htm) resource. The response includes matching records and display metadata for lookup target object types. This feature supports type-ahead search, recent lookups, and full search capabilities. Pass in `lookupValues` in the `uiapi` field. For example, use `objectApiName: "Opportunity"` and `fieldApiName: "AccountId"` to return lookup values for the account lookup field on the opportunity object. ``` { uiapi { lookupValues(objectApiName: "Opportunity", fieldApiName: "AccountId") { # fields } } } ``` ## Lookup Values Schema Query `lookupValues` by using this schema. ``` type UIAPI { lookupValues( objectApiName: String! fieldApiName: String! q: String searchType: LookupSearchType targetApiName: String sourceRecord: RecordSnapshotInput ): [LookupValues!] } ``` The `lookupValues` type has these arguments. - `objectApiName` - The object API name of a [supported object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). This argument is required. - `fieldApiName` - The API name of the lookup or reference field on the object. This argument is required. - `q` - Search query string for filtering lookup results. This argument is required with `TYPE_AHEAD` and `SEARCH` search types. - `searchType` - Search strategy that the [LookupSearchType enum](#lookupsearchtype) provides. Default value is `RECENT`. - `targetApiName` - For polymorphic lookup fields, filters results to a specific target object type. - `sourceRecord` - A `RecordSnapshotInput` type with the record’s live, possibly unsaved, field values for filtered lookups that depend on other field values on the source record. This argument must contain only one top-level key and it must use the `ObjectApiName`, for example, `Opportunity: OpportunitySnapshotFields`. ## LookupValues Type The `LookupValues` type returns matching records and display metadata for a single lookup target object type. ``` type LookupValues { targetApiName: String! records(first: Int, after: String, orderBy: RecordLookupOrderBy): RecordLookupConnection secondaryField: String suggestionsInfo: LookupDisplayInfo advancedDisplayFields: [LookupAdvancedDisplayInfoField!] } ``` The `LookupValues` type contains these fields. - `targetApiName` - API name of the target object type for this lookup result set. - `records` - A [RecordLookupConnection](#recordlookupconnection-type) with relay-style paginated matching records. - `first` - Number of records per page. Default value is `10`. - `after` - Returns the results after the given cursor. - `orderBy` - A `RecordLookupOrderBy` type that accepts one field per target object, named after the object’s search type, such as `OpportunitySearch`. This argument isn’t supported for recent or type-ahead search types. - `secondaryField` - API name of the secondary field to display alongside the primary name field. - `suggestionsInfo` - Display layout and matching field configuration for lookup suggestions. - `advancedDisplayFields` - Column configuration for the Advanced Lookup modal. ## RecordLookupConnection Type The `RecordLookupConnection` type represents a result set of lookup records that ties together the records and page info. ``` type RecordLookupConnection { edges: [RecordLookupEdge] pageInfo: PageInfo! totalCount: Int } ``` The `RecordLookupConnection` type contains these fields. - `edges` - A list of RecordLookupEdge types. - `pageInfo` - Information about the relative location in the result set. - `totalCount` - This value is always null because the lookup service doesn’t provide a total count. ## RecordLookupEdge Type The `RecordLookupEdge` type ties together the record and its cursor. ``` type RecordLookupEdge { node: RecordLookupPayload cursor: String! } ``` The `RecordLookupEdge` type contains these fields. - `node` - A RecordLookupPayload containing the record and secondary field value. - `cursor` - An opaque string used to page directly to this item in the result set. ## RecordLookupPayload Type The `RecordLookupPayload` type wraps a search record returned in lookup results. ``` type RecordLookupPayload { Record: RecordSearch SecondaryFieldValue: String } ``` The `RecordLookupPayload` type contains these fields. - `Record` - A RecordSearch record matching the lookup query. - `SecondaryFieldValue` - Value of the secondary display field for this record. ## RecordSearch Interface The `RecordSearch` interface is a marker interface for search record results. Field types are limited to those returnable by the search RETURNING clause. ``` interface RecordSearch { Id: ID! ApiName: String! DisplayValue: String WeakEtag: Long! LastModifiedById: IDValue LastModifiedDate: DateTimeValue SystemModstamp: DateTimeValue RecordTypeId: IDValue } ``` The `RecordSearch` interface contains these fields. - `Id` - The record ID. - `ApiName` - The API name of the record’s object type. - `DisplayValue` - The display value for the record (typically the name field). - `WeakEtag` - The weak entity tag for the record. - `LastModifiedById` - ID of the user who last modified the record. - `LastModifiedDate` - Date and time when the record was last modified. - `SystemModstamp` - System modification timestamp. - `RecordTypeId` - ID of the record type, if applicable. ## LookupDisplayInfo Type The `LookupDisplayInfo` type describes fields to display and fields to match on for lookup suggestions. ``` type LookupDisplayInfo { displayFields: [String!]! matchingFields: [String!]! } ``` The `LookupDisplayInfo` type contains these fields. - `displayFields` - List of field API names to display in lookup results. - `matchingFields` - List of field API names to match against the search query. ## LookupAdvancedDisplayInfoField Type The `LookupAdvancedDisplayInfoField` type describes a single field entry in the advanced lookup display configuration. ``` type LookupAdvancedDisplayInfoField { label: String objectApiName: String fieldPath: String } ``` The `LookupAdvancedDisplayInfoField` type contains these fields. - `label` - Display label for the field. - `objectApiName` - API name of the object containing the field. - `fieldPath` - Path to the field for relationship fields. ## Enumeration Types The `lookupValues` type has these enumerations. ### LookupSearchType The `LookupSearchType` enumeration specifies the search strategy for the lookup field. ``` enum LookupSearchType { RECENT TYPE_AHEAD SEARCH } ``` - `RECENT` - Returns most recently used records for the lookup field in order of recency and doesn’t support custom ordering. - `TYPE_AHEAD` - Returns records matching the query string for type-ahead suggestions in order of relevance and doesn’t support custom ordering or after cursor ordering. - `SEARCH` - Performs a full search across the target object. ## See Also [Get Lookup Values Examples](https://developer.salesforce.com/docs/platform/graphql/guide/query-lookup-values-examples.md) # Get Lookup Values Examples | AVAILABLE API VERSION | | --------------------- | | API v68.0 and later | ## Get Most Recently Used Records for a Lookup Field This example gets the most recently used account record lookup values for the opportunity object. ``` { uiapi { lookupValues( objectApiName: "Opportunity" fieldApiName: "AccountId" searchType: RECENT ) { targetApiName records { edges { node { Record { Id DisplayValue } } } pageInfo { hasNextPage endCursor } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "lookupValues": [ { "targetApiName": "Account", "records": { "edges": [ { "node": { "Record": { "Id": "001LT00000DzUzQYAV", "DisplayValue": "fong", "ApiName": "Account" } } }, { "node": { "Record": { "Id": "001LT00000DzUzOYAV", "DisplayValue": "Acme12", "ApiName": "Account" } } } ], "pageInfo": { "hasNextPage": false, "endCursor": "djE6MTE=" } } } ] } }, "errors": [], "extensions": {} } ``` ## Search with Object-Specific Fields and Metadata This example searches for accounts on the opportunity object. ``` { uiapi { lookupValues( objectApiName: "Opportunity" fieldApiName: "AccountId" searchType: SEARCH q: "acme" ) { targetApiName secondaryField suggestionsInfo { displayFields matchingFields } records( first: 10 orderBy: { AccountSearch: { Name: { order: ASC } } } ) { edges { node { SecondaryFieldValue Record { Id ApiName DisplayValue ... on AccountSearch { Name { value displayValue } Industry { value displayValue } BillingCity { value displayValue } } } } } pageInfo { hasNextPage endCursor } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "lookupValues": [ { "targetApiName": "Account", "secondaryField": "Site", "suggestionsInfo": { "displayFields": [ "Name", "Site" ], "matchingFields": [ "Name" ] }, "records": { "edges": [ { "node": { "SecondaryFieldValue": null, "Record": { "Id": "001LT00000DzV0RYAV", "ApiName": "Account", "DisplayValue": "acme", "Name": { "value": "acme", "displayValue": "acme" }, "Industry": { "value": null, "displayValue": null }, "BillingCity": { "value": null, "displayValue": null } } } }, { "node": { "SecondaryFieldValue": null, "Record": { "Id": "001LT00000DzUzOYAV", "ApiName": "Account", "DisplayValue": "Acme12", "Name": { "value": "Acme12", "displayValue": "Acme12" }, "Industry": { "value": "Manufacturing", "displayValue": "Manufacturing" }, "BillingCity": { "value": "New York", "displayValue": "New York" } } } } ], "pageInfo": { "hasNextPage": false, "endCursor": "djE6Mg==" } } } ] } }, "errors": [], "extensions": {} } ``` ## Get Lookup Values for a Polymorphic Field This example gets lookup values for the polymorphic contact ID field on cases. ``` { uiapi { lookupValues( objectApiName: "Case" fieldApiName: "ContactId" searchType: SEARCH q: "john" ) { targetApiName records { edges { node { SecondaryFieldValue Record { Id DisplayValue ... on UserSearch { Name { value } Email { value } } ... on GroupSearch { Name { value } } } } } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "lookupValues": [ { "targetApiName": "Contact", "records": { "edges": [ { "node": { "SecondaryFieldValue": null, "Record": { "Id": "003LT00000D26oDYAR", "DisplayValue": "John Amos" } } }, { "node": { "SecondaryFieldValue": null, "Record": { "Id": "003LT000001CFqlYAG", "DisplayValue": "Jon Amos" } } } ] } } ] } }, "errors": [], "extensions": {} } ``` ## See Also [Get Lookup Values](https://developer.salesforce.com/docs/platform/graphql/guide/query-lookup-values.md) # Get Object Layouts | AVAILABLE API VERSION | | --------------------- | | API v66.0 and later | The `recordLayouts` field of `LayoutConnection` type returns page layout metadata for objects. The response includes sections, rows, items, and polymorphic components, matching the [User Interface REST API Record Layout](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_responses_record_layout.htm). Pass in `recordLayouts` in the `uiapi` field. For example, use `objectApiName: ["Account"]` to return the page layout metadata for the account object. ``` { uiapi { recordLayouts(objectApiName: ["Account"]) { # fields } } } ``` ## Record Layout Schema Query `recordLayouts` by using this schema. ``` type UIAPI { recordLayouts( objectApiName: String! recordTypeIds: [Id!] layoutConfigs: [LayoutConfig!] layoutType = "FULL": LayoutType formFactor = "LARGE": FormFactor mode = "VIEW": LayoutMode first: Int after: String ): LayoutConnection } input LayoutConfig {recordTypeId: ID!, formFactor: FormFactor, mode: LayoutMode } ``` The `recordLayouts` type has these arguments. - `objectApiName` - The object API name of a [supported object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). This argument is required. - `recordTypeIds` - A list of up to 10 record type IDs. - `layoutConfigs` - An array of `layoutConfig` types with these arguments to request different form factor and mode combinations per record type. - `recordTypeId` - A record type ID. - `formFactor` - Form factor that the [FormFactor enum](#formfactor) provides for the record type layout. Default value is `LARGE`. - `mode` - Mode that the [LayoutMode enum](#layoutmode) provides for the record type layout. Default value is `VIEW`. - `layoutType` - Layout type that the [LayoutType enum](#layouttype) provides. Default value is `FULL`. - `formFactor` - Default form factor that the [FormFactor enum](#formfactor) provides for all layouts. Default value is `LARGE`. - `mode` - Default mode that the [LayoutMode enum](#layoutmode) provides for all layouts. Default value is `VIEW`. - `first` - Number of layouts per page. Specify up to 10 layouts. Default value is `10`. - `after` - Returns the results after the given cursor. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ## LayoutConnection Type The `LayoutConnection` type represents a result set of record layouts that ties together the layouts and page info. Layouts are paginated by record type, with each edge representing one layout for one record type. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ``` type LayoutConnection { edges: [LayoutEdge!] pageInfo: PageInfo! totalCount: Int! } ``` The `LayoutConnection` type contains these fields. - `edges` - A list of LayoutEdge types. - `pageInfo` - Information about the relative location in the result set. - `totalCount` - The number of records that are queried. ## LayoutEdge Type The `LayoutEdge` type ties together the record and its cursor. ``` type LayoutEdge { node: Layout cursor: String! } ``` The `LayoutEdge` type contains these fields. - `node` - One layout for one record type. - `cursor` - An opaque string used to page directly to this item in the result set. ## Layout Type The `Layout` type is the layout for the record type, matching the User Interface [Record Layout](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_responses_record_layout.htm) representation. ``` type Layout { id: ID layoutType: LayoutType mode: LayoutMode objectApiName: String! recordTypeId: ID saveOptions: [LayoutSaveOption!] sections: [LayoutSection!] } ``` The `Layout` type contains these fields. - `id` - ID of the layout. - `layoutType` - Layout type that the [LayoutType enum](#layouttype) provides. - `mode` - Mode that the [LayoutMode enum](#layoutmode) provides. - `objectApiName` - API name of the object that the layout is associated with. - `recordTypeId` - Record type ID. - `saveOptions` - A list of save options for the layout. - `sections` - A list of layout sections. ## LayoutSaveOption Type The `LayoutSaveOption` type is the save option for a record layout. Save options define behavior that occurs when objects are created or modified using the given layout. For example, for Cases and Leads, a “UseDefaultAssignmentRule” save option is exposed to control whether assignment rules are applied when Cases or Leads are created or edited. ``` type LayoutSaveOption { defaultValue: Boolean! isDisplayed: Boolean! label: String! name: String! restHeaderName: String soapHeaderName: String } ``` The `LayoutSaveOption` type contains these fields. - `defaultValue` - Indicates whether the save option defaults to enabled. - `isDisplayed` - Indicates whether the save option is displayed in the layout. - `label` - Label for the save option. - `name` - API name for the save option. - `restHeaderName` - REST API header for the save option. - `soapHeaderName` - SOAP API header for the save option. ## LayoutSection Type The `LayoutSection` type is a section in a record layout. ``` type LayoutSection { collapsible: Boolean! columns: Int! heading: String id: ID layoutRows: [LayoutRow!] rows: Int! tabOrder: TabOrder useHeading: Boolean! } ``` The `LayoutSection` type contains these fields. - `collapsible` - Indicates whether the section can be collapsed. - `columns` - Number of columns in the section. - `heading` - Heading text for the section. - `id` - ID of the section. - `layoutRows` - List of rows in the section. - `rows` - Number of rows in the section. - `tabOrder` - Tab order that the [TabOrder enum](#taborder) provides for the section. - `useHeading` - Indicates whether to display the heading text. ## LayoutRow Type The `LayoutRow` type is a row in a record layout. ``` type LayoutRow { layoutItems: [LayoutItem!] } ``` The `LayoutRow` type contains these fields. - `layoutItems` - A collection of items in the row, from left to right. Might not extend to the last column. ## LayoutItem Type The `LayoutItem` type is an item in a record layout. ``` type LayoutItem { editableForNew: Boolean! editableForUpdate: Boolean! label: String! layoutComponents: [LayoutComponent!] lookupIdApiName: String required: Boolean! sortable: Boolean! uiBehavior: UiBehavior } ``` The `LayoutItem` type contains these fields. - `editableForNew` - Indicates whether the item can be edited when creating a record. - `editableForUpdate` - Indicates whether the item can be edited when updating a record. - `label` - Text label for the item. - `layoutComponents` - List of components that make up the item. - `lookupIdApiName` - ID field name of a lookup field. - `required` - Indicates whether the field is required in a layout when creating or updating a record. This information is useful if you want to render required fields with a different treatment, such as a red outline. - `sortable` - Indicates whether the item is sortable. - `uiBehavior` - UI behavior that the [UiBehavior enum](#uibehavior) provides for the page and mini layout item. For other types of layouts, such as compact or quick action, the field is `null`. The value doesn’t reflect user-level or profile-level access. ## LayoutComponent Interface The `LayoutComponent` interface is polymorphic with six concrete implementations. The `componentType` field for each concrete implementation indicates the type. ``` interface LayoutComponent { apiName: String componentType: LayoutComponentType! } ``` The `LayoutComponent` interface contains these fields. - `apiName` - API name of the component. - `componentType` - Layout component type that the [LayoutComponentType enum](#layoutcomponenttype) provides. ### CanvasLayoutComponent The `CanvasLayoutComponent` is a canvas component on a record layout. ``` type CanvasLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! displayLocation: String height: String referenceId: ID showScroll: Boolean width: String } ``` The `CanvasLayoutComponent` type contains these fields. - `apiName` - API name of the canvas app. - `componentType` - Value is `CANVAS`. - `displayLocation` - Location in the application that is calling the canvas app. - `height` - Height of the component. - `referenceId` - Unique ID of the canvas app definition. - `showScroll` - Indicates whether to show the scroll bar on the canvas component. - `width` - Width of the component. ### CustomLinkLayoutComponent The `CustomLinkLayoutComponent` is a custom link component on a record layout. ``` type CustomLinkLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! behavior: WeblinkWindowType customLinkUrl: String label: String } ``` The `CustomLinkLayoutComponent` type contains these fields. - `apiName` - If a field powers this component, the API name of the field. - `componentType` - Value is `CUSTOM_LINK`. - `behavior` - Link behavior that the [WeblinkWindowType enum](#weblinkwindowtype) provides. - `customLinkUrl` - Custom link URL. - `label` - Custom link label. ### EmptySpaceLayoutComponent The `EmptySpaceLayoutComponent` is an empty placeholder space. ``` type EmptySpaceLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! } ``` The `EmptySpaceLayoutComponent` type contains these fields. - `apiName` - If the component is powered by a field, the API name of the field. - `componentType` - Value is `EMPTY_SPACE`. ### FieldLayoutComponent The `FieldLayoutComponent` is a standard field on a record layout. ``` type FieldLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! label: String } ``` The `FieldLayoutComponent` type contains these fields. - `apiName` - API name of the field. - `componentType` - Value is `FIELD`. - `label` - Label of the field. ### ReportLayoutComponent The `ReportLayoutComponent` is an embedded report chart component on a record layout. ``` type ReportLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! cacheData: Boolean error: String filter: String hideOnError: Boolean placeholder: String reportId: ID showTitle: Boolean size: String } ``` The `ReportLayoutComponent` type contains these fields. - `apiName` - If a field powers this component, the API name of the field. - `componentType` - Value is `REPORT_CHART`. - `cacheData` - Indicates whether to cache data. - `error` - Error message. - `filter` - Filter for the report. - `hideOnError` - Indicates whether to hide the component if there’s an error. - `placeholder` - Placeholder for the report. - `reportId` - Component’s report ID. - `showTitle` - Indicates whether to show the report’s title. - `size` - Size of the component. ### VisualforceLayoutComponent The `VisualforceLayoutComponent` is an embedded Visualforce component on a record layout. ``` type VisualforceLayoutComponent implements LayoutComponent { apiName: String componentType: LayoutComponentType! height: String showLabel: Boolean showScroll: Boolean visualforceUrl: String width: String } ``` The `VisualforceLayoutComponent` type contains these fields. - `apiName` - If a field powers this component, the API name of the field. - `componentType` - Value is `VISUALFORCE_PAGE`. - `height` - Height of the component. - `showLabel` - Indicates whether to show the section label with the component. - `showScroll` - Indicates whether to show the scroll bar on the component. - `visualforceUrl` - Visualforce URL. - `width` - Width of the component. ## PageInfo Type The `PageInfo` type contains relative position information, which shows where in the entire result set the current page is located. The `PageInfo` type is the same for every `Connection` type. See [PageInfo Type](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.md#pageinfo-type). ## Enumeration Types The `recordLayouts` type has these enumerations. ### FormFactor The `FormFactor` enumeration specifies the layout display size for the record. The `LARGE` value is for desktop, the `MEDIUM` value is for tablet, and the `SMALL` value is for phone. ``` enum FormFactor { LARGE MEDIUM SMALL } ``` ### LayoutComponentType The `LayoutComponementType` enumeration indicates the layout component type. ``` enum LayoutComponentType { CANVAS CUSTOM_LINK EMPTY_SPACE FIELD REPORT_CHART VISUALFORCE_PAGE } ``` ### LayoutMode The `LayoutMode` enumeration specifies the access mode for the record. The value determines which fields to get from a layout. Layouts have different fields for create, edit, and view modes. For example, formula fields are rendered in view mode, but not in create mode because they’re calculated at run time, like formulas in a spreadsheet. ``` enum LayoutMode { CREATE EDIT VIEW } ``` ### LayoutType The `LayoutType` enumeration specifies the layout type for the record. The `COMPACT` value indicates a layout that contains a record's key fields only. ``` enum LayoutType { FULL COMPACT } ``` ### TabOrder The `TabOrder` enumeration specifies the tab order for the items in a section. ``` enum TabOrder { LEFT_RIGHT TOP_DOWN } ``` ### UiBehavior The `UiBehavior` enumeration indicates the layout item behavior on page and mini layouts. The value doesn’t reflect user-level or profile-level access. ``` enum UiBehavior { EDIT REQUIRED READONLY } ``` ### WeblinkWindowType The `WeblinkWindowType` enumeration indicates how a link behaves on open. ``` enum WeblinkWindowType { NEW_WINDOW NO_SIDEBAR ONCLICK_JAVASCRIPT REPLACE SIDEBAR } ``` ## See Also [Get Record Layout Examples](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-layouts-examples.md) # Get Object Layouts Examples | AVAILABLE API VERSION | | --------------------- | | API v66.0 and later | ## Get Object Layout This example gets the layout for the account object. ``` { uiapi { recordLayouts(objectApiName: "Account") { edges { node { id layoutType mode objectApiName recordTypeId sections { heading columns rows collapsible layoutRows { layoutItems { label required editableForNew editableForUpdate uiBehavior layoutComponents { apiName componentType } } } } } } pageInfo { hasNextPage endCursor } totalCount } } } ``` ## Get Object Layout with a Record Type and Mode This example gets the layout for the opportunity object with a record type and a mode. ``` { uiapi { recordLayouts( objectApiName: "Opportunity" recordTypeIds: ["012000000000000AAA"] mode: EDIT layoutType: FULL formFactor: LARGE ) { edges { node { id mode sections { heading layoutRows { layoutItems { label required layoutComponents { apiName componentType } } } } saveOptions { name label defaultValue isDisplayed } } } } } } ``` ## Get Object Layout with Record Type Overrides This example gets the case layout with per-record-type mode and form factor overrides. ``` { uiapi { recordLayouts( objectApiName: "Case" layoutConfigs: [ { recordTypeId: "012000000000001AAA", mode: EDIT, formFactor: LARGE } { recordTypeId: "012000000000002AAA", mode: VIEW, formFactor: SMALL } ] ) { edges { node { recordTypeId mode sections { heading layoutRows { layoutItems { label layoutComponents { apiName componentType } } } } } } } } } ``` ## Get Object Layout with Pagination This example gets the account layout with pagination. ``` { uiapi { recordLayouts(objectApiName: "Account", first: 5) { edges { node { id recordTypeId } cursor } pageInfo { hasNextPage endCursor } totalCount } } } ``` This example gets the next page. ``` { uiapi { recordLayouts(objectApiName: "Account", first: 5, after: "") { edges { node { id recordTypeId } cursor } pageInfo { hasNextPage endCursor } } } } ``` ## Get Object Layout with Polymorphic Components This example gets the account layout with polymorphic components with inline fragments. ``` { uiapi { recordLayouts(objectApiName: "Account") { edges { node { sections { layoutRows { layoutItems { label layoutComponents { apiName componentType ... on FieldLayoutComponent { label } ... on VisualforceLayoutComponent { visualforceUrl height width showLabel showScroll } ... on CanvasLayoutComponent { referenceId displayLocation height width } ... on CustomLinkLayoutComponent { customLinkUrl label behavior } ... on ReportLayoutComponent { reportId filter size showTitle hideOnError cacheData } } } } } } } } } } ``` ## See Also [Get Object Layouts](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-layouts.md) # Get Object Metadata | AVAILABLE API VERSION | | ------------------------------------------------ | | API v56.0 and later | | Locale available in API v60.0 and later | | Picklist values available in API v65.0 and later | The `objectInfos` field of `ObjectInfo` type returns object metadata, such as whether an object is MRU enabled and whether an object is searchable or updateable. You can also retrieve picklist values when querying object metadata. The response includes metadata describing fields, child relationships, record type, and theme. You can request up to 2,000 objects in a single object metadata request. Pass in `objectInfos` in the `uiapi` field. For example, use `apiNames: ["Account"]` to return the object info for the account object. ``` { uiapi { objectInfos(apiNames: ["Account"]) { # fields } } } ``` ## Object Info Schema Query `objectInfos` with this schema. ``` type UIAPI { query: RecordQuery objectInfos( apiNames: [String] locale: String objectInfoInputs: [ObjectInfoInput!] ): [ObjectInfo] } input ObjectInfoInput {apiName: String!, recordTypeIds: [ID!], fieldNames: [String!] } ``` The `objectInfos` type is an array of `ObjectInfo` types with these arguments. - `apiNames` - A list of up to 2,000 object API names of [supported objects](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). It’s non-nullable, which means you can expect an array of zero or more items. - `locale` - Specifies which [locale](https://help.salesforce.com/s/articleView?id=xcloud.admin_supported_locales.htm) to use for the object’s labels. Defaults to the user’s locale. This argument is available in API v60.0 and later. - `objectInfoInputs` - Get picklist values along with object metadata without making multiple calls. This argument is available in API v65.0 and later. The `objectInfoInputs` argument is an array of `ObjectInfoInput` types with these arguments. - `apiName` - The API name of a [supported object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). This argument is required. - `recordTypeIds` - A list of record type IDs. An empty list, `[]`, retrieves picklist values for all record types for the `apiName` object. - `fieldNames` - A list of fields to filter on. The query returns picklist values only for the fields specified. A `null` or empty list, `[]`, retrieves picklist values for all picklist fields on the object. **note:** To retrieve object metadata without picklist values, you can either omit the `objectInfoInputs` argument or provide only `apiName` in the `objectInfoInputs` argument, such as `objectInfoInputs: {apiName: "Account"}`. ## ObjectInfo Types and Fields The `ObjectInfo` type includes fields for the object metadata. ``` type ObjectInfo { ApiName: String! childRelationships: [ChildRelationship]! creatable: Boolean! custom: Boolean! defaultRecordTypeId: ID deletable: Boolean! dependentFields: [DependentField]! feedEnabled: Boolean! fields: [Field]! keyPrefix: String label: String labelPlural: String layoutable: Boolean! mruEnabled: Boolean! nameFields: [String]! queryable: Boolean! recordTypeInfos: [RecordTypeInfo]! searchable: Boolean! themeInfo: ThemeInfo updateable: Boolean! locale: String } ``` The `ObjectInfo` type contains these fields. - `ApiName` - A [supported object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). Note the different case in `ApiName` compared to the `objectInfos` type argument `apiName` discussed in the first section. - `childRelationships` - The object’s [child relationships](#childrelationship). - `creatable` - Indicates whether the object can be created. - `custom` - Indicates whether the object is a custom object. - `defaultRecordTypeId` - The ID for the default record type for this object. If there isn’t a default record type, this value is the master record type, which is `012000000000000AAA`. If the record is a nested record (for example, in a request for an Account, the User object is a nested record), the value is null. - `deletable` - Indicates whether the object can be deleted. - `dependentFields` - The object’s [dependent fields](#dependentfield) returned as a list of key and values. - `feedEnabled` - Indicates whether the object can have feeds. - `fields` - A [field’s metadata](#field). This map only contains fields relevant to the requested layout and mode. It’s non-nullable, which means you can expect an array of zero or more items. - `keyPrefix` - The key prefix for IDs of this object. - `label` - The object’s display label. - `labelPlural` - The plural form of the object’s display label. - `layoutable` - Indicates whether the object can have a layout. - `mruEnabled` - Indicates whether the object can appear in Most Recently Used lists. - `nameFields` - A list of the API names of the fields used to identify the name field for standard and custom objects. Typically there’s one name field per object, except when the object has `FirstName` and `LastName` fields. - `queryable` - Indicates whether the context user can query the object. - `recordTypeInfos` - A list of [record type information](#recordtypeinfo) about the record type. All record types are visible whether the user has access to them. - `searchable` - Indicates whether the object can be searched. - `themeInfo` - [Theme information](#themeinfo) for the object. - `updateable` - Indicates whether the object can be updated. - `locale` - The locale for the object’s labels. This field is available in API v60.0 and later. ### ChildRelationship The `ChildRelationship` type represents the child relationship on a parent object. For example, you can return data about related object records on a record’s detail page. GraphQL API enables you to query the object info of all the child relationships by using the `objectInfo` field. ``` type ChildRelationship { childObjectApiName: String! fieldName: String junctionIdListNames: [String]! junctionReferenceTo: [String]! objectInfo: ObjectInfo relationshipName: String ``` The `ChildRelationship` type contains these fields. - `childObjectApiName` - The API name of the child object. - `fieldName` - The field on the child object that contains the reference to the parent object. Salesforce uses a reference field to store the ID of the related parent record. - `junctionIdListNames` - The names of the `JunctionIdList` fields associated with an object. Each ID is a polymorphic key, which is an ID that can refer to more than one type of object. - `junctionReferenceTo` - A collection of object names that the polymorphic keys in the `junctionIdListNames` property can reference. - `objectInfo` - The [object’s metadata](#objectinfo-types-and-fields). - `relationshipName` - The name of the relationship. The name is the plural form of the child object name. For example, Account has a `relationshipName` for each object: Assets, Cases, and Contacts. ### DependentField The `DependentField` type contains information about a dependent field that relies on the value of a controlling field. For example, a picklist with a list of cities depends on a controlling picklist field that shows a list of countries. Selecting a value on a controlling field filters down the values in a dependent field. ``` type DependentField { controllingField: String! dependentFields: [String]! } ``` The `DependentField` type contains these fields. - `controllingField` - Standard and custom checkboxes and picklists with at least one and less than 300 values can be controlling fields. - `dependentFields` - A list of dependent fields, such as custom picklists or multi-select picklists. Queries return dependent fields as a list of keys and values. ``` "dependentFields" : [ { "controllingField" : "Continents__c", "dependentFields" : ["Countries__c"] }, { "controllingField" : "Countries__c", "dependentFields" : ["Cities__c"] }, "controllingField" : "Cities__c", "dependentFields" : [] # Cities__c doesn't correspond to any dependent fields ] ``` ### Field The `Field` interface defines a field’s metadata. ``` type Field { ApiName: String! calculated: Boolean! compound: Boolean! compoundComponentName: String compoundFieldName: String controllerName: String controllingFields: [String]! creatable: Boolean! custom: Boolean! dataType: DataType defaultedOnCreate: Boolean! extraTypeInfo: FieldExtraTypeInfo filterable: Boolean! filteredLookupInfo: FilteredLookupInfo highScaleNumber: Boolean! htmlFormatted: Boolean! inlineHelpText: String label: String nameField: Boolean! polymorphicForeignKey: Boolean precision: Int reference: Boolean! referenceTargetField: String referenceToInfos: [ReferenceToInfo]! relationshipLabel: String relationshipName: String required: Boolean! scale: Int searchPrefilterable: Boolean sortable: Boolean! updateable: Boolean! } ``` The `Field` interface contains these fields. - `ApiName` - The API name for this field. - `calculated` - Indicates whether the field is a custom formula field. - `compound` - Indicates whether the field is a top-level compound field. If the `dataType` is `Location`, this value is usually `false`. - `compoundComponentName` - If the field is a component field of a compound field, the value is the normalized component name, otherwise the value is null. For example, if the field represents `BillingStreet` of an Address compound field, this value contains `Street`. - `compoundFieldName` - If the field is a component field of a compound field, `compoundFieldName` contains the top-level compound field. Otherwise, the value is null. - `controllerName` - If the field is a dependent picklist, `controllerName` is the name of the field that controls the values of the picklist. - `controllingFields` - If the field is a dependent picklist, `controllingFields` is a list of fields that control the values in the picklist. When there’s a hierarchy of controlling fields, the list starts with the immediate parent and moves up the tree. - `creatable` - Indicates whether the field can be created. - `custom` - Indicates whether the field is a custom field. - `dataType` - The field type that the [DataType enum](#enumeration-types) provides. - `defaultedOnCreate` - Indicates whether the field is automatically assigned a default value during record creation. This field is available in API v67.0 and later. - `extraTypeInfo` - Data type information that the [FieldExtraTypeInfo enum](#enumeration-types) provides. - `filterable` - Indicates whether the field is filterable. If true, then you can specify this field in the `where` argument. - `filteredLookupInfo` - If the field is a reference field type with a lookup filter, this value contains the lookup information. See [FilteredLookupInfo](#filteredlookupinfo). - `highScaleNumber` - Indicates whether the field stores numbers to 8 decimal places regardless of what’s specified in the field details. - `htmlFormatted` - Indicates whether the field is formatted for HTML and is encoded for display in HTML. Also indicates whether a field is a custom formula field that has an IMAGE text function. - `inlineHelpText` - The text that appears in the field-level help hover text. - `label` - Text label that appears next to the field in the Salesforce user interface. - `nameField` - Indicates whether the field is a name field. - `polymorphicForeignKey` - Indicates whether the field is a foreign key over a domain of multiple objects. - `precision` - For double fields, indicates the maximum number of digits that can be stored, on both sides of the decimal point. - `reference` - Indicates whether the field is a foreign key to another record. A reference field contains an ID value that points to a unique record (usually the parent record) on another object. - `referenceTargetField` - For indirect lookup relationships on external objects, this property is the target custom field of the referenced object. - `referenceToInfos` - For fields that refer to other objects, this list includes information about the object types and name fields of the referenced objects. See [ReferenceToInfo](#referencetoinfo). - `relationshipLabel` - The localized label of the `relationshipName` field. - `relationshipName` - The name of the relationship, if this relationship is a master-detail relationship field. - `required` - Indicates whether the field is required when creating or editing a record. - `scale` - For double fields, indicates the number of digits to the right of the decimal point. - `searchPrefilterable` - Indicates whether you can include a foreign key (relationship field) in the [`where` argument](https://developer.salesforce.com/docs/platform/graphql/filter/filter-fields.md). - `sortable` - Indicates whether the field is sortable. If true, then you can specify the field in an [`orderBy` argument](https://developer.salesforce.com/docs/platform/graphql/order.md). - `updateable` - Indicates whether the field can be edited. ### Field Types Two field types, `StandardField` and `PicklistField`, implement the Field interface. #### StandardField The `StandardField` type implements the `Field` interface and contains the same fields as the [`Field` interface](#field). #### PicklistField The `PicklistField` type implements the `Field` interface, contains the same fields as the [`Field` interface](#field), and has an additional `picklistValuesByRecordTypeIDs` field. ``` type PicklistField { //same fields as Field interface picklistValuesByRecordTypeIDs: [PicklistValueByRecordTypeIDs] } ``` For picklist fields, the `picklistValuesByRecordTypeIDs` field is a list of picklist values by record types. #### PicklistValueByRecordTypeIDs The `PicklistValueByRecordTypeIDs` type describes all the picklist values for a record. ``` type PicklistValueByRecordTypeIDs { recordTypeID: String! controllerValues: [ControllerValues!] picklistValues: [PicklistValuesValues!] defaultValue: PicklistValues } ``` The `PicklistValueByRecordTypeIDs` type has these fields. - `recordTypeID` — The ID of the record type. - `controllerValues` — The values in a controlling field that determine which dependent picklist values are available in a dependent picklist relationship. - `picklistValues` — The picklist values for the record. - `defaultValue` — The default picklist value for the record. #### ControllerValues The `ControllerValues` type describes the values in a controlling field that determine which dependent picklist values are available in a dependent picklist relationship. ``` type ControllerValues { value: String index: Int } ``` The `ControllerValues` type has these fields. - `value` — The controller field value. - `index` — The index that determines which dependent picklist value is valid for each controller field value. #### PicklistValues The `PicklistValues` type describes the picklist values. ``` type PicklistValues { value: String label: String validFor: [Int] attributes: PicklistAttributes } ``` The `PicklistValues` type has these fields. - `value` — The value of the picklist item. - `label` — The label of the picklist item. - `validFor` — Indicates which controlling field values a dependent picklist value is valid for. - `attributes` — The attributes of the picklist item. #### PicklistAttributes The `PicklistAttributes` type describes the attributes of the picklist item. ``` type PicklistAttributes { connectDisplayName: String internalName: String } ``` The `PicklistAttributes` type has these fields. - `connectDisplayName` — The display name of the picklist attribute. - `internalName` — The internal name of the picklist attribute. ### FilteredLookupInfo The `FilteredLookupInfo` type describes lookup filter information. If the type is null, the field it describes is a dependent lookup. ``` type FilteredLookupInfo { controllingFields: [String]! dependent: Boolean! optionalFilter: Boolean! } ``` The `FilteredLookupInfo` type contains these fields. - `controllingFields` - For dependent picklists, `controllingFields` returns a list of fields that control the values in the picklist. - `dependent` - Indicates whether the field depends on another field. - `optionalFilter` - Indicates whether the lookup filter is optional. ### ReferenceToInfo The `ReferenceToInfo` type describes information about a reference field’s referenced types and the name field names of those types. ``` type ReferenceToInfo { ApiName: String! nameFields: [String]! objectInfo: ObjectInfo } ``` The `ReferenceToInfo` type contains these fields. - `ApiName` - The object API name of a type that a relationship references. - `nameFields` - A collection of names of the name fields for this object type. - `objectInfo` - The [object’s metadata](#objectinfo-types-and-fields). ### ThemeInfo The `ThemeInfo` type describes color and icon information for a theme. ``` type ThemeInfo { color: String iconUrl: String } ``` The `ThemeInfo` type contains these fields. - `color` - Color information for a theme - `iconUrl` - Icon URL ### RecordTypeInfo The `RecordTypeInfo` type describes information about a record type. ``` type RecordTypeInfo { available: Boolean defaultRecordTypeMapping: Boolean master: Boolean name: String recordTypeId: String } ``` The `RecordTypeInfo` type contains these fields. - `available` - Indicates whether this record type is available to the context user when creating a record. - `defaultRecordTypeMapping` - Indicates whether this record type mapping is the default for the associated object. - `master` - Indicates whether this record type is the master record type. The master record type is the default record type that’s used when a record has no custom record type associated with it. - `name` - The record type’s label name. - `recordTypeId` - The ID of the record type. ## Enumeration Types The [`Field` interface](#field) contains several enum definitions for the `dataType` and `extraTypeInfo` fields. ### DataType The `DataType` enumeration describes the data type for the field. ``` enum DataType { ADDRESS ANYTYPE BASE64 BOOLEAN COMBOBOX COMPLEXVALUE CURRENCY DATE DATETIME DOUBLE EMAIL ENCRYPTEDSTRING INT JSON JUNCTIONLIST LOCATION LONG MULTIPICKLIST PERCENT PHONE PICKLIST REFERENCE STRING TEXTAREA TIME URL } ``` ### FieldExtraTypeInfo The `FieldExtraTypeInfo` enumeration describes data type information. ``` enum FieldExtraTypeInfo { EXTERNAL_LOOKUP IMAGE_URL INDIRECT_LOOKUP PERSONNAME PLAINTEXTAREA RICHTEXTAREA SWITCHABLE_PERSONNAME } ``` ## See Also [Get Object Metadata Examples](https://developer.salesforce.com/docs/platform/graphql/guide/query-objectinfo-examples.md) # Get Object Metadata Examples | AVAILABLE API VERSION | | ------------------------------------------------ | | API v56.0 and later | | Locale available in API v60.0 and later | | Picklist values available in API v65.0 and later | ## Query Account Object Metadata This example fetches the metadata for the Account object. ``` { uiapi { objectInfos(apiNames: ["Account"]) { ApiName childRelationships { fieldName childObjectApiName junctionIdListNames junctionReferenceTo relationshipName } createable custom defaultRecordTypeId deletable dependentFields { controllingField dependentFields } feedEnabled fields { ApiName calculated compound compoundComponentName controllerName controllingFields createable custom dataType extraTypeInfo filterable filteredLookupInfo { controllingFields dependent optionalFilter } highScaleNumber htmlFormatted inlineHelpText label nameField polymorphicForeignKey precision reference referenceToInfos { ApiName nameFields } relationshipName referenceTargetField scale sortable searchPrefilterable updateable } keyPrefix label labelPlural layoutable mruEnabled nameFields queryable recordTypeInfos { name recordTypeId } searchable themeInfo { color iconUrl } updateable } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "ApiName": "Account", "childRelationships": [ { "fieldName": "ParentId", "childObjectApiName": "Account", "junctionIdListNames": [], "junctionReferenceTo": [], "relationshipName": "ChildAccounts" }, //...truncated for display "createable": true, "custom": false, "defaultRecordTypeId": null, "deletable": true, "dependentFields": [], "feedEnabled": true, "fields": [ { "ApiName": "ShippingLatitude", "calculated": false, "compound": false, "compoundComponentName": "ShippingAddress", "controllerName": null, "controllingFields": [], "createable": true, "custom": false, "dataType": "DOUBLE", "extraTypeInfo": null, "filterable": true, "filteredLookupInfo": null, "highScaleNumber": false, "htmlFormatted": false, "inlineHelpText": null, "label": "Shipping Latitude", "nameField": false, "polymorphicForeignKey": false, "precision": 18, "reference": false, "referenceToInfos": [], "relationshipName": null, "referenceTargetField": null, "scale": 15, "sortable": true, "searchPrefilterable": false, "updateable": true }, //...truncated for display "keyPrefix": "001", "label": "Account", "labelPlural": "Accounts", "layoutable": true, "mruEnabled": true, "nameFields": [ "Name" ], "queryable": true, "recordTypeInfos": [ { "name": "Master", "recordTypeId": "012000000000000AAA" } ], "searchable": true, "themeInfo": { "color": "7F8DE1", "iconUrl": "https://www.example.com/img/account_120.png" }, "updateable": true } ] } }, "errors": [] } ``` ## Query Account Object Labels Using a Locale This example gets account labels in French. ``` query accounts { uiapi { objectInfos(apiNames: ["Account"], locale: "fr_FR") { ApiName locale fields { label } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "ApiName": "Account", "locale": "fr_FR", "fields": [ { "label": "Date de dernière modification" }, { "label": "Ville de facturation" }, { "label": "Jigsaw Company ID" }, { "label": "SLA" }, : : ] } ] } } } ``` ## Query Picklist Values for a Record Type This example gets all picklist values for the Account object for a specified record type ID. ``` query GetPicklistValuesByRecordType { uiapi { objectInfos(objectInfoInputs: { apiName: "Account", recordTypeIDs: ["012000000000000AAA"], fieldNames: [] }) { apiName fields { apiName ... on PicklistField { picklistValuesByRecordTypeIDs { recordTypeID controllerValues { value } picklistValues { value } } } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "apiName": "Account", "fields": [ { "apiName": "Industry", "picklistValuesByRecordTypeIDs": [ { "recordTypeID": "012000000000000AAA", "controllerValues": [], "picklistValues": [ { "value": "Agriculture" }, { "value": "Apparel" }, ... ] } ] }, ... ] } ] } } } ``` ## Query Picklist Values for Multiple Record Types This example gets all picklist values for two record type IDs and filtered by a field name. ``` query GetFilteredPicklistValues { uiapi { objectInfos(objectInfoInputs: { apiName: "Account", recordTypeIDs: ["012000000000000AAA", "012xx0000006ZD2AAM"], fieldNames: ["Industry"] }) { apiName fields { apiName ... on PicklistField { picklistValuesByRecordTypeIDs { recordTypeID controllerValues { value } picklistValues { value } } } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "apiName": "Account", "fields": [ { "apiName": "Industry", "picklistValuesByRecordTypeIDs": [ { "recordTypeID": "012000000000000AAA", "controllerValues": [], "picklistValues": [ { "value": "Agriculture" }, { "value": "Apparel" }, ... ] }, { "recordTypeID": "012xx0000006ZD2AAM", "controllerValues": [], "picklistValues": [ { "value": "Agriculture" }, { "value": "Apparel" }, ... ] } ] } ] } ] } } } ``` ## Query Account Child Relationships This example fetches all the child relationships for the Account object. ``` { uiapi { objectInfos(apiNames: ["Account"]) { childRelationships { objectInfo { ApiName createable custom defaultRecordTypeId deletable feedEnabled keyPrefix label labelPlural layoutable mruEnabled nameFields queryable searchable updateable } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "childRelationships": [ { "objectInfo": { "ApiName": "Account", "createable": true, "custom": false, "defaultRecordTypeId": null, "deletable": true, "feedEnabled": true, "keyPrefix": "001", "label": "Account", "labelPlural": "Accounts", "layoutable": true, "mruEnabled": true, "nameFields": [ "Name" ], "queryable": true, "searchable": true, "updateable": true } }, { "objectInfo": { "ApiName": "AccountChangeEvent", "createable": false, "custom": false, "defaultRecordTypeId": null, "deletable": false, "feedEnabled": false, "keyPrefix": "1CE", "label": "Account Change Event", "labelPlural": "Account Change Event", "layoutable": false, "mruEnabled": false, "nameFields": [ "Name" ], "queryable": false, "searchable": false, "updateable": false } }, //...truncated for display { "objectInfo": { "ApiName": "WorkOrderChangeEvent", "createable": false, "custom": false, "defaultRecordTypeId": null, "deletable": false, "feedEnabled": false, "keyPrefix": "1CE", "label": "Work Order Change Event", "labelPlural": "Work Order Change Event", "layoutable": false, "mruEnabled": false, "nameFields": [], "queryable": false, "searchable": false, "updateable": false } } ] } ] } }, "errors": [] } ``` ## Query Child Relationships for Account and Case This example returns the child relationships for accounts and cases. It also runs an `objectInfo` subquery to fetch the `queryable` field on `childRelationships`. ``` { uiapi { objectInfos(apiNames: ["Account", "Case"]) { ApiName childRelationships { childObjectApiName relationshipName objectInfo { ApiName queryable } } } } } ``` The previous query returns this response. ``` { "data": { "uiapi": { "objectInfos": [ { "ApiName": "Account", "childRelationships": [ { "childObjectApiName": "Account", "relationshipName": "ChildAccounts", "objectInfo": { "ApiName": "Account", "queryable": true } }, //...truncated for display ] } ] } } } ``` ## See Also [Get Object Metadata](https://developer.salesforce.com/docs/platform/graphql/guide/query-objectinfo.md) # Get Record Create Defaults | AVAILABLE API VERSION | | --------------------- | | API v68.0 and later | The `recordCreateDefaults` field of `CreateDefaultsConnection` type returns default field values for a new record of a given object type. The response includes the pre-populated field values that a user sees when opening a blank create form in the Salesforce user interface. This feature mirrors the behavior of the UI API [Get Default Values to Create a Record](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_record_defaults_create.htm) and [Get Default Values to Create a Record—Lightweight](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_record_defaults_template_create.htm) resources. If you need object info or layout structure, chain separate calls to [`objectInfo`](https://developer.salesforce.com/docs/platform/graphql/guide/query-objectinfo.md) and [`recordLayouts`](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-layouts.md) to get everything necessary to render a pre-populated create form. Pass `recordCreateDefaults` in the `uiapi` field. For example, use `objectApiName: "Account"` to return the default field values for a new account record. ``` { uiapi { recordCreateDefaults(objectApiName: "Account") { # fields } } } ``` ## Record Create Defaults Schema Query `recordCreateDefaults` by using this schema. ``` type UIAPI { recordCreateDefaults( objectApiName: String! recordTypeIds: [ID!] formFactor = "LARGE": FormFactor mode = "LAYOUT": CreateDefaultsMode configs: [CreateDefaultsConfig!] optionalFields: [String!] first: Int after: String ): CreateDefaultsConnection } input CreateDefaultsConfig { recordTypeId: ID! formFactor = "LARGE": FormFactor } ``` The `recordCreateDefaults` type has these arguments. - `objectApiName` - The object API name of a [supported object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). This argument is required. - `recordTypeIds` - A list of record type IDs. If unspecified, returns defaults for all accessible record types. Specify either `recordTypeIds` or `configs`. - `formFactor` - Default form factor that the [FormFactor enum](#formfactor) provides for all layouts. Default value is `LARGE`. This argument is ignored when the `mode` value is `TEMPLATE`. - `mode` - The mode that the [CreateDefaultsMode enum](#createdefaultsmode) provides. Controls whether to return all CREATE layout fields (`LAYOUT`) or only requested fields (`TEMPLATE`). Default value is `LAYOUT`. To discover which fields appear in `LAYOUT` mode, [get object layouts](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-layouts.md) with `mode: CREATE`. - `configs` - An array of `CreateDefaultsConfig` types with these arguments to request different form factor combinations per record type. Specify either `configs` or `recordTypeIds`. - `recordTypeId` - A record type ID. This argument is required. - `formFactor` - Form factor that the [FormFactor enum](#formfactor) provides for the record type. Default value is `LARGE`. - `optionalFields` - A list of additional field API names to include in the response alongside the fields determined by `mode`. Useful when `mode` is `TEMPLATE` to specify exactly which fields to return. - `first` - Number of results per page. Default value is `10`. - `after` - Returns the results after the given cursor. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ## CreateDefaultsConnection Type The `CreateDefaultsConnection` type represents a result set of record create defaults that ties together the defaults and page info. Results are paginated by record type, with each edge representing one set of defaults for one record type. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ``` type CreateDefaultsConnection { edges: [CreateDefaultsEdge] pageInfo: PageInfo! totalCount: Int } ``` The `CreateDefaultsConnection` type contains these fields. - `edges` - A list of CreateDefaultsEdge types. - `pageInfo` - Information about the relative location in the result set. - `totalCount` - The total number of `recordTypeId` and `formFactor` pair results. ## CreateDefaultsEdge Type The `CreateDefaultsEdge` type ties together the create defaults node and its cursor. ``` type CreateDefaultsEdge { node: CreateDefaults cursor: String! } ``` The `CreateDefaultsEdge` type contains these fields. - `node` - One set of create defaults for one record type. - `cursor` - An opaque string used to page directly to this item in the result set. ## CreateDefaults Type The `CreateDefaults` type is the set of default field values for the record type. ``` type CreateDefaults { recordTypeId: ID formFactor: FormFactor fields: [FieldDefault!]! } ``` The `CreateDefaults` type contains these fields. - `recordTypeId` - Resolved record type ID, which can differ from the requested ID if the object has a default record type and none was specified. - `formFactor` - Form factor that the [FormFactor enum](#formfactor) provides for this set of defaults. - `fields` - A list of FieldDefault types containing the default value for each field. ## FieldDefault Type The `FieldDefault` type represents a single field and its default value. ``` type FieldDefault { apiName: String! rawValue: String value: FieldDefaultValue } ``` The `FieldDefault` type contains these fields. - `apiName` - The API name of the field. - `rawValue` - The raw string representation of the default value. Null if the field has no default and for relationship traversal fields. - `value` - The typed default value. The [FieldDefaultValue union](#fielddefaultvalue-union) provides the concrete value type. ## FieldDefaultValue Union The `FieldDefaultValue` union represents the typed value for a field default. Use inline fragments to access the fields of each concrete type. ``` union FieldDefaultValue = StringValue IntValue BooleanValue IDValue DateValue DateTimeValue TimeValue TextAreaValue LongTextAreaValue RichTextAreaValue PhoneNumberValue EmailValue UrlValue EncryptedStringValue CurrencyValue LongitudeValue LatitudeValue PicklistValue MultiPicklistValue LongValue DoubleValue PercentValue Base64Value JSONValue FieldDefaultReferenceValue ``` Most `FieldDefaultValue` member types implement the `FieldValue` interface and expose a `value` field and a `displayValue` field. Use inline fragments to query type-specific fields. For example, `... on StringValue { value displayValue }`. See [Fields](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.md#fields) for more information about Field Value types. ## FieldDefaultReferenceValue Type The `FieldDefaultReferenceValue` type is the resolved reference record info for a relationship traversal field, such as owner or parent. ``` type FieldDefaultReferenceValue { id: ID displayValue: String objectApiName: String } ``` The `FieldDefaultReferenceValue` type contains these fields. - `id` - The ID of the referenced record. - `displayValue` - The display name of the referenced record. - `objectApiName` - The object API name of the referenced record’s type. ## PageInfo Type The `PageInfo` type contains relative position information, which shows where in the entire result set the current page is located. The `PageInfo` type is the same for every `Connection` type. See [PageInfo Type](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.md#pageinfo-type). ## Enumeration Types The `recordCreateDefaults` type has these enumerations. ### CreateDefaultsMode The `CreateDefaultsMode` enumeration controls which fields are returned. ``` enum CreateDefaultsMode { LAYOUT TEMPLATE } ``` - `LAYOUT` - Returns all fields from the object’s CREATE page layout. This is the default. - `TEMPLATE` - Returns only the fields specified in the `optionalFields` argument. ### FormFactor The `FormFactor` enumeration specifies the layout display size. Use the `LARGE` value for desktop, the `MEDIUM` value for tablet, and the `SMALL` value for phone. See [FormFactor](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-layouts.md#formfactor). ## See Also [Get Record Create Defaults Examples](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-create-defaults-examples.md) # Get Record Create Defaults Examples | AVAILABLE API VERSION | | --------------------- | | API v68.0 and later | ## Get Create Defaults for an Object This example gets the default field values for creating an account record. Use `rawValue` for scalar fields. Use a single [inline fragment](https://graphql.org/learn/queries/#inline-fragments) with the `... on Object` syntax for reference fields. ``` { uiapi { recordCreateDefaults(objectApiName: "Account") { edges { node { recordTypeId formFactor fields { apiName rawValue value { __typename ... on FieldDefaultReferenceValue { id displayValue objectApiName } } } } } pageInfo { hasNextPage endCursor } } } } ``` The previous query returns this partial response. ``` { "edges": [ { "node": { "recordTypeId": "012000000000000AAA", "formFactor": "LARGE", "fields": [ { "apiName": "OwnerId", "rawValue": "005xx000001X7oXAAS", "value": { "__typename": "IDValue" } }, { "apiName": "Owner", "rawValue": null, "value": { "__typename": "FieldDefaultReferenceValue", "id": "005xx000001X7oXAAS", "displayValue": "Admin User", "objectApiName": "User" } }, { "apiName": "Name", "rawValue": null, "value": { "__typename": "StringValue" } }, { "apiName": "Industry", "rawValue": null, "value": { "__typename": "PicklistValue" } } ] } } ] } ``` ## Get Create Defaults with Typed Field Values This example gets the default field values for a new opportunity record with a reusable fragment to get the typed value for each field. ``` fragment FieldDefaultFragment on FieldDefault { apiName rawValue value { __typename ... on IDValue { id: value } ... on StringValue { s: value } ... on BooleanValue { b: value } ... on IntValue { i: value } ... on LongValue { l: value } ... on DoubleValue { d: value } ... on PercentValue { pct: value } ... on CurrencyValue { cv: value } ... on DateValue { date: value } ... on DateTimeValue { dt: value } ... on TimeValue { time: value } ... on TextAreaValue { t: value } ... on LongTextAreaValue { lta: value } ... on UrlValue { u: value } ... on PicklistValue { p: value } ... on MultiPicklistValue { mp: value } ... on LongitudeValue { lov: value } ... on LatitudeValue { lav: value } ... on FieldDefaultReferenceValue { id displayValue objectApiName } } } { uiapi { recordCreateDefaults(objectApiName: "Opportunity") { edges { node { recordTypeId formFactor fields { ...FieldDefaultFragment } } } } } } ``` ## Get Create Defaults in Template Mode This example uses `TEMPLATE` mode with `optionalFields` to return defaults only for the specified fields on the opportunity object. ``` { uiapi { recordCreateDefaults( objectApiName: "Opportunity" mode: TEMPLATE optionalFields: ["Opportunity.Name", "Opportunity.StageName", "Opportunity.CloseDate", "Opportunity.OwnerId"] ) { edges { node { recordTypeId fields { apiName rawValue value { __typename ... on FieldDefaultReferenceValue { id displayValue objectApiName } } } } } } } } ``` ## Get Create Defaults and Layout This example chains getting account create defaults with the account layout to minimize round trips. The two fields share multiple arguments, such as `objectApiName` and `recordTypeId`, and require consistency in query. ``` { uiapi { recordLayouts( objectApiName: "Account" mode: CREATE formFactor: LARGE ) { edges { node { recordTypeId sections { heading layoutRows { layoutItems { label required editableForNew layoutComponents { apiName componentType } } } } } } } recordCreateDefaults(objectApiName: "Account") { edges { node { recordTypeId fields { apiName rawValue value { __typename ... on FieldDefaultReferenceValue { id displayValue objectApiName } } } } } } } } ``` ## See Also [Get Record Create Defaults](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-create-defaults.md) # Get Related List Metadata | AVAILABLE API VERSION | | --------------------- | | API v57.0 and later | The `relatedListByName` type returns metadata for a related list in a page layout. The response includes metadata describing fields, relationships, the columns in the list, and the list’s sort order. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for querying. Pass in the `relatedListByName` type in the `uiapi` field. For example, to return metadata for the Opportunity related list on the Account object, use `parentApiName: "Account"` and `relatedListName: "Opportunities"`. ``` { uiapi { relatedListByName(parentApiName: "Account", relatedListName: "Opportunities") { # fields } } } ``` ## Related List Schema Query `relatedListByName` by following this schema. ``` type UIAPI { relatedListByName(parentApiName: String!, relatedListName: String!): RelatedListInfo } ``` ## RelatedListInfo Types and Fields The `RelatedListInfo` type includes fields for the related list metadata. ``` type RelatedListInfo { childApiName: String! displayColumns: [ListColumn!]! fieldApiName: String! label: String! orderedByInfo: [ListOrder!]! parentApiName: String! relatedListName: String! } ``` The `RelatedListInfo` type contains these fields. - `childApiName`: The API name of a [supported child object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm#ui_api_get_started_supported_objects). - `displayColumns`: All [display columns](#listcolumn) for the related list. - `fieldApiName`: The API name of the field in the child object that links to the parent object. - `label`: The related list display label, for example, "Opportunities". - `orderedByInfo`: [Ordering information](#listorder) for the related list. - `parentApiName`: The API name of a [supported parent object](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm#ui_api_get_started_supported_objects). - `relatedListName`: The name of a supported related list for an object, such as Opportunities. ### ListColumn The `ListColumn` type represents metadata for a column in the related list. ``` type ListColumn { fieldApiName: String! label: String! lookupId: String sortable: Boolean } ``` The `ListColumn` type contains these fields. - `fieldApiName`: The API name for the column field. - `label`: The label of the column field. - `lookupId`: The ID of the column field if the field is a reference. If the field isn’t a reference, the value can be null. - `sortable`: Indicates whether the column is sortable. ### ListOrder The `ListOrder` type represents the ordering information for a related list. ``` type ListOrder { fieldApiName: String! sortDirection: ResultOrder } ``` The `ListOrder` type contains these fields. - `fieldApiName`: The API name for the field. - `sortDirection`: The sort order specified by the [ResultOrder](#resultorder) enum. ## Enumeration Types The [`ListOrder` type](#listorder) contains an enum definition for the `sortDirection` field. ### ResultOrder The `ResultOrder` enumeration specifies whether the results are ordered in ascending or descending order. ``` enum ResultOrder { ASC DESC } ``` ## Example: Query Opportunities Related List Metadata for Account This example fetches the metadata for the Opportunities related list on an Account. ``` { uiapi { relatedListByName(parentApiName: "Account", relatedListName: "Opportunities") { label parentApiName childApiName relatedListName displayColumns { fieldApiName label sortable } } } } ``` ### Example Response for Opportunities Related List Metadata for Account The previous query returns this response. ``` { "data": { "uiapi": { "relatedListByName": { "label": "Opportunities", "parentApiName": "Account", "childApiName": "Opportunity", "relatedListName": "Opportunities", "displayColumns": [ { "fieldApiName": "Name", "label": "Opportunity Name", "sortable": true }, { "fieldApiName": "StageName", "label": "Stage", "sortable": true }, { "fieldApiName": "Amount", "label": "Amount", "sortable": true }, { "fieldApiName": "CloseDate", "label": "Close Date", "sortable": true } ] } } }, "errors": [] } ``` # Get Started with GraphQL API | REQUIRED EDITIONS | | ---------------------------------------------------------------------------------------- | | Available in: **Enterprise**, **Performance**, **Unlimited**, and **Developer Editions** | GraphQL API is a new paradigm of sending and receiving data, offering developers a single endpoint to call for all data needed in one request. This API allows developers to interact with the Salesforce Platform through GraphQL, a standard query language for APIs and a runtime for fulfilling those queries with your data. Apps that call GraphQL APIs are often much more performant than those that use traditional REST APIs. They are able to reduce round trips to the server through retrieval of all necessary data in just a single invocation. To make your first call, use a [Quick Start](https://developer.salesforce.com/docs/platform/graphql/guide/get-started.md). To see the GraphQL API endpoint, see [API Reference](/docs/platform/graphql/references/graphql?meta=Summary). **tip:** Learn more about GraphQL at [graphql.org](http://graphql.org/). You can also [quickly get started with GraphQL API here](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-graphql.md) and make calls to a Salesforce org. [GraphQL API is available with Lightning Web Components (LWC)](https://developer.salesforce.com/docs/platform/graphql/guide/wire/graphql-wire-lwc.md). Using the GraphQL wire adapter, LWC developers can work with Salesforce data using GraphQL API while taking advantage of its extensive benefits to build web components and mobile offline apps. GraphQL API # GraphQL API GraphQL API provides a single endpoint that returns exactly what you request for. You can [introspect the schema](/docs/platform/graphql/guide/get-started.html) to define your request with the data you need. The schema contains concrete representations of Salesforce objects, following the object-level and field-level security settings of the context user. To learn how to authenticate and authorize requests, see [Authorization](/docs/platform/graphql/guide/authorization.html). To learn what's new with GraphQL API and see versioned reference changes, see [Release Notes](/docs/platform/graphql/guide/graphql-release-notes.html). **Version:** 68.0 ## Servers * `https://{MyDomainName}.my.salesforce.com/services/data/v68.0` The production API server. The `{MyDomainName}` variable is your org's My Domain name, which is used as a subdomain for the URLs that Salesforce uses to serve your org. For example, if your Lightning URL is `https://yourcompanyname.lightning.force.com`, then your My Domain name is `yourcompanyname`. Find your My Domain name and login URL on the My Domain page in Setup, or use the `getMyDomainName()` method in the Apex Domain class. ## Operations ### POST Send Query `POST /graphql` Operation ID: `sendQuery`. Returns the result of a GraphQL query. Execute a GraphQL query. Before you can send a GraphQL API query, make sure you set up authorization by following a [Quick Start](/docs/platform/graphql/guide/get-started.html). You need an API access token to authenticate your requests via a client like Altair or Postman. For example requests, see the [Postman Collection](https://www.postman.com/salesforce-developers/workspace/salesforce-developers/folder/12721794-23e285e8-51bd-438a-a130-847f1e3e6d7b?ctx=documentation). #### Request body Media type: `application/json`. Schema: `GraphQLInputRepresentation`. _Example_ ``` { "query": "query accounts { uiapi { query { Account { edges { node { Name { value } } } } } } }" } ``` #### Responses * **200** Success Media type: `application/json`. Schema: `GraphQLRepresentation`. _Example_ ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0011a000005slmbAAA", "Name": { "value": "GenePoint" } } }, { "node": { "Id": "0011a000005slmcAAA", "Name": { "value": "United Oil & Gas, UK" } } }, { "node": { "Id": "0011a000005slmeAAA", "Name": { "value": "Edge Communications" } } } ] } } } }, "errors": [ { "extensions": { "ErrorType": "ValidationError" }, "locations": [ { "column": 7, "line": 4 } ], "message": "Validation error of type FieldUndefined: Field 'Accounts' in type 'RecordQuery' is undefined @ 'uiapi/query/Accounts'", "paths": [ "uiapi", "query", "Account", "edges", 4, "node" ] } ], "extensions": {} } ``` ## Schemas ### GraphQLInputRepresentation A GraphQL query and any associated variables. * `extensions` (_object_) The extensions to the input. Additional properties: `object`. * `operationName` (_string_) The operation that’s being executed. * `query` (_string_, required) The GraphQL query. * `variables` (_object_) The variables for the query. Additional properties: `object`. ### GraphQLRepresentation GraphQL query result. * `data` (_object_) The data of the GraphQL query result. Additional properties: `object`. * `errors` (_array of GraphQLErrorRepresentation_) The errors that resulted from this query. * `extensions` (_object_) The extensions that resulted from this query. Additional properties: `object`. ### GraphQLErrorRepresentation A GraphQL Error. * `extensions` (_object_) Information about the error. See [Status Codes and Error Responses](/docs/platform/graphql/guide/query-status.html). Additional properties: `object`. * `locations` (_array of GraphQLErrorLocation_) The locations where the error occurred. * `message` (_string_) The reason the error occurred. * `paths` (_array of any_) The paths where the error occurred. Each item in the paths array can either be a string or an integer. As the path is a reference to the resolved data, the path may contain integers when the error occurs within a list. ### GraphQLErrorLocation The location where a GraphQL error occurred. * `column` (_integer_) The column number where the GraphQL error occurred. * `line` (_integer_) The line number where the GraphQL error occurred. # GraphQL API Query Limitations | AVAILABLE API VERSION | | --------------------------------------------------------- | | API v56.0 and later | | Event and task beta available in API v59.0–65.0 | | Event and task generally available in API v66.0 and later | GraphQL has the same limitations as SOQL. When working with GraphQL API queries, consider the following limitations. - Each GraphQL query can contain up to 10 subqueries. - Each subquery counts as one request for rate limiting. - Each subquery can return up to 2000 records within the same GraphQL query. - By default, the first 10 records are returned. You can use [pagination information](https://developer.salesforce.com/docs/platform/graphql/paginate.md) to retrieve additional records. - You can query only objects that [User Interface API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm) supports. **note:** Some fields are not filterable using the `where` filter. To find out if a field is supported for filtering, see the [Object Reference for the Salesforce Platform](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_list.htm). For example, the [NewValue and OldValue fields](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_casehistory.htm) on the CaseHistory object don't include "Filter" in the **Properties** section and aren't supported for filtering. If you attempt to pass in an unsupported field to the `where` filter, you get a "Field 'FieldName' in type 'ObjectName' is undefined" error. ## Relationship Queries An object must have a parent or child relationship with another object to form a query similar to an SOQL join. Limitations for [relationship queries](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_and_custom_objects.htm) are discussed in the next few sections. ### Child-to-Parent Relationships Child-to-parent relationships follow these limits. - A query can specify up to 55 child-to-parent relationships. A custom object allows up to 40 relationships, so you can reference all the child-to-parent relationships for a custom object in one query. - You can specify up to five levels in a child-to-parent relationship. - A child relationship name can't be the same as a parent relationship name within an object. This example shows three levels of child-to-parent relationship, which is `Contact.Account.Owner.FirstName`. ``` query { uiapi { query { Contact { edges { node { Id Name { value } Account { # first level of child-to-parent relationship Owner { # second level FirstName { value } # third level } } } } } } } } ``` Additionally, consider these differences between API versions. - In API version 57.0 and earlier, you can specify up to two levels of child-to-parent relationship in a query. - In API version 58.0 and later, you can specify up to five levels of child-to-parent relationship for standard and custom objects. ### Parent-to-Child Relationships Parent-to-child relationships follow these limits. - A query can specify up to 20 parent-to-child relationships. - You can specify one level in a parent-to-child relationship. - A parent relationship name can't be the same as a child relationship name within an object. This example shows a parent-to-child relationship, which is `Account.Contacts`. ``` query { uiapi { query { Account { edges { node { Id Name { value } Contacts { # parent-to-child relationship edges { node { Owner { # child-to-parent relationship CreatedBy { # child-to-parent relationship Name { value } } } } } } } } } } } } ``` If you’re querying Account, the fields you select can specify only the Contact or other objects at that level. The query can’t specify a child object of Contact. ## Semi-Join and Anti-Join Queries GraphQL API follows SOQL restrictions on semi-join and anti-join queries. - You can use up to two `nin` and `ninq` operators in a `where` argument. A `nin` and `ninq` operator can support up to two `in` or `nin` operators. - You can't use the `ne` operator with semi-joins and anti-joins. Using this operator converts a semi-join to an anti-join and vice versa. Instead, write the query in the appropriate semi-join or anti-join form. ### Main Query Limits Consider these restrictions on the `where` argument of a semi-join or anti-join query. - You must use a single ID for the semi-join or anti-join query. - The ID in the `where` argument that's used in the semi-join or anti-join can't use relationships. This example uses a single ID in a semi-join to return contact names associated with accounts whose ownership is public. ``` query { uiapi { query { Contact (where: { AccountId: { inq: { Account: { Ownership: { eq: "Public" } }, ApiName:"Id" }, } }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Contact WHERE AccountId IN ( SELECT Id FROM Account WHERE Ownership = 'Public' ) ``` ### Subquery Limits A subquery must query a field referencing the same object type as the main query. For example, use the Id field on the `where` argument followed by `ApiName:"AccountId"`in the `inq` operator. Using `Account.Id` (dot notation) instead of `AccountId` isn't supported. This example returns specific accounts using AccountId as the selected field in the subquery, in which the contacts' last names start with "B". ``` query { uiapi { query { Account (where: { Id: { inq: { Contact: { LastName: { like: "B%" } }, ApiName:"AccountId" }, } }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Contact WHERE LastName LIKE 'B%' ) ``` There's no limit on the number of records matched in a subquery. By default, the first 10 records are returned. You can use the [pagination information](https://developer.salesforce.com/docs/platform/graphql/paginate.md) to retrieve additional records. ``` query { uiapi { query { Account (first:50, where: { Id: { inq: { Contact: { LastName: { like: "B%" } }, ApiName:"AccountId" }, } }) { edges { node { Id Name { value } } } } } } } ``` The selected field in a subquery must be a reference to a different object, and can't traverse relationships. In the previous example, the main query selects from accounts and the subquery selects from contacts. You can’t query on the same object in a subquery as in the main query. Instead of selecting from the same object in the main query and subquery, you can rewrite a semi-join query using the `Parent` field. ``` query { uiapi { query { Account ( where: { Parent: { Name: { like: "United%" } } }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Parent.Name LIKE 'United%' ``` A semi-join or anti-join statement: - Can’t be nested in another semi-join or anti-join statement - Can’t be used in a subquery `where` argument. A subquery can’t be used with: - The `or` operator - The `orderBy` operator ### Multiple Semi-Joins and Anti-Joins You can combine semi-join or anti-join clauses in a query using the `inq` or `ninq` functions in a `where` argument. However, you can use only up to two subqueries in a single semi-join or anti-join queries. This example includes 2 semi-join filters that return accounts if they have an associated opportunity and an associated case that has its Priority field set to "High". ``` query { uiapi { query { Account (where: { and: [{ Id: { inq: { Opportunity: {}, ApiName:"AccountId" }, }, Id: { inq: { Case : { Priority : { eq : "High" } }, ApiName:"AccountId" } } }] }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Opportunity ) AND Id IN ( SELECT AccountId FROM Case WHERE Priority = 'High' ) ``` ## Object-Specific Limitations Only the [UI API supported objects](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm) are available in GraphQL API. Certain supported objects come with additional limitations. ### Note Object Limitations The Note object has these limitations. - You can't query the Note object in subqueries. - You can query the Note object but you can't evaluate the body of a note, such as filtering on `Note.Body` by using the `eq` or `like` operator. You also can’t filter against the content of textarea fields, blobs, or S-control components in any object. You can return the content of the body of the note like this. ``` query { uiapi { query { Account ( where: { Name: { like: "Edge%" } }) { edges { node { Notes { edges { node { Body {value} } } } Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, (SELECT Note.Body FROM Account.Notes) FROM Account WHERE Name LIKE 'Edge%' ``` You can also return all account names and the owner ID for any notes associated with the account. ``` query { uiapi { query { Account ( where: { Name: { like: "Edge%" } }) { edges { node { Notes { edges { node { OwnerId { value } } } } Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Account.Name, (SELECT Note.OwnerId FROM Account.Notes) FROM Account ``` ### External Objects Limitations External objects have these limitations. - A subquery that involves external objects can fetch up to 1,000 rows of data. - Each query can have up to 4 joins across external objects and other types of objects. Each join requires a separate round trip to the external system when executing the query. Expect longer response times for each join in a query. - External objects don’t support the `orderBy` argument in relationship queries. This limit applies only when the external data is accessed via the OData 2.0 adapter for Salesforce Connect. ## See Also [SOQL Limits on Objects](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_limits.htm) [Understanding Relationship Query Limitations](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_query_limits.htm) # GraphQL API Release Notes To discover what’s new and changed in GraphQL API, see the Salesforce Release Notes. [_Salesforce Release Notes_](https://help.salesforce.com/s/articleView?id=release-notes.salesforce_release_notes.htm) ## GraphQL API Reference Change Log GraphQL uses a versioned base URI in this format: `{MyDomainName}.my.salesforce.com/services/data/v{ApiVersion}/graphql`. Update your base URI when changing API versions. Here’s a list of changes to the GraphQL API reference content. ### v68.0 No API changes ### v67.0 No API changes ### v66.0 No API changes ### v65.0 - `GraphQLInputRepresentation` has a new `extensions` property for passing extensions with your request. - `GraphQLOutputRepresentation` has a new `extensions` property that returns any extensions included in the query result. ### v64.0 No API changes ### v63.0 No API changes ### v62.0 No API changes ### v61.0 No API changes ### v60.0 No API changes ### v59.0 No API changes ### v58.0 - `GraphQLErrorRepresentation` has a new `extensions` property that provides additional error details, including an `ErrorType` property that identifies the type of error returned. ### v57.0 No API changes. Request and response body examples are now included in the reference documentation. ### v56.0 Initial release of the GraphQL API reference. Supports a single POST `/graphql` endpoint for executing GraphQL queries. The `GraphQLInputRepresentation` request body has these properties. - `query`—the GraphQL query string - `operationName`—the operation to execute - `variables`—a map of variables for the query The `GraphQLRepresentation` response body has these properties. - `data`—the query result data - `errors`—an array of `GraphQLErrorRepresentation` objects, each with: - `message`—description of the error - `locations`—line and column in the query where the error occurred - `path`—path to the field that caused the error # GraphQL Request and Response Structure GraphQL API is an alternative to a traditional REST API, but operates similarly. To execute a query, make a POST request to the GraphQL endpoint, available at `https://{MyDomainName}.my.salesforce.com/services/data/v{version}/graphql`. Replace these values: - `MyDomainName`: A custom subdomain specific to a Salesforce org. For example, `companyname` creates the URL `https://companyname.my.salesforce.com`. - `version`: A Salesforce API version in the format XX.X. For example, 57.0. For a collection of sample queries, connect to the [Salesforce Developer Postman Collection](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-postman.md). For a deep dive into the types involved in the request and response, see the [API Reference](/docs/platform/graphql/references/graphql?meta=Summary). ## Request The GraphQL request body has four parts. The `query` field contains the GraphQL query as a string. Optionally, use the `operationName` field to indicate which query to execute. Provide the `operationName` field if the query has multiple queries or mutations, to specify which query or mutation to execute. If the query defines any variables, include them as a map under the `variables` field. Finally, if the query uses extensions, include them as a map under the `extensions` field. Here's a simple request to execute a query. ```json { "query": "query accounts { uiapi { query { Account { edges { node { Id Name { value } } } } } }" } ``` This request specifies that the `contacts` query is the one query executed of the two defined in the document. ```json { "query": "query accounts { uiapi { query { Account { edges { node { Id Name { value } } } } } } query contacts { uiapi { query { Contact { edges { node { Id Name { value } } } } } }" "operationName": "contacts" } ``` This request includes argument values for variables defined in the query. ```json { "query": "query accountById($id: ID) { uiapi { query { Account(where: { Id: { eq: $id } }) { edges { node { Id Name { value } } } } } }", "variables": { "id": "001xx000003GYQxAA0" } } ``` ### Example Requests If you're sending a request via curl or HTTP, send the query with your API access token in a JSON string. ```bash curl --location --request POST 'https://lng-dev-ed.my.salesforce.com/services/data/v57.0/graphql' \ -H 'Authorization: Bearer YourAccessToken' \ -H 'Content-Type: application/json' \ -d '{ "query": "query accounts { uiapi { query { Account { edges { node { Id \n Name { value } } } } } } }" }' ``` You can also use a JSON tool like [JQ](https://stedolan.github.io/jq/) to help transform or format your output. ```bash curl --location --request POST 'https://lng-dev-ed.my.salesforce.com/services/data/v57.0/graphql' \ -H 'Authorization: Bearer YourAccessToken' \ -H 'Content-Type: application/json' \ -d '{ "query": "query accounts { uiapi { query { Account { edges { node { Id \n Name { value } } } } } } }" }' \ | jq . ``` To send a request via a client like [Altair or Postman](https://developer.salesforce.com/docs/platform/graphql/guide/get-started.md), pass in the query directly. ``` query AllAccounts { uiapi { query { Account { edges { node { Id Name { value } } } } } } } ``` ## Response The response has a `data` section, an `errors` section, and an `extensions` section. The `data` section contains the response to the request query. The `errors` [section](/docs/platform/graphql/references/graphql?meta=type%3AGraphQLErrorRepresentation) includes errors that occur during the execution of the request. The `extensions` section includes extensions returned by the request. ```http { "data": { ... }, "errors": [ ... ], "extensions": { ... } } ``` ### Example Responses If the request is successful, you receive a JSON blob like this. ```json { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0011a000005slmbAAA", "Name": { "value": "GenePoint" } } }, { "node": { "Id": "0011a000005slmcAAA", "Name": { "value": "United Oil & Gas, UK" } } }, { "node": { "Id": "0011a000005slmeAAA", "Name": { "value": "Edge Communications" } } } ] } } } }, "errors": [], "extensions": {} } ``` If the request fails, you receive a JSON blob like this. ```json { "data": {}, "errors": [ { "extensions": { "ErrorType": "ValidationError" }, "locations": [ { "column": 7, "line": 4 } ], "message": "Validation error of type FieldUndefined: Field 'Accounts' in type 'RecordQuery' is undefined @ 'uiapi/query/Accounts'", "paths": [] } ], "extensions": {} } ``` ## See Also [Status Codes and Error Responses](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-status.md) # GraphQL Wire Adapter Best Practices When creating queries for your GraphQL wire adapter, follow these best practices to get the most out of GraphQL API for your LWC development. ## Query Only the Data You Need Here’s where the power of GraphQL shines. You can write a query that satisfies your data needs and gives you exactly what you asked for, nothing more and nothing less. Writing a brief query that satisfies your data requirements makes the return result predictable, while ensuring that your query remains performant. Use the `first` argument to limit the number of results, and [paginate your results](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-paginate.md) with the `after` argument. The default is 10. In this example, including the `totalCount` field makes the query look up all existing records, even though it returns only the first 5. ```javascript //simpleGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class SimpleGQL extends LightningElement { results; errors; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Account(first: 5) { totalCount edges { node { Id Name { value } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.query.Account.edges.map((edge) => edge.node); } this.errors = errors; } } ``` **tip:** Requesting `totalCount` can have performance implications for large or complex queries. ## Use GraphQL Variables for Arguments Using variables makes your query reusable with LWC’s reactivity feature, which means that your query fetches the data only if any of the variable values changed. Using variables ensures that your query results reflect the arguments being used. It also helps improve performance so that the client framework understands that the query itself hasn’t changed and it can skip parsing and revalidating the query. The `$minAmount` GraphQL variable enables the component to set and change the minimum amount. ```javascript @wire(graphql, { query: gql` query bigAccounts($minAmount: Currency) { uiapi { query { Account(where: { AnnualRevenue: { gte: $minAmount } }) { edges { node { Id Name { value } AnnualRevenue { displayValue } } } } } } }`, variables: '$variables', //Use a getter function to make the variables reactive }) graphqlQueryResult({ data, errors }) { if (data) { this.records = data.uiapi.query.Account.edges.map(edge => edge.node); } this.errors = errors; } ``` For more information, see [Make Your Variables Reactive](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-reactive.md). ## Delay Query Execution To delay your query from executing, such as for testing or if you’re working with multiple queries, use a getter and pass in the query using a variable like `query: '$recordQuery'`. For example, delaying the query can be helpful if you’re fetching contacts by account ID and don’t have the account ID when the component loads. ```javascript @wire(graphql, { query: '$recordQuery', variables: '$variables' }) ...; get recordQuery() { return this.recordId ? gql`thequery` : undefined; } get variables() { return { this.recordId } } ``` **note:** If `this.recordId` is `undefined` during the initial page load, `get recordQuery()` returns `undefined`. Most Salesforce mobile environments, like Field Service and the Salesforce mobile app, can’t prefetch `undefined` queries. In this example, the `accountId` isn’t reactive to changes. ```javascript // Don't do this @wire(graphql, { query: '$query', variables: { accountId: this.accountId }) ; ``` In some cases, you don’t have the account ID when the component loads, for example: - You expect the user to select an account, which then sets the account ID - You set the account ID depending on which account record page displays To delay query execution, make your query reactive by updating the `query` and `variables` parameters like in the next example. This example queries the associated contacts on an account record page that’s currently displayed. The AccountId field value on the Contact object is provided by `@api recordId`, which makes [a component aware of its record context](https://developer.salesforce.com/docs/platform/lwc/guide/use-record-context.html). ```javascript // accountIdExample.js import { LightningElement, wire, api } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AccountIdExample extends LightningElement { contacts; errors; @api recordId; @wire(graphql, { query: "$accountQuery", variables: "$accountData", }) contactsQueryResult({ data, errors }) { if (data) { this.contacts = data.uiapi.query.Contact.edges.map((edge) => edge.node); } if (errors) { this.contactsError = errors; } } get accountQuery() { // Send a request to the server only if recordId is provided. if (!this.recordId) return undefined; return gql` query contactsOnAccount($recordId: ID!) { uiapi { query { Contact(where: { AccountId: { eq: $recordId } }) { edges { node { Id Name { value } } } } } } } `; } get accountData() { return { recordId: this.recordId, }; } } ``` The HTML template looks like this. ```html ``` ## Dynamically Construct Queries at Run Time Dynamically generate queries in the wire adapter at run time to support component state or user input. To dynamically construct your query, use JavaScript string interpolation inside the `gql` tagged template literal. Dynamic query construction in the wire adapter is available in API v65.0 and later and requires the `lightning/graphql` LWC module. In this example, `${this.objectName}` represents the dynamic part of the query that’s resolved at run time. ```javascript import { LightningElement, track, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class DynamicGraphQLQuery extends LightningElement { @track objectName = "Account"; get resolvedQuery() { return gql` query { uiapi { query { ${this.objectName} { edges { node { Id Name } } } } } } `; } @wire(graphql, { query: "$resolvedQuery", variables: {} }) result; get data() { return this.result?.data ? JSON.stringify(this.result.data, null, 2) : ""; } } ``` Unlike static queries, referential integrity isn’t automatically preserved for dynamically generated queries. You must manually resolve any compilation errors in LWC components caused by renamed or deleted entities or fields. ## Execute Multiple Queries Send multiple queries in one operation if you want to request record data for multiple objects. Combining multiple queries can help prevent unnecessary requests to the server. For example, send your query in a separate call if the query depends on a field or value from an earlier query. Alternatively, work with [semi-joins or auto-joins](https://developer.salesforce.com/docs/platform/graphql/filter/filter-parent.md) to query records with parent and child relationships. ## Work with Parent and Child Relationships You can specify a parent or child relationship in your query for the GraphQL wire adapter. Objects can have children relationships to the same object, just like a parent account can have child accounts. Some objects have children relationships to other objects. For example, accounts have child relationships to assets, cases, and contacts among other objects. The GraphQL API schema provides details of parent-child relationships. For example, the Account field is a `parentRelationship` type on the Contact object. Similarly, the Cases field is a `childRelationship` type on the Contact object. ``` query contacts { uiapi { query { Contact { edges { node { Cases { edges { node { Subject { value } Status { value } Priority { value } } } } Account { Name { value } } } } } } } } ``` For more information, see [Relationship Filters](https://developer.salesforce.com/docs/platform/graphql/filter/filter-parent.md). ## Use Aliases with Custom Objects and Fields Salesforce automatically understands references to objects and fields within your GraphQL queries and applies referential integrity to those references. If your GraphQL query references a custom entity or field and that entity or field is renamed, Salesforce updates your GraphQL query to use the new name. While this update prevents your query from failing at run time, it also changes the shape of the data returned from the query. To protect against unintentional change of the data shape, we recommend that you add GraphQL aliases to any custom object and field names in your GraphQL query that could change. Adding aliases preserves the names used for these objects and fields in the GraphQL result, while still allowing Salesforce’s referential integrity mechanisms to work correctly. Aliases ensure that your component remains valid and prevents any run-time errors in the future. **note:** We recommend that you add the alias to any custom object and field during development time, which ensures that changes made to these objects in a subscriber org won’t break the component. Using an alias isn’t supported for standard objects and fields. Let’s say you are querying a custom object and a custom field like this. ```javascript //aliasGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AliasGQL extends LightningElement { results; errors; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Custom_object__c(first: 5) { edges { node { Id Object_name__c { value } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.query.Custom_object__c.edges.map((edge) => edge.node); } this.errors = errors; } } ``` Add aliases to all custom objects and fields used in your query during development, before you publish a managed package. See [Use a Namespace and Alias in Managed Packages](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-namespace.md). ```javascript //aliasUpdateGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AliasGQL extends LightningElement { results; errors; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Custom_object: Custom_object__c(first: 5) { edges { node { Id Object_name: Object_name__c { value } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.query.Custom_object.edges.map((edge) => edge.node); } this.errors = errors; } } ``` If a subscriber org or your team member changes the object or field name, updating `Custom_object__c` to `Custom_object2__c`, and `Object_name__c` to `Object_name2__c`, your component preserves its referential integrity. ```javascript //aliasUpdateGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AliasUpdateGQL extends LightningElement { results; errors; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Custom_object: Custom_object2__c(first: 5) { edges { node { Id Object_name: Object_name2__c { value } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.query.Custom_object.edges.map((edge) => edge.node); } this.errors = errors; } } ``` The wire adapter returns a JSON response that looks like this. ```json { "data": { "uiapi": { "query": { "Custom_object": { "edges": [ { "node": { "Id": "00X1a00000cR4wuAAC", "Object_name": { "value": "My name" } } }, # more data here ] } } } }, "errors": [] } ``` ## See Also [GraphQL Wire Adapter Limitations](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-limitations.md) # GraphQL Wire Adapter for LWC The Lightning Web Components (LWC) framework implements core Web Components standards to enable developers to create reusable components on the Salesforce platform using standard HTML, JavaScript, and CSS. You can work with Salesforce data via [Lightning Data Service](https://developer.salesforce.com/docs/platform/lwc/guide/data-ui-api.html), which is available to your components via base components like `lightning-record-form` or via wire adapters and functions. ## GraphQL Wire Adapter With the [GraphQL wire adapter](https://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-graphql-module.html), you can query Salesforce data using SOQL-like queries with functionalities like filtering and data aggregation. Lightning Data Service manages your data and you don’t need different wire adapters for each query defined in the GraphQL schema, unlike the other LWC wire adapters. The extensive benefits of using the GraphQL wire adapter simplify and speed up access to your Salesforce data from your LWC web components and mobile apps. ::video{src="https://www.youtube.com/embed/PTYEzizzyW0" title="codeLive: How to Work with GraphQL Wire Adapter for LWC" type="youtube" } ## See Also [_Lightning Web Components Developer Guide_: lightning/graphql Wire Adapter (v2)](https://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-graphql-module.html) [_Lightning Web Components Developer Guide_: lightning/uiGraphQLApi (v1)](https://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-graphql-api.html) # GraphQL Wire Adapter Limitations The GraphQL wire adapter isn’t currently supported for variables in [directives](https://graphql.org/learn/queries/#directives) such as using `@skip` and `@include`. Features and capabilities in the GraphQL API can take several releases to be available in the GraphQL wire adapter. Consider these additional limitations. - If you’re supporting Mobile Offline use cases, you must use the `lightning/uiGraphQLApi` LWC module. - If using [pagination with an upper-bound limit](https://developer.salesforce.com/docs/platform/graphql/paginate-use-upperbound.md), the wire adapter expects the upper-bound limit to stay constant for a given paginated collection. - If your GraphQL query fails prefetch in the Salesforce mobile app, Salesforce Field Service (SFS), or Mobile Offline, you must continue to use metaschema directives in your GraphQL query for [referential integrity](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-namespace.md#referential-integrity) and [offline priming](https://help.salesforce.com/s/articleView?id=service.mfs_offline_parent.htm) functionality. See _Known Issue_: [GraphQL query fails prefetch with an "Unknown Field" warning](https://issues.salesforce.com/issue/a028c00000xGGwE/graphql-query-fails-prefetch-with-an-unknown-field-warning). ## See Also [Feature Limitations of Offline GraphQL](https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_graphql_limitations.htm) # Group Aggregate Results | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | Group results using the `groupBy` argument. Results are grouped according to the field values within the record and the provided grouping function. When querying a [`RecordAggregate`](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate.md#recordaggregate-type), you can pass in an aggregate function and a `groupBy` argument. If you don't need aggregation, use the [`RecordQuery` type](https://developer.salesforce.com/docs/platform/graphql/query/query-record-objects.md) instead. The `groupBy` argument behaves like the [SOQL `GROUP BY` clause](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby.htm). It can map elements to groups in three ways: - Using the distinct set of values you provide for the `groupBy` argument - Using the `CUBE` type - Using the `ROLLUP` type ## Groupable Fields Grouping is useful for summarizing your data based on a particular field. For example, when grouping by an Industry, passing in `Industry` to the `groupBy` argument clause assigns all Accounts that share an Industry to the same group, similar to a `GROUP BY Industry` SOQL clause. The following field types support grouping. A Date/Time function can be applied to the field if it's a Date, Time, or DateTime function. | | Group by ApiName | Group by Date/Time Function | | :-----: | :--------------: | :-------------------------: | | Boolean | ✅ | | | Date | ✅ | ✅ | | Int | ✅ | | | Email | ✅ | | | String | ✅ | | | ID | ✅ | | Group your results to avoid iterating through individual query results, specifying a group of records instead. You can use `groupBy` with aggregate functions like `sum` or `max`, which summarizes the data and enables you to roll up query results. ## Example: Query Object with Grouping First, you can query the `LeadSource` without grouping, which returns a list of all lead sources on each lead, including duplicate values. ``` query LeadSourceExample { uiapi { query { Lead { edges { node { LeadSource { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT LeadSource FROM Lead ``` Instead of writing code to iterate through the query results and increment counters for each LeadSource value, you can use `groupBy` to return the same results. ``` query LeadSourceExample { uiapi { aggregate { Lead ( groupBy: { LeadSource: { group: true } } ) { edges { node { aggregate { Name { count { value } } } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT LeadSource, COUNT(Name) FROM Lead GROUP BY LeadSource ``` You can also query all distinct values, including `null`, without an aggregated function. ``` query LeadSourceWithoutNullValues { uiapi { aggregate { Lead ( groupBy: { LeadSource: { group: true } } ) { edges { node { aggregate { LeadSource { value } } } } } } } } ``` The previous query is similar to the folowing SOQL statement. ``` SELECT LeadSource FROM Lead GROUP BY LeadSource ``` # Group By Cube | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | The `CUBE` type adds subtotals for all combinations of a grouped field in the query result. This group by type enables you to create a query to calculate a sum, an average, or another aggregate function. You can then group the results by a horizontal set of values and a vertical set of values. Use `CUBE` with [aggregate functions](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-support.md), such as `sum` and `count`. If you want only subtotals for a subset of the grouped field combinations, use [`groupBy` with `ROLLUP` type](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-groupby-rollup.md) instead. ## Aggregate Results with Group By Cube To aggregate results using group by cube, use the following syntax. Replace _objectApiName_ with the object's API name, like Account. _Field1_ and _Field2_ represent fields on the object, like Industry and AnnualRevenue. ``` query rollupExample { uiapi { aggregate { objectApiName (groupBy: { type: CUBE, Field1: { group: true }, Field2: { group: true } }) { edges { node { aggregate { _Field1_ { value grouping { value } } _Field2_ { value grouping { value } } // Other optional fields } } } } } } ``` **note:** A query with the `CUBE` type can include up to three fields in a comma-separated list in the `groupBy` argument clause. ## See Also [SOQL and SOSL Reference: GROUP BY CUBE](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby_cube.htm) # Group By Rollup | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | The `ROLLUP` type adds subtotals for aggregate data in the query result. Use `ROLLUP` with [aggregate functions](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-support.md), such as `sum` and `count`. ## Aggregate Results with Group By Rollup To aggregate results and include subtotals in the query result, use the following syntax. Replace _objectApiName_ with the object's API name, like Account. _Field1_ and _Field2_ represent fields on the object, like Industry and AnnualRevenue. ``` query rollupExample { uiapi { aggregate { objectApiName (groupBy: { type: ROLLUP, Field1: { group: true }, Field2: { group: true } }) { edges { node { aggregate { _Field1_ { value grouping { value } } _Field2_ { value grouping { value } } // Other optional fields } } } } } } ``` A query that uses the `groupBy` argument with the `ROLLUP` type returns the same aggregated data as a query with the `groupBy` argument. However, a query with the `ROLLUP` type also returns multiple levels of subtotals. For example, you can return the number of records for each lead sources and a subtotal of those records using the `ROLLUP` type. **note:** A query with the `ROLLUP` type can include up to three fields in a comma-separated list in the `groupBy` argument clause. The result includes one grand total regardless of how many rollup fields you use. The order of rollup fields you pass in to the `groupBy` argument determines how the subtotals are calculated and how the results are grouped. ## Group By One Rollup Field Grouping by one rollup field returns subtotals for each field selection and one grand total. For example, if you query the rollup by `LeadSource`, the query returns the number of records for each lead source and a grand total. ``` query LeadSourceRollupExample { uiapi { aggregate { Lead ( groupBy: { type: ROLLUP, LeadSource: { group: true } } ) { edges { node { aggregate { Name { count { value } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT LeadSource, COUNT(Name) FROM Lead GROUP BY ROLLUP(LeadSource) ``` ## Group By Two Rollup Field A query that includes two rollup fields returns first-level subtotals for _Field1_. Results are grouped by _Field2_. For example, if you query the rollup by `Status` and `LeadSource`, the query returns subtotals for the number of records for each lead source that has a particular status. ``` query LeadSourceExample { uiapi { aggregate { Lead ( groupBy: { type: ROLLUP, Status: { group: true }, LeadSource: { group: true } } ) { edges { node { aggregate { Name { count { value } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Status, LeadSource, COUNT(Name) FROM Lead GROUP BY ROLLUP(Status, LeadSource) ``` ## Group By Three Rollup Field A query that includes three rollup fields returns: - First-level subtotals for each combination of _Field1_ and _Field2_. Results are grouped by _Field3_. - Second-level subtotals for each value of _Field1_. Results are grouped by _Field2_ and _Field3_. ## See Also [SOQL and SOSL Reference: GROUP BY ROLLUP](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby_rollup.htm) # Group By Schema | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | All sObjects in the schema have a corresponding `RecordGroupBy` type. The `RecordGroupBy` type combines the object API name with the `_GroupBy` suffix. For example: ``` type Account { groupBy: Account_GroupBy orderBy: Account_OrderBy } ``` The `RecordGroupBy` type is introduced by the [`RecordQueryAggregate` type](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate.md#recordqueryaggregate-type). ## RecordGroupBy Type `RecordGroupBy` creates one input type per sObject type. For example, Account has a corresponding `Account_GroupBy` type that you can use with the `groupBy` argument. The `Account_GroupBy` type contains fields of `GroupByClause`. Some fields are shown here for brevity. We recommend that you use the [Altair GraphQL client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md) for a complete view of the schema. ``` input Account_GroupBy { AccountNumber: GroupByClause BillingCity: GroupByClause BillingCountry: GroupByClause CreatedBy: User_GroupBy CreatedById: GroupByClause Id: GroupByClause Industry: GroupByClause Name: GroupByClause NumberOfEmployees: GroupByClause OperatingHours: OperatingHours_GroupBy Owner: User_GroupBy OwnerId: GroupByClause Ownership: GroupByClause Parent: Account_GroupBy ParentId: GroupByClause # More fields here type: GroupByType } ``` ## GroupByType Type The `GroupByType` type defines the type of `Group By` clause. ``` type GroupByType { GROUP_BY: GROUP_BY ROLLUP: ROLLUP CUBE: CUBE } ``` `GroupByType` contains these fields. - `GROUP_BY` - The default grouping. - `ROLLUP` - Adds subtotals for aggregated data in the query result. - `CUBE` - Adds subtotals for all combinations of a grouped field in the query results. ## GroupByClause Type The `GroupByClause` type has a `group` field of type `Boolean`. Pass these fields to the `groupBy` argument in the `aggregate` field. ``` type GroupByClause { group: Boolean } ``` The `GroupByClause` type contains the following field. - `group` - Pass in `true` to the `groupBy` argument to group the query by the specific field. If true, the field is included in the `Group By` SOQL clause. ## User_GroupBy Type Some fields like `CreatedBy` and `OperatingHours` correspond to a `_GroupBy` type, which contains additional fields of type `OrderByClause` or `_GroupBy`. ``` type User_GroupBy { AboutMe: OrderByClause Account: Account_OrderBy AccountId: OrderByClause # Other User_GroupBy fields } ``` ## GroupByFunction Enum Use the `GroupByFunction` enumeration with fields of type DateTime and Time. Fields of type DateTime and Time cannot be included with their field name alone, and so providing `group: true` for those field types is invalid. **note:** You can't use `group:true` for fields of type DateTime and Time. Instead, use these fields with the aggregate functions. See [Grouping Examples](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-groupby-examples.md). ``` Enum GroupByFunction { CALENDAR_MONTH CALENDAR_QUARTER CALENDAR_YEAR DAY_IN_WEEK DAY_IN_MONTH DAY_IN_YEAR DAY_ONLY FISCAL_MONTH FISCAL_QUARTER FISCAL_YEAR HOUR_IN_DAY WEEK_IN_MONTH WEEK_IN_YEAR } ``` The `GroupByFunction` enumeration contains these values. - `CALENDAR_MONTH`- Returns a number 1 (January) to 12 (December) for the calendar month on a date field. - `CALENDAR_QUARTER` - Returns a number 1 (January 1 - March 31) to 4 (October 1 through December 31) for the calendar quarter on a date field. - `CALENDAR_YEAR` - Returns the calendar year on a date field. - `DAY_IN_WEEK` - Returns a number 1 (Sunday) to 7 (Saturday) for the day of the week on a date field. - `DAY_IN_MONTH` - Returns a number 1–31 for the day in the month on a date field. - `DAY_IN_YEAR` - Returns a number 1–365 for the day in the year on a date field. - `DAY_ONLY` - Returns a date for the day portion on a DateTime field, for example, `2009-09-22` for September 22, 2009. - `FISCAL_MONTH` - Returns a number 1–12 for the discal month on a date field, which can differ from `CALENDAR_MONTH` if your organization uses a fiscal year that does not match the Gregorian calendar. This field is not supported if your organization has custom fiscal years enabled. - `FISCAL_QUARTER` - Returns a number 1–4 for the fiscal quarter on a date field, which can differ from `CALENDAR_QUARTER` if your organization uses a fiscal year that does not match the Gregorian calendar. This field is not supported if your organization has custom fiscal years enabled. - `FISCAL_YEAR` - Returns the fiscal year on a date field, which can differ from `CALENDAR_YEAR` if your organization uses a fiscal year that does not match the Gregorian calendar. - `HOUR_IN_DAY` - Returns a number 1–24 for the hour in the day on a DateTime field. Only DateTime and Time fields are supported. - `WEEK_IN_MONTH` - Returns a number 1–5 for the week in the month on a date field. - `WEEK_IN_YEAR` - Returns a number 1–53 for the week in the year on a date field. ## See Also [Aggregate Examples](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-examples.md) [SOQL and SOSL Reference: Date Functions](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_date_functions.htm) # Grouping Examples | AVAILABLE API VERSION | | --------------------- | | API v58.0 and later | You can use aggregate functions without a `groupBy` argument or use them with a `groupBy` argument with optional types `CUBE` or `ROLLUP`. ## Get Average Amount on Opportunities by Campaign Use the aggregate function with a `groupBy` argument to find the average amount of all your opportunities by campaign. ``` query OppsByCampaign { uiapi { aggregate { Opportunity (groupBy: { CampaignId: { group: true } }) { edges { node { aggregate { Amount { avg { value } } } } } } } } } ``` This query returns the average amount of all your opportunities by campaign. ``` { "data": { "uiapi": { "aggregate": { "Opportunity": { "edges": [ { "node": { "aggregate": { "Amount": { "avg": { "value": 185806.4516129032 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT CampaignId, AVG(Amount) FROM Opportunity GROUP BY CampaignId ``` ## Get Average Amount on Opportunities by Account ID and Name You can also use the aggregate function with a `groupBy` argument to group by multiple fields. ``` query OppsByCampaign { uiapi { aggregate { Opportunity(groupBy: {AccountId: {group: true}, Name: { group: true }}) { edges { node { aggregate { Amount { avg { value } } } } } } } } } ``` This query is similar to the following SOQL statement. ``` SELECT AVG(Amount) Amount__a FROM Opportunity GROUP BY AccountId, Name ``` ## Get the Number of Accounts for Each Industry and Group By Industry ``` query industry { uiapi { aggregate { Account ( groupBy: { Industry: { group: true } } ) { edges { node { aggregate { Industry { value } Name { count { value } } } } } } } } } ``` This query provides the following response. ``` { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "value": null }, "Name": { "count": { "value": 18 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Apparel" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Biotechnology" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Construction" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Consulting" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Education" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Electronics" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Energy" }, "Name": { "count": { "value": 3 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Hospitality" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Transportation" }, "Name": { "count": { "value": 1 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT Industry, COUNT(Name) FROM Account GROUP BY Industry ``` ## Get Accounts and Group By Year ``` query GroupAccountsByYear { uiapi { aggregate { Account (groupBy: { CreatedDate: { function : CALENDAR_YEAR } } ) { edges { node { aggregate { Name { count { value } } CreatedDate { calendarYear { value } } } } } } } } } ``` This query provides the following response. ``` { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Name": { "count": { "value": 24 } }, "CreatedDate": { "calendarYear": { "value": 2022 } } } } }, { "node": { "aggregate": { "Name": { "count": { "value": 5 } }, "CreatedDate": { "calendarYear": { "value": 2023 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT Count(Name), CALENDAR_YEAR(CreatedDate) FROM Account GROUP BY CALENDAR_YEAR(CreatedDate) ``` ## Get the Sum of Accounts for Combination of Type and Industry ``` query aggregates { uiapi { aggregate { Account(groupBy: { type: CUBE, Industry: { group: true }, Type: { group: true } }) { edges { node { aggregate { Industry { value grouping { value } } Type { value grouping { value } } NumberOfEmployees { sum { value } } } } } } } } } ``` This query provides the following response. ``` { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 0 } }, "Type": { "value": null, "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": null } } } } }, { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 0 } }, "Type": { "value": null, "grouping": { "value": 1 } }, "NumberOfEmployees": { "sum": { "value": null } } } } }, { "node": { "aggregate": { "Industry": { "value": "Manufacturing", "grouping": { "value": 0 } }, "Type": { "value": "Prospect", "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": 680 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Manufacturing", "grouping": { "value": 0 } }, "Type": { "value": null, "grouping": { "value": 1 } }, "NumberOfEmployees": { "sum": { "value": 680 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Media", "grouping": { "value": 0 } }, "Type": { "value": "Prospect", "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": 14668 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Media", "grouping": { "value": 0 } }, "Type": { "value": null, "grouping": { "value": 1 } }, "NumberOfEmployees": { "sum": { "value": 14668 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Technology", "grouping": { "value": 0 } }, "Type": { "value": "Customer", "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": null } } } } }, { "node": { "aggregate": { "Industry": { "value": "Technology", "grouping": { "value": 0 } }, "Type": { "value": null, "grouping": { "value": 1 } }, "NumberOfEmployees": { "sum": { "value": null } } } } }, { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 1 } }, "Type": { "value": null, "grouping": { "value": 1 } }, "NumberOfEmployees": { "sum": { "value": 15348 } } } } }, { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 1 } }, "Type": { "value": null, "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": null } } } } }, { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 1 } }, "Type": { "value": "Prospect", "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": 15348 } } } } }, { "node": { "aggregate": { "Industry": { "value": null, "grouping": { "value": 1 } }, "Type": { "value": "Customer", "grouping": { "value": 0 } }, "NumberOfEmployees": { "sum": { "value": null } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to the following SOQL statement. ``` SELECT Industry, Type, SUM(NumberOfEmployees) FROM Account GROUP BY CUBE(Industry, Type) ``` ## See Also [SOQL and SOSL Reference: GROUP BY CUBE](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby_cube.htm) # Location-Based Filters | AVAILABLE API VERSION | | ------------------------------------------------ | | API v57.0 and later | | Compound fields available in API v59.0 and later | Run a query on a geolocation field for a supported object using the [GeolocationInput type](https://developer.salesforce.com/docs/platform/graphql/guide/filter-fields.md#geolocation-field-types). The geolocation custom field types stores location values on records using latitude and longitude values. You can create queries that calculate the distance between two location values or between a location value and a latitude-longitude coordinate. To create a location-based filter, use the `where` and `orderBy` arguments. ## Query Records with Geolocation Fields A compound geolocation field includes latitude and longitude values. To work with compound geolocation fields, reference the individual components of the returned value. For example, if your geolocation field name is `Location`, use the `Location__Latitude__s` and `Location__Longitude__s`. ``` query accounts { uiapi { query { Account{ edges { node { Id Name { value } Location__Latitude__s { value }, Location__Longitude__s { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Name, Location__latitude__s, Location__longitude__s FROM Account ``` ## Filter Using `where` Pass in the `where` argument to filter records based on a geolocation compound field. Let's say you have a custom geolocation field `Location__c` on accounts. This `where` argument finds accounts that are within 500 miles of 47.6062°, -122.3321° (Seattle, WA) using the `lt` function. ``` Account(where: { Location__c: { lt: { latitude: 47.6062 longitude: 122.3321 radius: 500 unit: MI } } }) { edges { node { DisplayValue } } } ``` The previous query is similar to the following SOQL statement. ``` WHERE DISTANCE(Location__c, GEOLOCATION(47.6062,-122.3321), 'mi') < 500 ``` ## Order Results Using `orderBy` Given a set of records with geolocation fields, you can sort them by distance using the `distance` filter type with the `orderBy` argument. You can also order the results in ascending or descending order. The geolocation field support ordering using the [`OrderByClause` type](https://developer.salesforce.com/docs/platform/graphql/order.md). Here's a basic query that orders the results in ascending order and null records at the end. ``` query { uiapi { query { Account(orderBy:{ Location__c:{ distance:{ latitude:47.6062 longitude:122.3321 }, nulls:LAST order:ASC } }) { edges { node { Id Name { value }, Location__Latitude__s { value }, Location__Longitude__s { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Name, Location__latitude__s, Location__longitude__s FROM Account ORDER BY DISTANCE(Location__c, GEOLOCATION(47.606, 122.332), 'mi') ASC NULLS LAST ``` The following example adds the `orderBy` argument to a `where` argument. ``` query { uiapi { query { Account(where: { Location__c: { lt: { Latitude: 47.6062 Longitude: 122.3321 radius: 500 unit: MI } } }, orderBy: { Location__c: { distance: { latitude: 47.6062 longitude: 122.3321 } } }) { edges { node { Id Name { value }, Location__Latitude__s { value }, Location__Longitude__s { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Id, Name FROM Account WHERE DISTANCE(Location__c, GEOLOCATION(47.6062,-122.3321), 'mi') < 500 ORDER BY DISTANCE(Location__c, GEOLOCATION(47.6062,-122.3321), 'mi') ``` ## Location-Based Query Limitations When you query geolocation compound fields, use the constituent fields in the query. ``` edges{ node{ Name { value }, Location__c { # don't do this value } } } ``` Provide a direct reference to the internal primitive data types. For example, use `Location__Latitude__s` and `Location__Longitude__s` if you have a compound geolocation field `Location__c`. ``` query AccountLocations { uiapi { query { Account (where: { Location__Latitude__s: { ne: null }}){ edges { node { Id Name { value } Location__c { # Geolocation compound field Location__Latitude__s { # Constituent field value }, Location__Longitude__s { # Constituent field value } } } } } } } } ``` Similar to how SOQL calculates and compares distances, you can’t check locations or distances for equality with GraphQL API. You can only determine whether a location is farther or closer than another location, or one distance is greater or smaller than another. ## See Also [Field Operators: Geolocation Field Types](https://developer.salesforce.com/docs/platform/graphql/guide/filter-fields.md#geolocation-field-types) [Object Reference: Geolocation Compound Field](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/compound_fields_geolocation.htm) [SOQL and SOSL Reference: Location-Based SOQL Queries](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_geolocate.htm?language=en&q=implicit) [SOQL SELECT Syntax: Order By](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm) # Make Your Variables Reactive Use the `variables` configuration parameter of the `graphql` wire adapter to supply dynamic values to your GraphQL query. **tip:** The [`graphqlVariables` component](https://github.com/trailheadapps/lwc-recipes/tree/main/force-app/main/default/lwc/graphqlVariables) in the [lwc-recipes repo](https://github.com/trailheadapps/lwc-recipes) returns contact data based on a dynamic search string. ## Implement GraphQL Variables in LWC Let’s say you have a component that displays a dropdown with several options to represent different annual revenue amounts. Selecting an amount returns the accounts whose annual revenue is greater or equal to the amount. In this example, the `$minAmount` GraphQL variable enables the component to set and change the minimum amount, displaying the corresponding records when the value changes. ```javascript //accountsGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AccountsGQL extends LightningElement { records; errors; minAmount = "5000000"; minAmounts = [ { label: "All", value: "0" }, { label: "$5,000,000", value: "5000000" }, { label: "$50,000,000", value: "50000000" }, { label: "$500,000,000", value: "500000000" }, ]; @wire(graphql, { query: gql` query bigAccounts($minAmount: Currency) { uiapi { query { Account(where: { AnnualRevenue: { gte: $minAmount } }) { edges { node { Id Name { value } AnnualRevenue { displayValue } } } } } } } `, variables: "$variables", // Use a getter function to make the variables reactive }) graphqlQueryResult({ data, errors }) { if (data) { this.records = data.uiapi.query.Account.edges.map((edge) => edge.node); } this.errors = errors; } get variables() { return { minAmount: this.minAmount, }; } // Called when the user selects a new minimum amount handleMinAmountChange(event) { this.minAmount = event.detail.value; } } ``` Next, create the dropdown in your component to enable input selection. Selecting an option on the dropdown triggers the `handleMinAmountChange` function and sets the new value on the `minAmount` variable, which updates the query results based on the selected amount. ```html ``` GraphQL variables allow your query to use values that aren’t known until run time. They also reduce the size of your component by eliminating the need for multiple queries that are near-duplicates. **note:** GraphQL variables can’t be used to pass the names of objects or fields. This is a limitation of the GraphQL syntax and the way the Salesforce GraphQL schema is designed. ## See Also [GraphQL Variables](https://graphql.org/learn/queries/#variables) # Mutations | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | Besides [querying records](https://developer.salesforce.com/docs/platform/graphql/query/query-records.md) using the `Query` operation type, you can create, update, or delete record data with mutations using [the `Mutation` operation type](https://developer.salesforce.com/docs/platform/graphql/schema-conventions.md). For more information, see [GraphQL Mutations](https://graphql.org/learn/queries/#mutations). # Mutations Limitations | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | Consider these limitations for mutations. - Creating a record with child relationships isn’t currently supported. - Multiple dependent operations like creating an account hierarchy can either all execute successfully or not at all. - The [GraphQL wire adapter](https://developer.salesforce.com/docs/platform/graphql/wire/graphql-wire-lwc.md) supports mutations in API v66.0 and later. - In API v59.0–65.0, the `RecordUpdatePayload` type includes only a `success` field returning `true` or `false` to denote if the update is successful. ## See Also [Feature Limitations of Offline GraphQL](https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_graphql_limitations.htm) # Mutations Schema | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally available v66.0 and later | The [`Mutation` operation type](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-intro.md) has a `uiapi` field with a `UIAPIMutationsInput` argument. The `UIAPIMutationsInput` argument has a boolean argument `allOrNone` that has a default value of `true`. When `true`, if one or more operations fail, all operations are rolled back and not executed. ``` type Mutation { uiapi(input: UIAPIMutationsInput): UIAPIMutations! } input UIAPIMutationsInput { allOrNone: Boolean } ``` Use mutations to create, update, or delete records. Under the `UIAPIMutations` type, each Salesforce object corresponds to a `RecordCreate`, `RecordEdit`, and `RecordDelete` field that accepts a response payload you define. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for mutations. The context user’s [object-level and field-level permissions](https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/security_data_access.htm) control access to supported objects and fields on those objects. An object is accessible if the user has the correct permissions, and the object is either on the supported object list or is a custom object. For create mutations, the context user must have read access to the new record. **note:** To view the GraphQL API schema via introspection, use the [Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md). ## UIAPIMutations Type The `UIAPIMutations` type has three fields—`RecordCreate`, `RecordDelete`, and `RecordUpdate`—for each object type accessible to the user. Here’s the `Account` example. ``` type UIAPIMutations { AccountCreate ( input AccountCreateInput! ): AccountCreatePayload AccountDelete ( input RecordDeleteInput! ): RecordDeletePayload AccountUpdate ( input AccountUpdateInput! ): AccountUpdatePayload } ``` The `UIAPIMutations` type contains fields for creating, deleting, and updating records. ## RecordCreate Field The `RecordCreate` field accepts the `RecordCreateInput` object type as an argument with a `RecordCreateRepresentation` type. Here’s the `AccountCreateInput` example. ``` input AccountCreateInput { Account: AccountCreateRepresentation! } ``` The `RecordCreateRepresentation` type represents the record view after the create mutation operation completes. The `RecordCreateRepresentation` differs from the `RecordRepresentation` that is used for querying records. The `RecordCreateRepresentation` excludes foreign key details (other than ID) and child relationships because the related objects aren’t part of the mutation operation. Here’s the `AccountCreateRepresentation` example. ``` type AccountCreateRepresentation { AccountNumber: String AccountSource: Picklist AnnualRevenue: Currency # Other Account fields } ``` The input type for `RecordCreate` contains fields that are createable. Required fields must be non-null. If you don’t include the `OwnerId` field, it’s set to the context user. **note:** The `Id` field isn’t included in the `RecordCreateRepresentation` type. ## RecordCreatePayload Type The `RecordCreatePayload` type returns the result of record creation. It returns a `Record` object with its corresponding fields. Here’s the `AccountCreatePayload` example. ``` type AccountCreatePayload { Record: Account } ``` The `Record` object maps to a Salesforce object and its fields. If record creation is successful, the response payload also contains the `Id` of the new record. ## RecordDelete Field The `RecordDelete` field accepts the `RecordDeleteInput` object type as an argument. Here’s the `AccountDeleteInput` example. ``` input AccountDeleteInput { Id: IdOrRef! } ``` ## RecordDeletePayload Type The `RecordDeletePayload` type returns the `Id` field of the deleted record. Here’s the `AccountDeletePayload` example. ``` type AccountDeletePayload { Id: ID } ``` ## RecordUpdate Field The `RecordUpdate` field accepts the `RecordUpdateInput` object type as an argument with a `RecordUpdateRepresentation` type. Here’s the `AccountUpdateInput` example. ``` input AccountUpdateInput { Account: AccountUpdateRepresentation! Id: IdOrRef! } ``` The `RecordUpdateRepresentation` type represents the record view after the update mutation operation completes. The `RecordUpdateRepresentation` differs from the `RecordRepresentation` that is used for querying records. The `RecordUpdateRepresentation` excludes foreign key details (other than ID) and child relationships because the related objects aren’t part of the mutation operation. Here’s the `AccountUpdateRepresentation` example. ``` type AccountUpdateRepresentation { AccountNumber: String AccountSource: Picklist AnnualRevenue: Currency # Other Account fields } ``` The input type for `RecordUpdate` contains fields that are updateable. It includes a non-null `Id` field for specifying which record to update. **note:** The `Id` field isn’t included in the `RecordUpdateRepresentation` type. ## RecordUpdatePayload Type The `RecordUpdatePayload` type returns the result of record update. It returns a `Record` object with its corresponding fields. Here’s the `AccountUpdatePayload` example. ``` type AccountUpdatePayload { Record: Account } ``` The `Record` object maps to a Salesforce object and its fields. **note:** The `RecordUpdatePayload` type includes the `Record` field in API v66.0 and later. In API v59–65, the `RecordUpdatePayload` type includes a `success` field returning `true` or `false` to denote if the update is successful. # Order Aggregate Results | AVAILABLE API VERSION | | --------------------- | | API v59.0 and later | Use the `orderBy` argument to sort the aggregate results alphabetically in either ascending or descending order. You can also specify if null values appear first in the result set. When querying a [`RecordAggregate`](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate.md#recordaggregate-type), you can pass in an aggregate function and a `orderBy` argument. If you don't need aggregation, use the [`RecordQuery` type](https://developer.salesforce.com/docs/platform/graphql/query/query-record-objects.md) instead. The `orderBy` argument behaves like the [SOQL `ORDER BY` clause](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm). **note:** To use the `orderBy` argument, your field must be grouped or aggregated. All sObjects in the schema have a corresponding order type. The order type combines the API name with the `_OrderBy`. For example, under the `RecordQueryAggregate` fields, `Account` has a corresponding `Account_OrderBy` type. See [Aggregate Schema](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-schema.md). The following field types support ordering. Each field type corresponds to an `AggregateOrderByClause` type. See [Order By Schema](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-orderby-schema.md). - Int - String - Boolean - Id - DateTime - Time - Date - TextArea - LongTextArea - PhoneNumber - Email - Url - Currency - Geolocation - Longitude - Latitude - Picklist - Long - Double - Percent - Base64 # Order By Considerations | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | `orderBy` is compatible with relationship queries. For example, you can order by `Account.Name` like this. ``` query industry { uiapi { query { Case ( orderBy: { Account: { Name: { order: ASC }}}) { edges { node { Id CaseNumber { value } AccountId { value } Account { Name { value }} } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Id, CaseNumber, AccountId, Account.Name FROM Case ORDER BY Account.Name ``` Additionally, the `orderBy` argument follows these SOQL limitations. - The sort order depends on your user locale setting. For English locales, SOQL uses the UTF-8 values of the uppercase character to create a sort order. In other words, sorting for English locales is case insensitive. - For non-English locales, SOQL uses a pre-defined order that is natural for the locale specified. This is because different cultures may sort the same characters in different ways, and this nuance can't be captured by the UTF-8 values alone. By default, the first 10 results are returned with [pagination information](https://developer.salesforce.com/docs/platform/graphql/guide/paginate.md). You can request for a larger number of results to be returned by using the `first` argument. ``` Case ( first:50, orderBy: { Account: { Name: { order: ASC }}}) ``` The previous query is similar to the following SOQL ORDER BY clause. ``` ORDER BY Account.Name ASC LIMIT 50 ``` # Order By Examples | AVAILABLE API VERSION | | --------------------- | | API v59.0 and later | You can use aggregate functions with or without an `orderBy` argument. ## Example: Query Aggregate Fields with Ordering This example queries the Industry field and an aggregate count function on Name, grouped by Industry. Use the `orderBy` argument for the aggregated Name field. The result lists all industries and the number of accounts that are assigned to that particular industry. By default, null values are returned first the results. To remove accounts without a specified industry, use `where: { Industry: { ne: null } }`. **note:** All aggregate functions ignore null values, except for COUNT() and COUNT(Id). ``` query IndustryAndNameCount { uiapi { aggregate { Account ( where: { Industry: { ne: null } }, groupBy: { Industry: { group: true } }, orderBy: { Name: { order: DESC, function: COUNT }}){ edges { node { aggregate { Industry { value } Name { count { value } } } } } } } } } ``` ### Example Response for Aggregate Fields with Ordering ``` { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "value": "Energy" }, "Name": { "count": { "value": 3 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Biotechnology" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Construction" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Consulting" }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Education" }, "Name": { "count": { "value": 1 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to this SOQL statement. ``` SELECT Industry, COUNT(Name) FROM Account WHERE Industry != null GROUP BY Industry ORDER BY COUNT(Name) DESC ``` Similar to SOQL, you can't order by the aggregated name count unless you also group by Industry. For example, you get an error if you don't provide `GROUP BY Industry`. You also can't group by the aggregated name count. Only date aggregate functions are allowed in a grouping. ## Example: Query Multiple Aggregate Fields with Ordering This example queries the Industry field with 2 aggregate functions on AnnualRevenue and Name fields. Use the `orderBy` argument for the aggregated fields. The result lists all industries, the corresponding average amount on the AnnualRevenue fields, and the number of accounts that are assigned to that particular industry. ``` query IndustryAndAvgRevenue { uiapi { aggregate { Account ( orderBy: { Name: { order: ASC, function: COUNT }, AnnualRevenue: { order: ASC, function: AVG } }, groupBy: { Industry: { group: true } } ) { edges { node { aggregate { Industry { value } AnnualRevenue { avg { value } } Name { count { value } } } } } } } } } ``` ## Example Response for Multiple Aggregate Fields with Ordering ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "Industry": { "value": "Education" }, "AnnualRevenue": { "avg": { "value": null } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Biotechnology" }, "AnnualRevenue": { "avg": { "value": 30000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Consulting" }, "AnnualRevenue": { "avg": { "value": 50000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Electronics" }, "AnnualRevenue": { "avg": { "value": 139000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Apparel" }, "AnnualRevenue": { "avg": { "value": 350000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Hospitality" }, "AnnualRevenue": { "avg": { "value": 500000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Construction" }, "AnnualRevenue": { "avg": { "value": 950000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Transportation" }, "AnnualRevenue": { "avg": { "value": 950000000 } }, "Name": { "count": { "value": 1 } } } } }, { "node": { "aggregate": { "Industry": { "value": "Energy" }, "AnnualRevenue": { "avg": { "value": 5600000000 } }, "Name": { "count": { "value": 3 } } } } }, { "node": { "aggregate": { "Industry": { "value": null }, "AnnualRevenue": { "avg": { "value": null } }, "Name": { "count": { "value": 18 } } } } } ] } } } }, "errors": [] } ``` The previous query is similar to this SOQL statement. ``` SELECT Industry, AVG(AnnualRevenue), COUNT(Name) FROM Account GROUP BY Industry ORDER BY COUNT(Name), AVG(AnnualRevenue) ``` ## Example: Query Minimum Revenue of All Industries with Ordering To return the minimum value of a field, use the `min` function. This example returns the minimum value of the AnnualRevenue field for each industry. ``` query MinRevenueGroupByIndustry { uiapi { aggregate { Account (groupBy: { Industry: { group: true } }, orderBy: { AnnualRevenue: { function: MIN } } ) { edges { node { aggregate { AnnualRevenue { min { displayValue } } Industry { value } } } } } } } } ``` The [`orderBy` argument](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-orderby.md) orders the results in ascending order of annual revenue. Similar to SOQL, you can't order by the aggregated minimum annual revenue unless you also group by Industry. In other words, if you use `orderBy` in a query, you must also include the `groupBy` argument. ### Example Response for Minimum Revenue of All Industries ```json { "data": { "uiapi": { "aggregate": { "Account": { "edges": [ { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$30,000,000" } }, "Industry": { "value": "Biotechnology" } } } }, { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$50,000,000" } }, "Industry": { "value": "Consulting" } } } }, { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$139,000,000" } }, "Industry": { "value": "Electronics" } } } }, { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$350,000,000" } }, "Industry": { "value": "Apparel" } } } }, { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$500,000,000" } }, "Industry": { "value": "Hospitality" } } } }, { "node": { "aggregate": { "AnnualRevenue": { "min": { "displayValue": "$5,600,000,000" } }, "Industry": { "value": "Energy" } } } } ] } } } }, "errors": [] } ``` The previous query is similar to this SOQL statement. ``` SELECT MIN(AnnualRevenue), Industry FROM Account GROUP BY Industry ORDER BY MIN(AnnualRevenue) ``` ## See Also [SOQL and SOSL Reference: ORDER BY](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm) # Order By Examples | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | Order objects are used to order the result set of records. All sObjects in the schema have a corresponding order type. The order type combines the object API name with the `_OrderBy` suffix. For example, `Account` has a corresponding `Account_OrderBy` type. ## Example: Order By Account Names Pass in the `orderBy` argument to the object. ``` query accounts { uiapi { query { Account ( orderBy: { Name: { order: ASC } }) { edges { node { Id Name { value } } } } } } } ``` The query returns the following example response. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Name": { "value": "Alpha Dynamics" } } }, { "node": { "Name": { "value": "Burlington Textiles" } } }, // more results here ] } } } }, "errors": [] } ``` ## Example: Order By Child Contacts on Accounts Here's an example `orderBy` argument for contacts on account records. ``` query AccountWithChildrenAccounts { uiapi { query { Account(where: { Name: { eq: "Alpha Dynamics" } }) { edges { node { Id Name { value } Contacts ( orderBy: { Name: { order: ASC } }) { edges { node { Name { value } } } } } } } } } } ``` The query returns the following example response. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "001RM000005ZdMGYA0", "Name": { "value": "Alpha Dynamics" }, "Contacts": { "edges": [ { "node": { "Name": { "value": "Amy Taylor" } } }, { "node": { "Name": { "value": "Caroline Kingsley" } } }, { "node": { "Name": { "value": "Jennifer Wu" } } } ] } } } ] } } } }, "errors": [] } ``` **note:** [Custom metadata types](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_custommetadatatype__mdt.htm) (types ending in `__mdt`) don't support ordering through parent relationships, and so they don't have any input object fields corresponding to parent relationships on the `OrderBy` object. # Order By Schema | AVAILABLE API VERSION | | --------------------- | | API v59.0 and later | All sObjects in the schema have a corresponding `RecordOrderBy` type. The `RecordOrderBy` type combines the object API name with the `_OrderBy` suffix. For example: ``` type Account { groupBy: Account_GroupBy orderBy: Account_OrderBy } ``` The `RecordOrderBy` type is introduced by the [`RecordQueryAggregate` type](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate.md#recordqueryaggregate-type). ## RecordOrderBy Type `RecordOrderBy` creates one input type per sObject type. For example, Account has a corresponding `Account_OrderBy` type that you can use with the `orderBy` argument. The `Account_OrderBy` type contains fields of `OrderByClause` type. Some fields are shown here for brevity. We recommend that you use the [Altair GraphQL client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md) for a complete view of the schema. ``` input Account_OrderBy { AccountNumber: AggregateOrderByStringClause AnnualRevenue AggregateOrderByNumberClause BillingCity: AggregateOrderByStringClause BillingCountry: AggregateOrderByStringClause CreatedBy: User_OrderBy CreatedById: NoFunctionAggregateOrderByClause Id: AggregateOrderByStringClause Industry: AggregateOrderByStringClause Name: AggregateOrderByStringClause NumberOfEmployees: AggregateOrderByNumberClause OperatingHours: OperatingHours_OrderBy Owner: User_OrderBy OwnerId: NoFunctionAggregateOrderByClause Ownership: AggregateOrderByStringClause Parent: Account_OrderBy ParentId: NoFunctionAggregateOrderByClause } ``` The main types include: - `AggregateOrderByStringClause` - Defines aggregate functions used by fields of these types: - String - Id - DateTime - Time - Date - Email - PhoneNumber - Url - Picklist - `AggregateOrderByNumberClause` - Defines aggregate functions used by fields of these types: - Int - Double - Long - Latitude - Longitude - Percent - `NoFunctionAggregateOrderByClause` - Defines how null values are returned and how sorting order are used by fields of these types: - Boolean - Reference fields like AccountId and OwnerId ## AggregateOrderByStringClause Type The `AggregateOrderByStringClause` type has several enumeration types. ``` type AggregateOrderByStringClause { function: AggregateOrderByStringFunction nulls: NullsOrder order: ResultsOrder } ``` Pass these types to the `orderBy` argument in the `aggregate` field. - `function` - The aggregate function to apply to the filter. - `nulls` - Orders null records either first or last. - `order` - Order the aggregate results by ascending or descending order. ## AggregateOrderByStringFunction Enum The `AggregateOrderByStringFunction` enum values define aggregate functions for string fields like date, email, or Url and so on. ``` enum AggregateOrderByStringFunction { COUNT COUNT_DISTINCT MAX MIN } ``` Use these values with string fields. - `COUNT` - Returns the number of rows matching the query criteria. - `COUNT_DISTINCT` - Returns the number of distinct non-null field values matching the query criteria. - `MAX` - Returns the maximum value of a field. - `MIN` - Returns the minimum value of a field. ## AggregateOrderByNumberClause Type The `AggregateOrderByNumberClause` type has several enumeration types. ``` type AggregateOrderByNumberClause { function: AggregateOrderByNumberFunction nulls: NullsOrder order: ResultsOrder } ``` Pass these types to the `orderBy` argument in the `aggregate` field. - `function` - The aggregate function to apply to the filter. - `nulls` - Orders null records either first or last. - `order` - Order the aggregate results by ascending or descending order. ## NoFunctionAggregateOrderByClause Type The `NoFunctionAggregateOrderByClause` type has several enumeration types. ``` type NoFunctionAggregateOrderByClause { nulls: NullsOrder order: ResultsOrder } ``` Pass these types to the `orderBy` argument in the `aggregate` field. - `nulls` - Orders null records either first or last. - `order` - Order the aggregate results by ascending or descending order. ## AggregateOrderByNumberFunction Enum The `AggregateOrderByNumberFunction` enum values define aggregate functions for number fields like double, long, percent and so on. ``` enum AggregateOrderByNumberFunction { AVG COUNT COUNT_DISTINCT MAX MIN SUM } ``` Use these values with numeric fields. - `AVG` - Returns the average value of a field. - `COUNT` - Returns the number of rows matching the query criteria. - `COUNT_DISTINCT` - Returns the number of distinct non-null field values matching the query criteria. - `MAX` - Returns the maximum value of a field. - `MIN` - Returns the minimum value of a field. - `SUM` - Returns the total sum of a numeric field. ## NullsOrder Enum The `NullsOrder` enumeration type specifies the order in which nulls appear in the result set. By default, null values are sorted first. ``` enum NullsOrder { FIRST LAST } ``` Use these values in the `orderBy` argument. - `FIRST` - Order the null values first. This is the default. - `LAST` - Order the null values last. ## ResultsOrder Enum The `ResultsOrder` enumeration type specifies whether the results are ordered in ascending or descending order. By default, the result is ordered in ascending order. ``` enum ResultsOrder { ASC DESC } ``` Use these values in the `orderBy` argument. - `ASC` - Ascending order (default) - `DESC` - Descending order ## User_OrderBy Type Some fields like `CreatedBy` and `Owner` correspond to a `_OrderBy` type, which contains additional fields. ``` type User_GroupBy { AboutMe: AggregateOrderByStringClause Account: Account_OrderBy AccountId: NoFunctionAggregateOrderByClause Contact: Contact_OrderBy NumberOfFailedLogins: AggregateOrderByNumberClause # Other User_OrderBy fields } ``` ## See Also [Aggregate Examples](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate-examples.md) [SOQL and SOSL Reference: Date Functions](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_date_functions.htm) # Order By Schema | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | Each orderable field on a record, such as on an account, gets a corresponding field on `Account_OrderBy` with type `OrderByClause`. The `OrderByClause` type allows you to specify ascending or descending order, as well as the order of null values. Orderable fields are linked to `InputObject` types like `OrderByClause`, depending on their type, such as `User_OrderBy` for user fields, or `OrderByGeolocation` for geolocation fields. ``` input Account_OrderBy { Id: OrderByClause Name: OrderByClause AnnualRevenue: OrderByClause Location__c: OrderByGeolocationClause Owner: User_OrderBy Parent: Account_OrderBy } ``` ## OrderByClause Type Let's take a look at an example account object that demonstrates how fields map to `Account_OrderBy`. ``` type Account { Id: ID Name: StringValue AnnualRevenue: CurrencyValue Location__c: Geolocation } ``` The `OrderByClause` type contains `order` and `nulls` enumeration types. ``` input OrderByClause { order: ResultOrder nulls: NullOrder } ``` ## ResultOrder Enum The `ResultOrder` enumeration type specifies whether the results are ordered in ascending or descending order. By default, the result is ordered in ascending order. ``` # Specifies whether the results are ordered in ascending or descending order enum ResultOrder { ASC DESC } ``` ## NullOrder Enum The `NullOrder` enumeration type specifies the order in which nulls appear in the result set. By default, null values are sorted first. ``` # Specifies the order in which nulls appear in the result set enum NullOrder { FIRST LAST } ``` The order by object has input object fields for each parent relationship the object has. The field has the same name as the parent relationship, and have the `OrderBy` type corresponding to the object that the relationship points at. ``` type Contact { AccountId: IDValue Account: Account # the 'Contact' sObject has a relationship 'Account' which points at the 'Account' object } input Contact_OrderBy { AccountId: OrderByClause Account: Account_OrderBy # 'Account_OrderBy" is used as the input type for the 'Account' input object field } input Account_OrderBy { # has the order by fields for Account } ``` ## OrderByGeolocationClause Type Geolocation fields map to the `OrderByGeolocationClause` type. Its constituent fields `Location__Latitude__s` and `Location__Longitude__s` map to the `OrderByClause` type. ``` input Account_OrderBy { Name: OrderByClause Location__c: OrderByGeolocationClause Location__Latitude__s: OrderByClause Location__Longitude__s: OrderByClause } ``` The `DistanceInput` type specifies the latitude and longitude fields on a geolocation field. ``` DistanceInput { latitude: Float longitude: Float } ``` For more information, see [Location-Based Filters](https://developer.salesforce.com/docs/platform/graphql/guide/filter/filter-location.md). ## See Also [`ORDER BY` statement](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm) # Order Results | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | Order objects are used to order the result set of records. All sObjects in the schema have a corresponding order type. The order type combines the object API name with the `_OrderBy` suffix. For example, `Account` has a corresponding `Account_OrderBy` type. ## Query Sortable Fields Fields that have a scalar or Field Value Type that support ordering have a corresponding Input Object Field of type `OrderByClause`. The following field types support ordering. - Int - String - Boolean - Id - DateTime - Time - Date - TextArea - PhoneNumber - Email - Url - Currency - Geolocation - Longitude - Latitude - Picklist - Long - Double - Percent - Base64 Consider these guidelines for specific field types. - Corporate currency always sorts using corporate currency value, if available. - Phone data does not include any special formatting when sorting, for example, non-numeric characters such as dash or parentheses are included in the sorting. - Picklist sorting is defined by the picklist sort determined during setup. These data types are not supported. - Multi-select picklist - Rich text area - Long text area - Encrypted - Data category group reference, if Salesforce Knowledge is enabled To identify sortable fields on an object, query the [objectInfos type](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-objectinfo.md). ``` query objectInfos { uiapi { objectInfos(apiNames: ["Account"]) { fields { ApiName sortable compound } } } } ``` Not all sortable fields can be ordered. Not all fields returned by `objectInfos` are sortable. For example, Address compound fields aren't sortable. To sort using compound fields, use its constituent fields. For example, BillingLatitude and BillingLongitude are constituent fields of the BillingAddress compound field. ## Use the `orderBy` Argument Multiple column sorting is supported by listing more than one field on the `orderBy` argument. The order of results isn't guaranteed unless you use the `orderBy` argument in a query. When you use `orderBy`, the order of results can vary if there are duplicate values on the fields you use in the `orderBy` argument. For example, if there are multiple account records assigned to the same industry, the order of the results can vary. To ensure that the order of the results is consistent, add the Id to the `orderBy` argument. ``` query IndustryOrderBy { uiapi { query { Account ( orderBy: { Industry: { order: ASC }, Id: { order: ASC } }) { edges { node { Name { value } Industry { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Name, Industry FROM Account ORDER BY Industry, Id ``` The following example returns Account records in alphabetical order by first name, sorted in descending order, with accounts that have null names appearing last. ``` query IndustryOrderByNulls { uiapi { query { Account ( orderBy: { Name: { order: DESC, nulls: LAST }}) { edges { node { Name { value } } } } } } } ``` The previous query is similar to the following SOQL statement. ``` SELECT Name FROM Account ORDER BY Name DESC NULLS LAST ``` ## See Also [SOQL and SOSL Reference: `ORDER BY` statement](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_orderby.htm) # Paginate Results | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | GraphQL API returns the first 10 results of a query by default. Based on the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm), the Connection object contains the returned object and the `node` (account, for example), `totalCount`, and `resultPageCount` objects. Additionally, the `pageInfo` object contains cursor information and if there are more results to return. Within [the `RecordQuery` type](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-record-objects.md), each field is a [Relay Record Connection](https://relay.dev/graphql/connections.htm) type. Connections enable paging through the result set with ease. Connections are made up of four types: - `Connection`: The root object for the paged collection, which ties together the result set with the `PageInfo` type. The `Connection` type is specific to the type of resource being paged, for example when paging through `Account` objects the `Connection` type is `AccountConnection`. - `Edge`: Ties together the actual record result type, for example `Account`. Includes a cursor that points to the specific location in the result set and the `Node` type. - `Node`: The actual resource being paged. - `PageInfo`: Contains relative position information, which shows where in the entire result set the current page is located. The `PageInfo` type is the same for every `Connection` type. Use pagination several ways. - Paginate using [an upper-bound limit](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use-upperbound.md). Available in API version 59.0 and later. - Paginate by [switching from relay record pagination to upper-bound limit pagination](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use-upperbound.md#use-the-upper-bound-limit-in-a-subsequent-query). Available in API version 60.0 and later. - Paginate using GraphQL [relay record connections](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use.md). # Paginate with Record Connections | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | To retrieve more than 200 records, we recommend using [an upper-bound limit](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use-upperbound.md). Using pagination without an upper-bound limit lets you retrieve up to 4,000 records only. In API v60.0 and later, you can [switch from record connection pagination to upper-bound limit pagination](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use-upperbound.md#use-the-upper-bound-limit-in-a-subsequent-query), allowing you to retrieve more than 4,000 records. ## Paging Through Results Record Connections paging uses the `first` and `after` arguments based on [relay record connections](https://relay.dev/graphql/connections.htm), which follows the specification for [forward pagination arguments](https://relay.dev/graphql/connections.htm#sec-Forward-pagination-arguments). - The `first` argument is the maximum number of records to fetch as part of your query. **note:** The initial query results can return any number of records up to the number you specify in the `first` argument. For example, if you request five records and the initial query result returns four records, use the `after` argument to page to the remaining record. - The `after` argument is a cursor used to page through the result set. Use a returned cursor to continue paging through the result set from that cursor position. The `after` argument is typically set to the value of the `endCursor` field on the relay connection's `PageInfo`. If you want to page from a particular element in the result set, use the `cursor` field from a relay edge. ``` query accounts { uiapi { query { Account { edges { node { Id Name { value } } } totalCount pageInfo { endCursor hasNextPage hasPreviousPage } } } } } ``` The query results are as follows. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0011a000005slmbAAA", "Name": { "value": "GenePoint" } } }, { "node": { "Id": "0011a000005slmlAAA", "Name": { "value": "United Oil & Gas Corp" } } }, // 8 more account records (10 results by default) ], "totalCount": 26, "pageInfo": { "endCursor": "djE6OQ==", "hasNextPage": true, "hasPreviousPage": false } } } } }, "errors": [] } ``` This example returns the next set of results after the `djE6OQ==` end cursor from the previous example. ``` query accounts { uiapi { query { Account (first:5, after:"djE6OQ==") { edges { node { Id Name { value } } } } } } } ``` The query results are as follows. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0011a000005slmlAAA", "Name": { "value": "United Oil & Gas Corp" } } }, // more results } ] } } } }, "errors": [] } ``` Here's an example query for accounts with cursors [using variables](https://graphql.org/learn/queries/#variables). ``` query accountsWithCursors($first: Int, $after: String) { uiapi { query { Account(first: $first, after: $after) { edges { node { Id Name { value } } cursor } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } } } } ``` The query returns the account IDs and names with cursor information. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0015f00000Afmo9AAB", "Name": { "value": "Burlington Textiles Corp of America" } }, "cursor": "djE6Mw==" }, { "node": { "Id": "0015f00000AfmoAAAR", "Name": { "value": "Pyramid Construction Inc." } }, "cursor": "djE6NA==" }, { "node": { "Id": "0015f00000AfmoBAAR", "Name": { "value": "Dickenson plc" } }, "cursor": "djE6NQ==" }, { "node": { "Id": "0015f00000AfmoCAAR", "Name": { "value": "Grand Hotels & Resorts Ltd" } }, "cursor": "djE6Ng==" }, { "node": { "Id": "0015f00000AfmoDAAR", "Name": { "value": "United Oil & Gas Corp." } }, "cursor": "djE6Nw==" }, { "node": { "Id": "0015f00000AfmoEAAR", "Name": { "value": "Express Logistics and Transport" } }, "cursor": "djE6OA==" }, { "node": { "Id": "0015f00000AfmoFAAR", "Name": { "value": "University of Arizona" } }, "cursor": "djE6OQ==" } ], "pageInfo": { "hasNextPage": true, "hasPreviousPage": false, "startCursor": "djE6MA==", "endCursor": "djE6OQ==" } } } } }, "errors": [] } ``` ## Paging Through Record Connections Child Relationships You can page through the child records on a queried parent record. Paging on the parent and children records at the same time isn't supported. The child relationships records in the response are paginated and include cursor and pagination information. Use the `first` argument to specify the number of records to return. The default is 10. ``` query accounts { uiapi { query { Account ( where: { Name: { eq: "Edge Communications" } } ) { edges { node { Contacts ( first: 5 ) { edges { cursor node { Name { value } } } totalCount pageInfo { hasNextPage } } } } } } } } ``` The query results are as follows. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Contacts": { "edges": [ { "cursor": "djE6MA==", "node": { "Name": { "value": "Sean Forbes" } } }, { "cursor": "djE6MQ==", "node": { "Name": { "value": "Rose Gonzalez" } } } ], "totalCount": 2 } } }, { "node": { "Contacts": { "edges": [], "totalCount": 0 } } } ] } } } }, "errors": [] } ``` The maximum number of child relationship records to return can be specified using the `first` argument. However, if supplying a cursor value to the `after` argument of a child relationship, then the parent record must be limited to a single result. For example: ``` query paginateChild { uiapi { query { Account(first:1) { # must limit to one result as we are paging through the child edges { node { Cases(first:100, after:"djE6Mw==") { edges { cursor node { Id } } } } } } } } } ``` # Paginate with Upper-Bound Limit | AVAILABLE API VERSION | | --------------------- | | API v59.0 and later | Use pagination with an upper-bound limit for queries that return 200 or more records. To paginate with an upper-bound limit, use the `upperBound` argument in the initial query or, starting in API v60.0, in a subsequent query. ## Use the Upper-Bound Limit in the Initial Query When you use an upper-bound limit, you can paginate up to the `upperBound` number of records. - The `first` argument corresponds to the batch size to query and subsequently to retrieve the next batch if there are more records than a certain threshold. `first` can have a value from 200 to 2000 only. - The `after` argument is a cursor used to page through the result set. Omit the argument or provide a null value to start at the beginning of the result set. Use `after` following your initial query to get the next batch of results. - The `upperBound` argument specifies a limit for the number of records to retrieve. We recommend using a high default value for your query. In API v59.0, you must specify the `upperBound` argument in the initial query. In API v60.0 and later, you can specify the `upperBound` argument in a subsequent query, allowing you to switch from record connection pagination to upper-bound limit pagination. This example uses the `upperBound` limit. ``` query RecordsWithPagination { uiapi { query { Contact (first:200, upperBound:5000) { edges { node { Id Name { value } } } totalCount pageInfo { hasNextPage endCursor } } } } } ``` An example response looks like this. ``` { "data": { "uiapi": { "query": { "Contact": { "edges": [ { "node": { "Name": { "value": "Rose Gonzalez" } } }, { "node": { "Name": { "value": "Sean Forbes" } } } //More records in the result here ], "totalCount": 1034, "pageInfo": { "hasNextPage": true, "endCursor": "djI6LTE1NjE0NTE4NDc6MHI4eHgxdk5tcUM5SU1jQUVOLTE5OQ==" } } } } }, "errors": [] } ``` ## Retrieve the Next Batch After Using upperBound in the Initial Query After using the upper-bound limit to send an initial query, retrieve the next batch of results. To retrieve the next batch, use the `first` and `after` arguments. ``` query RecordsWithPagination { uiapi { query { Contact (first:200, after:"djI6LTE1NjE0NTE4NDc6MHI4eHgxdk5tcUM5SU1jQUVOLTE5OQ==") { edges { node { Id Name { value } } } totalCount pageInfo { hasNextPage endCursor } } } } } ``` ## Use the Upper-Bound Limit in a Subsequent Query If you don't include the `upperBound` argument initially, the query applies simple pagination using relay record connections. In API v60.0 and later, you can use the `upperBound` argument in a subsequent query to retrieve more than 4,000 records overall. This means you can switch from using record connection pagination to using upper-bound limit pagination for the same query. Here’s an example where we initially query a batch of 2,000 accounts using the `first` argument. ``` { uiapi { query { Account(first:2000) { totalCount pageInfo { hasPreviousPage hasNextPage startCursor endCursor } edges { cursor node { Id } } } } } } ``` Here's an example result of the query with simple pagination. ``` { "data": { "uiapi": { "query": { "Account": { "totalCount": 4087, "pageInfo": { "hasPreviousPage": false, "hasNextPage": true, "startCursor": "djE6MA==", "endCursor": "djE6MTk50Q==" }, "edges": [ { // cursor and node properties removed for brevity }, .... ] } } } } } ``` ## Retrieve the Next Batch After Using upperBound in a Subsequent Query After an initial relay record connections query, retrieve the next batch of results and include the `upperBound` argument in a subsequent query. Continuing with the previous example, we query the next batch of results using the `first`, `after`, and `upperBound` arguments, switching to upper-bound limit pagination. The `after` argument uses the `endCursor` value from the result of the initial query. The `upperBound` argument specifies the limit for the number of records to retrieve. Even though the initial query requested a batch of 2,000 records, the subsequent upper-bound limit pagination allows the query to return up to 5,000 records. ``` { uiapi { query { Account(first:2000, after:"djE6MTk5OQ==", upperBound:5000) { totalCount pageInfo { hasPreviousPage hasNextPage startCursor endCursor } edges { cursor node { Id } } } } } } ``` The example result looks like this. ``` { "data": { "uiapi": { "query": { "Account": { "totalCount": 4087, "pageInfo": { "hasPreviousPage": true, "hasNextPage": true, "startCursor": "djI6LTY1MTM3MjA4OjByOHh4MktEZkJBSTdJOUFXTC0yMDAw", "endCursor": "djI6LTY1MTM3MjA4OjByOHh4MktEZkJBSTdJOUFXTC0zOTk5" }, "edges": [ { "cursor": "djI6LTY1MTM3MjA4OjByOHh4MktEZkJBSTdJOUFXTC0yMDAw", "node": { "Id": "001xx000003GestAAC" } }, { "cursor": "djI6LTY1MTM3MjA4OjByOHh4MktEZkJBSTdJOUFXTC0yMDAx", "node": { "Id": "001xx000003GesuAAC" } }, ... ] } } } } } ``` Then you can make subsequent queries using `first` and `after` arguments to page through more results up to the upper-bound limit. ## Paging Through upperBound Child Relationships You can page through child records by querying a parent record with an `upperBound` argument. When the parent query uses the `upperBound` argument, the child query must use this argument as well. You can also page through child records using the `upperBound` argument when the parent query doesn't use the `upperBound` argument. Paging on the parent and children records at the same time isn't supported. Keep in mind that paging through child relationships with large upper-bound limits can have performance implications. ## Upper-Bound Pagination Limitations When querying with the `upperBound` argument, consider these limitations. - You must query 200 records or more. For example, set `first:200` with `upperBound:5000`. To query fewer than 200 records, use [simple pagination](https://developer.salesforce.com/docs/platform/graphql/guide/paginate-use.md) without an upper-bound limit. - Records created after pagination begins aren't included in results. To view newly created records, refresh the results by restarting pagination from the beginning. - Paging through child relationships with large upper-bound limits can have performance implications. ## See Also [_SOAP API Developer Guide_: queryMore()](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_querymore.htm) # Paginate Your Results GraphQL queries can return up to 2000 records. By default, the wire adapter returns the first 10 results and you can request subsequent pages using the cursor information. The GraphQL API and graphql wire adapter use the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) for pagination of all data collections they return. ## Query with Cursor Information To specify the number of records to return, use the `first` argument. The default number is 10. If `hasNextPage` is true, you can provide the `endCursor` value to the `after` argument of a subsequent query, which requests the next page of results. **note:** Backward pagination using `last` and `before` isn’t currently supported. Here’s a basic query with cursor information. ```javascript query AccountRecords { uiapi { query { Account (first: 5, after: "endCursorFromPreviousQuery") { edges { node { Id Name { value } } } totalCount pageInfo { endCursor hasNextPage } } } } } ``` This example response contains cursor information. ```json { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "001RM000005ZclBYAS", "Name": { "value": "GenePoint" } } }, { "node": { "Id": "001RM000005Zcl6YAC", "Name": { "value": "United Oil" } } } ], // 3 more node objects here removed for brevity "totalCount": 5, "pageInfo": { "endCursor": "djE6Nw==", "hasNextPage": true } } } } }, "errors": [] } ``` **tip:** Requesting `totalCount` can have performance implications for large or complex queries. ## Implement Pagination in LWC In this example, we create a `simplePagination` component with a reset button and a next page button. The reset button resets the pagination. The next page button pages through the results. The component displays 5 results on each page by default. It uses an `isLastPage` property to determine if the next page button is disabled. **tip:** The [`graphqlPagination` component](https://github.com/trailheadapps/lwc-recipes/tree/main/force-app/main/default/lwc/graphqlPagination) in the [lwc-recipes repo](https://github.com/trailheadapps/lwc-recipes) gets contact data with pagination to navigate through the list. ```javascript // simplePagination.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; const pageSize = 3; export default class GraphqlPagination extends LightningElement { after; pageNumber = 1; @wire(graphql, { query: gql` query paginatedContacts($after: String, $pageSize: Int!) { uiapi { query { Contact(first: $pageSize, after: $after, orderBy: { Name: { order: ASC } }) { edges { node { Id Name { value } } } pageInfo { endCursor hasNextPage hasPreviousPage } } } } } `, variables: "$variables", }) contacts; get variables() { return { after: this.after || null, pageSize, }; } get isFirstPage() { return !this.contacts.data?.uiapi.query.Contact.pageInfo.hasPreviousPage; } get isLastPage() { return !this.contacts.data?.uiapi.query.Contact.pageInfo.hasNextPage; } handleNext() { if (this.contacts.data?.uiapi.query.Contact.pageInfo.hasNextPage) { this.after = this.contacts.data.uiapi.query.Contact.pageInfo.endCursor; this.pageNumber++; } } handleReset() { this.after = null; this.pageNumber = 1; } } ``` The component uses the `lightning-button` base component to display the reset button and next page button. It displays the account name and annual revenue in the `lightning-card` base component. ```html ``` When clicked, the next page button sets the `lastCursor` value to the `endCursor` value and displays the next set of results. ## See Also [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md) [Feature Limitations of Offline GraphQL](https://developer.salesforce.com/docs/atlas.en-us.mobile_offline.meta/mobile_offline/use_graphql_limitations.htm) # Parent and Child Relationship Filters | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | In [Field Operators](https://developer.salesforce.com/docs/platform/graphql/guide/filter-fields.md) and [Boolean Operators](https://developer.salesforce.com/docs/platform/graphql/guide/filter-boolean.md), we discussed how fields map to the filter type and how to combine filters with the `AND`, `OR`, and `NOT` functions. The sObject is also added to the filter type for each parent relationship. Objects can have a child-to-parent relationship or a parent-to-child relationship. For example, the Contact object has a child-to-parent relationship to the Account object. An Account has parent-to-child relationships to Assets, Cases, and Contacts, and other objects. ## Child-to-Parent Relationships Child-to-parent relationships can be many-to-one, just like multiple child contacts can be on a parent account. ``` query { uiapi { query { Contact (where: { Account: { Industry: { eq : "media" } } } ) { edges { node { Id Name { value } Account { Name { value } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name, Account.Name FROM Contact WHERE Account.Industry = 'media' ``` For some objects that can have a parent relationship with the same object, you can query the parent relationship using the `Parent` field. For example, an account can have a parent account and a campaign can have a parent campaign. ``` query AccountWithNameAndParent { uiapi { query { Account(where: { Name: { like: "Express%" } }) { edges { node { Id Name { value } Parent { Id Name { value } } } } } } } } ``` Accounts without parent account records are also returned. The previous query returns this example response. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "001RM000005ZdMLYA0", "Name": { "value": "Express Logistics", "displayValue": null }, "Parent": { "Id": "001RM000005Zcl7YAC", "Name": { "value": "Express Logistics and Transport" } } } }, { "node": { "Id": "001RM000005Zcl7YAC", "Name": { "value": "Express Logistics and Transport", "displayValue": null }, "Parent": null } } ] } } } }, "errors": [] } ``` Here’s a query that returns cases with their parent accounts. Cases without parent accounts are also returned by the query. ``` query CasesWithParent { uiapi { query { Case { edges { node { Subject { value } Parent { Id Account { Name { value } } } } } } } } } ``` You can filter records to return only those accounts without a null Parent Id value. ``` query { uiapi { query { Account (where: { Parent: { Id: { ne: null }}}) { edges { node { Name { value } Parent { Name { value } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, Parent.Name FROM Account WHERE Parent.Id!=null ``` Only accounts with parent account records are returned. The previous query returns this example response. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Name": { "value": "United Oil & Gas Corp" }, "Parent": { "Name": { "value": "United Oil & Gas, UK" } } } } ] } } } }, "errors": [] } ``` ## Parent-to-Child Relationships Parent-to-child relationships are usually one-to-many, just like a parent account can have many child contacts. To include subqueries for standard objects, specify the plural form of the object name, which is the name of the relationship for the object. For example, by selecting from Account, you can query the children records via the Cases, Contacts, and Opportunities fields. Let’s say you want to query cases on an account. ``` query { uiapi { query { Account { edges { node { Id Name { value } Cases { edges { node { Subject { value } Priority { value } } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, ( SELECT Subject, Priority FROM Cases ) FROM Account ``` You can also query account names and the last name of contacts on each account. ``` query { uiapi { query { Account { edges { node { Name { value } Contacts { edges { node { LastName { value } } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, ( SELECT LastName FROM Contacts ) FROM Account ``` Some objects have children relationships to the same object. For example, use the `ChildAccounts` field to query children accounts on account records. Accounts without children accounts are also returned. ``` query AccountWithChildrenAccounts { uiapi { query { Account(where: { Name: { like: "Express%" } }) { edges { node { Id Name { value } ChildAccounts { edges { node { Name { value } } } } } } } } } } ``` To query object metadata that includes child relationships, pass in the [`childRelationships` field](https://developer.salesforce.com/docs/platform/graphql/query/query-objectinfo.md). You can also traverse the parent-to-child relationship using a reference to a different object. In this case, the CreatedBy field references the Name field on the User object. ``` query { uiapi { query { Account { edges { node { Name { value } Notes { edges { node { CreatedBy { Name { value } } } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, ( SELECT CreatedBy.Name FROM Notes ) FROM Account ``` A query and its subqueries can include the `where` argument. The argument can filter on a supported object in the current scope via parent relationships. For example, you can query accounts in a given industry and the last name of every contact whose created by first name is 'Marc'. ``` query { uiapi { query { Account ( where: { Industry: { eq: "Technology"}} ) { edges { node { Name { value } Contacts (where: { CreatedBy: { FirstName: { eq : "Marc" } } } ) { edges { node { LastName { value } } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Name, ( SELECT LastName FROM Contacts WHERE CreatedBy.FirstName = 'Marc') FROM Account WHERE Industry = 'Technology' ``` ## Lookup Relationships With a [lookup relationship](https://help.salesforce.com/s/articleView?id=platform.overview_of_custom_object_relationships.htm), you can retrieve field information on a child or parent object. For example, you can query accounts and their associated contact names. ``` query AccountWithContacts { uiapi { query { Account(where: { Name: { like: "Edge%" } }) { edges { node { Name { value } Contacts { edges { node { Name { value } } } } } } } } } } ``` Accounts without child contact records are also returned. The previous query returns this example response. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Name": { "value": "Edge Engineering" }, "Contacts": { "edges": [] } } }, { "node": { "Name": { "value": "Edge Communications", "displayValue": null }, "Contacts": { "edges": [ { "node": { "Name": { "value": "Sean Forbes" } } }, { "node": { "Name": { "value": "Rose Gonzalez" } } } ] } } } ] } } } }, "errors": [] } ``` You can also use the [`orderBy` clause](https://developer.salesforce.com/docs/platform/graphql/order.md) to order your child records in ascending or descending order. ``` query AccountsWithContactsOrderBy { uiapi { query { Account (where: {Name: { eq: "Alpha Dynamics"}}) { edges { node { Name { value } Contacts(orderBy: { Name: {order: ASC } }) { edges { node { Name { value } } } } } cursor } } } } } ``` The child records are paginated and include cursor and pagination information. By default, the first 10 children records are returned. To specify the number of children records to return, use the `first` argument on the child object. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Name": { "value": "Alpha Dynamics" }, "Contacts": { "edges": [ { "node": { "Name": { "value": "Amy Taylor" } } }, { "node": { "Name": { "value": "Caroline Kingsley" } } }, { "node": { "Name": { "value": "Jennifer Wu" } } } ] } }, "cursor": "djE6MA==" } ] } } } }, "errors": [] } ``` ## Lookup Relationships with null Values With an `orderBy` argument, records are returned even if the reference field has a null value. For example, any case records with a null AccountId field are also returned. ``` query { uiapi { query { Case (orderBy: { Account: { Name: { order: ASC } } } ) { edges { node { Id CaseNumber { value } AccountId { value } Account { Name { value } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, CaseNumber, Account.Id, Account.Name FROM Case ORDER BY Account.Name ``` With a `where` argument that uses the `or` boolean operator, records are returned even if the reference field value in a record is null. For example, if a contact with a specific LastName has a null AccountId field and another contact with a different last name and specific parent account name, the query returns both contacts. ``` query { uiapi { query { Contact (where: { or: [ { LastName: { eq: "Young" } }, { Account : { Name: { eq: "Edge Communications" } } } ] }) { edges { node { Id FirstName { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, FirstName FROM Contact WHERE LastName = 'Young' or Account.Name = 'Edge Communications' ``` With a `where` argument that checks for a value in a parent field, the record is returned even if the parent value is null. ``` query { uiapi { query { Case (where: { Contact: { LastName: { eq: null } } } ) { edges { node { Id Description { value } Priority { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Description, Priority FROM Case WHERE Contact.LastName = null ``` ## See Also [_SOQL and SOSL Reference_: Understanding Relationship Fields and Polymorphic Fields](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_and_polymorph_keys.htm) [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md) # Polymorphic Relationship Filters | AVAILABLE API VERSION | | ------------------------------------------------------ | | API v56.0 and later | | Event and Task (Beta) available in API v59.0 and later | A polymorphic relationship is one where an object can be one of several object types. For example, an event can have a polymorphic relationship to an account, campaign, or opportunity via the Related To field. Conversely, a contact has a non-polymorphic relationship to an account via the Account Name field. [Common polymorphic fields](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_and_polymorph_keys.htm#common-polymorphic-fields) include the Owner, Who, and What fields. To query using a polymorphic relationship, use [inline fragments](https://graphql.org/learn/queries/#inline-fragments) with the `... on Object` syntax. ## Owner Polymorphic Field The Owner field represents the parent of the record. For example, a case owner can be a Group or User object. When the parent relationship is polymorphic, an input object following the naming convention `__Filters` is constructed and used as the filter type for that parent relationship. The Owner field follows the naming convention `_Owner`, which is used as the filter type for that parent relationship. For example, the Case object’s Owner filter has a type of `Case_Owner_Filters`. ``` type Case { Owner: Case_Owner } ``` The union has one possible type for each concrete type that participates in the polymorphic relationship. ``` union Case_Owner = Group | User ``` The input object type has one input object field of the filter type for each object that participates in the polymorphic relationship. ``` input Case_Owner_Filters { Group: Group_Filter Name: Name_Filter User: User_Filter } ``` Let’s say you query cases that match a specified Owner.Name value. Case records correspond to owners that are either groups or users. This example queries cases where the owner’s username starts with "D" and the Owner.Type is a User object. ``` query { uiapi { query { Case ( where: { Owner: { User: { Name: {like: "D%"} }}} ) { edges { node { Id Owner { ... on User { Name { value } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Owner.Name FROM Case WHERE Owner.Name like 'D%' ``` In the next example, the Name field is available only when the node is of type User. ``` query AccountCasesDetail { uiapi { query { Contact ( where: { Name: { like: "Rose%" } } ) { edges { node { Id Name { value displayValue } Cases { edges { node { Subject { value } Owner { ... on User { Name { value } } } CreatedDate { displayValue } IsEscalated { value } } } } } } } } } } ``` ## Who Polymorphic Field The Who field represents the person associated with the record. Some objects, like Event, Task, ContactRequest, and SocialPost, have a Who field. For more information, see the [Object Reference for the Salesforce Platform](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/field_types.htm). **note:** Not all objects that have a Who field are available in [GraphQL API via UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). For example, the `ContactRequest` object's `Who` filter has a type of `ContactRequest_Who_Filters`. This input object has one input object field for each concrete type that participates in the polymorphic relationship. ``` type ContactRequest { who: ContactRequest_Who } ``` The union has one possible type for each concrete type that participates in the polymorphic relationship. ``` union ContactRequest_Who = Contact | Lead | User ``` ``` input ContactRequest_Filter { who: ContactRequest_Who_Filters # the filter object contains another filter object constructed for the polymorphic type } ``` The input object type has one input object field of the filter type for each object that participates in the polymorphic relationship. ``` input ContactRequest_Who_Filters { Contact: Contact_Filter Lead: Lead_Filter Name: Name_Filter User: User_Filter } ``` ContactRequest records have a Who field that can reference a contact, lead, name, or user. This example query applies to ContactRequest records whose owners can be either a Group or User object. It filters the records based on the User object and select records where the Who.Type is a Contact object. ``` query { uiapi { query { ContactRequest ( where: { Owner: { User: { FirstName: {like: "D%"} }}} ) { edges { node { Id Who { ... on Contact { Name { value } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Who.FirstName, Who.LastName FROM ContactRequest WHERE Owner.FirstName LIKE 'D%' ``` ## What Polymorphic Field The What field represents non-person objects that are associated with the record. Some objects, like Event and ContactRequest, have a What field. For more information, see the [Object Reference for the Salesforce Platform](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/field_types.htm). **note:** Not all objects that have a Who field are available in [GraphQL API via UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). For example, the `ContactRequest` object's `What` filter has a type of `ContactRequest_What_Filters`. This input object has one input object field for each concrete type that participates in the polymorphic relationship. ``` type ContactRequest { who: ContactRequest_What } ``` The union has one possible type for each concrete type that participates in the polymorphic relationship. ``` union ContactRequest_What = Account | Case | Opportunity ``` ``` input ContactRequest_Filter { What: ContactRequest_What_Filters # the filter object contains another filter object constructed for the polymorphic type } ``` The input object type has one input object field of the filter type for each object that participates in the polymorphic relationship. ``` input ContactRequest_What_Filters { Account: Account_Filter Case: Case_Filter Name: Name_Filter Opportunity: Opportunity_Filter } ``` ContactRequest records have a What field that can reference an account, case, name, or opportunity. This example query applies to ContactRequest records whose What field is Account. It returns ContactRequest records with the Name field, the What.Name field where the What.Type is Account. ``` query { uiapi { query { ContactRequest { edges { node { Id Name { value } What { ... on Account { Name { value } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name, What.Name FROM ContactRequest ``` ## Filter Polymorphic Fields with Boolean Operators You can filter the result set by the value of the underlying polymorphic types data. Each filter is combined with an [`and` operator](https://developer.salesforce.com/docs/platform/graphql/guide/filter-boolean.md) to assert the polymorphic relationship is of the filter type. ``` query { uiapi { query { ContactRequest ( where: { and: [{ Who: { Contact: { FirstName: { like: "R%" } } }, Who: {Contact: { LastName: { like: "G%" } } } }] }) { edges { node { Id Name { value } } } } } } } ``` The query is similar to this SOQL statement. ``` SELECT Id, Name FROM ContactRequest WHERE Who.FirstName LIKE 'R%' AND Who.LastName LIKE 'G%' ``` You can work with multiple fields on a polymorphic filter with an [`or` operator](https://developer.salesforce.com/docs/platform/graphql/guide/filter-boolean.md). This example returns ContactRequest records with the Id, Name, and What.Name fields where the What.Type is Account. It filters the records where the What.Name is "Salesforce" or the Who.FirstName contact names start with "R". ``` query { uiapi { query { ContactRequest ( where: { or: [{ What: { Account: { Name: { eq: "Salesforce" } } }, Who: { Contact: { FirstName: { like: "R%" } } } }] }) { edges { node { Id Name { value } What { ... on Account { Name { value } } } } } } } } } ``` The previous query is similar to this SOQL statement where the individual clauses are joined with `OR`, allowing selective filtering based on the underlying type of the polymorphic relationship. ``` SELECT Id, Name, What.Name FROM ContactRequest WHERE What.Name = 'Salesforce' OR Who.FirstName LIKE 'R%' ``` **note:** Although objects with an `OwnerId`, `WhatId`, or `WhoId` field have polymorphic parent relationships, GraphQL API includes as possible types only [those objects that are available via the User Interface API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm). If the parent relationship is non-polymorphic, then the corresponding filter type for that object is used. ## Non-Polymorphic Relationships Consider an account that as a parent relationship `CreatedBy` points to the User object. ``` type Account { CreatedBy: User } ``` As the relationship is non-polymorphic, the filter has a field with the same name of the parent relationship with the corresponding filter type. ``` input Account_Filter { CreatedBy: User_Filter } ``` To find all accounts created by a particular user, we can construct a `where` argument as follows. ``` query { uiapi { query { Account ( where: { CreatedBy: { FirstName: { like: "Misato" } } } ) { edges { node { Id Name { value } } } } } } } ``` This query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE CreatedBy.FirstName='Misato' ``` # Query Multiple Objects Dynamically GraphQL API simplifies how you query records across multiple objects. You can write a query that asks for the exact fields you want in one call. Using GraphQL API to query multiple objects is more performant than making multiple Apex wire calls. Previously, you could also achieve this by calling a custom Apex controller and then pass the returned records to [the `getRecords` wire adapter](https://developer.salesforce.com/docs/platform/lwc/guide/reference-wire-adapters-records.html) with additional parameters that request records from other objects. Additionally, when statically defined, GraphQL API queries support [referential integrity](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-best.md#use-aliases-with-custom-objects-and-fields) for references to objects and fields. You don’t need to [import references to objects and fields](https://developer.salesforce.com/docs/platform/lwc/guide/data-wire-service-about.html#import-references-to-salesforce-objects-and-fields) like you do with other LWC wire adapters. ## Use GraphQL Variables in Multiple Objects Query When you request records across multiple objects, you don’t always know the record ID. For example, the record ID can vary depending on the record page you’re viewing, or the user ID can depend on the context user. To provide the record ID as a dynamic value for your query, use [the `variables` configuration parameter](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-reactive.md). **tip:** The [`graphqlMultipleObjects` component](https://github.com/trailheadapps/lwc-recipes/tree/main/force-app/main/default/lwc/graphqlMultipleObjects) in the [lwc-recipes repo](https://github.com/trailheadapps/lwc-recipes) retrieves and displays account and contact records using a single query. This example queries all contacts related to an account and displays the contacts with record data from the User object. The query requests the `Id` and `Name` fields on the Contact object, along with the `Id` and `Name` fields on the User object. The `AccountId` field on the Contact object corresponds to the ID of an account record. Use the `recordId` property to include the account [record context](https://developer.salesforce.com/docs/platform/lwc/guide/use-record-context.html) for the contacts query. To get record data about the current user, import the [`@salesforce/user/Id` module](https://developer.salesforce.com/docs/platform/lwc/guide/get-current-user.html). ```javascript //multipleObjectsGraphQL.js import { LightningElement, wire, api } from "lwc"; import { gql, graphql } from "lightning/graphql"; import Id from "@salesforce/user/Id"; export default class MultipleObjectsGraphQL extends LightningElement { queryError; contacts; @api recordId; userName; userId = Id; @wire(graphql, { query: "$contactQuery", variables: "$queryData", }) recordsQueryResult({ data, errors }) { if (data) { this.contacts = data.uiapi.query.Contact.edges.map((edge) => edge.node); this.userName = data.uiapi.query.User.edges.map((edge) => edge.node); } if (errors) { this.queryError = errors; } } get contactQuery() { return gql` query contactsOnAccount($recordId: ID!, $userId: ID!) { uiapi { query { Contact(where: { AccountId: { eq: $recordId } }) { edges { node { Id Name { value } } } } User(where: { Id: { eq: $userId } }) { edges { node { Id Name { value } } } } } } } `; } get queryData() { return { recordId: this.recordId, userId: this.userId, }; } } ``` Display the records using the `for:each` directive. ```html ``` ## See Also [Query Objects Examples](https://developer.salesforce.com/docs/platform/graphql/query/query-record-examples.md) [Call Apex Methods](https://developer.salesforce.com/docs/platform/lwc/guide/apex.html) [GraphQL API Query Limitations](https://developer.salesforce.com/docs/platform/graphql/query/query-limits.md) # Query Objects | AVAILABLE API VERSION | | ------------------------------------------------ | | API v56.0 and later | | Compound fields available in API v59.0 and later | | Optional fields available in API v65.0 and later | Use queries to load objects, such as Accounts or Contacts. The `query` field under the `uiapi` field is of `RecordQuery` type and gives you access to all object types your Salesforce user has access to. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for querying. ## Object Access Schema The context user’s [object-level and field-level permissions](https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/security_data_access.htm) control access to supported objects and fields on those objects. An object or field is accessible if the user has the correct permissions, and the object is either on the supported object list or is a custom object. Starting in API v68.0, admins can control unauthenticated guest user access to GraphQL from Setup. Unauthenticated guest user access is turned off by default in new orgs. To update guest user access, from Setup, in the Quick Find box, enter **API Access Controls** and select it, and then update guest user access. In orgs with guest user access, GraphQL API honors the same object-level and field-level permissions that guest users have in the org. In orgs with guest user access turned off, guest users can’t access the GraphQL endpoint and receive errors when making requests. For more information about guest user access, see [Securely Share Your Exerience Cloud Sites with Guest Users](https://help.salesforce.com/s/articleView?id=platform.networks_secure_community.htm&type=5). To construct queries that succeed even if the context user doesn’t have access to a field, use [optional fields](#optional-fields). ### RecordQuery Type The `RecordQuery` type has one field for each object type accessible to the user. Only `Account` is shown here for brevity. ``` type RecordQuery { Account( # request the "Account" field to query "Account" objects after: String first: Int orderBy: Account_OrderBy scope: ACCOUNT_SCOPE updateMRU: Boolean upperBound: Int where: Account_Filter ): AccountConnection } ``` The `RecordQuery` type contains these fields. - `after` - Returns the results after the given cursor. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). - `first` - Returns the first n results. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). - `orderBy` - Orders the query using a specified field. See [Order Results](https://developer.salesforce.com/docs/platform/graphql/order.md). - `scope` - An enumeration of the possible [scopes](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_using_scope.htm) that are defined for the object type. Provide this argument to filter the result set to records that have the specified scope. Relay Record Connections don’t have a `scope` argument, as child relationships can’t be filtered by a scope. - `updateMRU` - If set to `true`, updates the `LastViewedDate` field on the records that your query returns. Results for queries with the `updateMRU` field are the same as those without the field. To see the updated last viewed dates, make another query that includes the `LastViewedDate` field. The `updateMRU` field is available in API v66.0 and later. - `upperBound` - Specifies the number of records by which to limit the query. Allows pagination up to `upperBound` number of records. Valid values are 200 to 2000. - `where` - Filters the query with an argument. See [Field Operators](https://developer.salesforce.com/docs/platform/graphql/filter/filter-fields.md). ### RecordConnection Type The `Account` field returns the `AccountConnection` type, which represents a result set of records that ties together the records and page info. `AccountConnection` ties together the elements of the result set (the edges) with information about the relative position of the returned edges to all possible results. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ``` type AccountConnection { edges: [AccountEdge] pageInfo: PageInfo! totalCount: Int! pageResultCount: Int! } ``` The `RecordConnection` type contains these fields. - `edges` - A list of RecordEdge types. - `pageInfo` - Information about the relative location in the result set. - `totalCount` - The number of records that are queried. - `pageResultCount` - The number of records in the page of results. Available in API v60.0 and later. ### RecordEdge Type The `RecordEdge` type, represented by `AccountEdge` here, ties together the record and its cursor. ``` type AccountEdge { cursor: String! node: Account } ``` The `RecordEdge` type contains these fields. - `cursor` - An opaque string used to page directly to this item in the result set. - `node` - The GraphQL object equivalent for the Salesforce object. For supported sObjects that are added before API v60.0, the node type name and sObject type name are the same. To avoid name collisions, supported sObjects that are added in API v60.0 and later have a node type name with a `_Record` suffix. For example, `FeedItem` is added in API v60.0 and its node type name is `FeedItem_Record`. ### PageInfo Type The `PageInfo` type contains relative position information, which shows where in the entire result set the current page is located. The `PageInfo` type is the same for every `Connection` type. ``` type PageInfo { hasNextPage: Boolean hasPreviousPage: Boolean startCursor: String endCursor: String } ``` The `PageInfo` type contains these fields. - `hasNextPage` - Specifies whether the result set have a next page - `hasPreviousPage` - Specifies whether the result set have a previous page - `startCursor` - An opaque string used to page to the first record in the result set - `endCursor` - An opaque string used to page to the last record in the result set **tip:** For more information about pagination, see [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/paginate.md). ## Mapping sObjects to GraphQL Objects Each supported sObject type the user has access to maps to a corresponding GraphQL object type. For supported sObjects that are added before API v60.0, the sObject type and the corresponding GraphQL object type have the same name. That is, `Account` maps to a GraphQL object type named `Account`, or `MyCustomObject__c` maps to `MyCustomObject__c`. To avoid name collisions, supported sObjects that are added in API v60.0 and later map to a GraphQL object type name with a `_Record` suffix. For example, `FeedItem` is added in API v60.0 and maps to a GraphQL object type named `FeedItem_Record`. All object types implement the `Record` interface, which has a standard set of fields that are useful for most applications. **tip:** For a complete list of fields on each object type, we recommend that you review the schema documentation using the [Altair GraphQL client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md). ``` interface Record { Id: ID! ApiName: String! WeakEtag: Long! DisplayValue: String LastModifiedById: IDValue LastModifiedDate: DateTimeValue SystemModStamp: DateTimeValue RecordTypeId: IDValue } ``` Standard fields on the `Record` interface includes: - `Id` - The record ID. - `ApiName` - The API name of the Salesforce object. - `WeakEtag` - If the weak etag is non-zero, two records that have the same `ApiName`, `Id` and `WeakEtag` is of the same version. This means they represent the same record at that point in time. If two records have the same `ApiName` and `Id` but different `WeakEtag`, the record with the greater `WeakEtag` is the more recent version of the record. - `DisplayValue` - The displayable value for a field. In API v60.0 and later, `DisplayValue` is also supported for polymorphic fields. Querying `DisplayValue` for multiple polymorphic fields requires additional processing time. - `LastModifiedById` - The ID of the user who last updated this record. - `LastModifiedDate` - The date and time when a user last modified this record. Date and time information is in ISO 8601 format. - `SystemModStamp` - The date and time when a user or an automated process (such as a trigger) last modified this record. Date and time information is in ISO 8601 format. - `RecordTypeId` - The record type ID for this record. An object can map to three categories of fields: - Salesforce object fields - [Parent Relationships](https://developer.salesforce.com/docs/platform/graphql/filter/filter-parent.md) - [Child Relationships](https://developer.salesforce.com/docs/platform/graphql/filter/filter-parent.md) ### Fields Fields on the object are either mapped to a [GraphQL Scalar](https://graphql.org/learn/schema/#scalar-types) or a "Field Value" type. The GraphQL Schema contains at least one scalar for each field type on Salesforce objects. Mapping a field into the schema uses these scalars. ``` scalar Base64; scalar Boolean; scalar Currency; scalar Date; scalar DateTime; scalar Double; scalar Email; scalar EncryptedString; scalar ID; scalar IdorRef; scalar Int; scalar JSON; scalar Latitude; scalar Long; scalar LongTextArea; scalar Longitude; scalar MultiPicklist; scalar Percent; scalar PhoneNumber; scalar Picklist; scalar RichTextArea; scalar String; scalar TextArea; scalar Time; scalar Url; ``` **note:** This list doesn’t include every scalar type in the schema. Only the scalars that represent possible types for Salesforce object fields are listed. Field value types have the naming pattern `Value`, for example, `PicklistValue`. All field value types have a field named `value`, of the corresponding `scalar` type. That is, `PicklistValue` has a field value of type `Picklist`. The field value type has a field called `label` if the field type supports the `toLabel()` SOQL function. The field value type has a field called `format` if the field type supports the `format()` SOQL function. In addition, the field value type has a field called `displayValue`, backed by whichever of the two `toLabel()` or `format()` function calls the field type supports. **note:** Currently, no field type supports both `format()` and `toLabel()`, and so there’s no ambiguity on which value is used for the `displayValue` field. Here’s an example of a few field value types: ``` type PicklistValue { value: Picklist # the raw value of the field on the object label: String # execute a SOQL toLabel() call displayValue: String # backed by the toLabel() call } type CurrencyValue { value: Currency # the raw value of the field on the object format: String # execute a SOQL format() call displayValue: String # backed by the format() call } ``` When mapping a Salesforce object field into the schema, the field maps to either a field value type or the scalar directly. This is the process for the field type-mapping operation. - If the field name is Id, the scalar ID is used. - If the field type is Double, the field participates in a compound field of type Address or Geolocation and the field name is or ends with Latitude then the `LatitudeValue` object type is used. - If the field type is Double, the field participates in a compound field of type Address or Geolocation and the field name is or ends with Longitude then the `LongitudeValue` object type is used. - If the field type is TextArea, and the fields extra type info has the rich text flag, then the `RichTextAreaValue` object type is used. - If the field type is TextArea, and the fields length value is greater than 255, the `LongTextAreaValue` object type is used. Otherwise, the field has the corresponding value type for the field type. For example, fields of type Picklist use the `PicklistValue` type, and fields of type Currency use the `CurrencyValue` type. ## Optional Fields Use the `@optional` field directive for successful query execution even if some fields are inaccessible to the context user. Mark fields, including parent and child relationship fields, as optional anywhere in your query. If the context user has access to the optional field, the query returns all the data. If the context user doesn’t have access to the optional field, the query succeeds but doesn’t return the optional field or any subfields. Arguments can’t take the optional directive, but fields that take arguments can. If an optional field takes an argument that is set to a variable, the context user must also have access to the variable type for the query to succeed. ## Compound Fields Compound fields correspond to the `ObjectName__FieldName__CompoundField` GraphQL type. For example, the `BillingAddress` field on the Account object, or the `Address` field on the Lead object are compound fields. They correspond to the `Account_BillingAddress_CompoundField` type and `Lead_Address_CompoundField` type respectively. Here’s an example of the `Account_BillingAddress_CompoundField` type: ``` type Account { BillingAddress: BillingAddress # `Account_BillingAddress_CompoundField type Location__c: Location__c # Account_Location__c_CompoundField type } ``` An address compound field comprises several constituent fields, like `BillingCity` and `BillingCountry`. ``` type BillingAddress { BillingCity: StringValue BillingCountry: StringValue BillingGeocodeAccuracy: PicklistValue BillingLatitude: LatitudeValue BillingLongitude: LongitudeValue BillingPostalCode: StringValue BillingState: StringValue BillingStreet TextAreaValue } ``` A [geolocation compound field](https://developer.salesforce.com/docs/platform/graphql/filter/filter-location.md) includes the `FieldName__Latitude__s` and `FieldName__Longitude__s` fields. ``` type Account_Location__c_CompoundField { Location__Latitude__s: DoubleValue Location__Longitude__s DoubleValue } ``` Compound fields follow these restrictions. - Include a compound field with its constituent fields in a query. - Use the constituent fields when ordering by or filtering using a `where` argument. - Use the constituent fields when working with aggregate queries. This example queries accounts with its billing address fields. ``` query AccountsWithBillingAddress{ uiapi { query { Account { edges { node { Name { value } BillingAddress { BillingCity { value displayValue label } BillingCountry { value displayValue label } } } } } } } } ``` **note:** Compound fields follow the limitations described at [Object Reference for the Salesforce Platform](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/compound_fields.htm). ## Parent Relationships Each parent relationship on an object has a corresponding field on the GraphQL object, if one of the sObjects that participates in the relationship also participates in the schema. The field name on the GraphQL object matches the relationship name. For example, both `Contact` and `Account` participate in the schema, so an Account field (relationship name) of type `Account` (sObject name) is present on type `Contact`. If the object pointed at doesn’t appear in the schema, then no field for that relationship is added to the object type. For example, a relationship points at an object that’s not supported by UI API, so it isn’t mapped into the schema. As a result, the relationship isn’t mapped onto the object. If the relationship is non-polymorphic, then the field has a type of that sObject. ``` type Account { LastModifiedBy: User # lastModifiedBy is non-polymorphic LastModifiedById: IDValue # The ID field of the parent relationship is included as well } # the 'LastModifiedBy' field on 'Account' points at the 'User' object type User { ... } ``` If the relationship is polymorphic, then the field’s name is still the relationship name, but the field type is a Union. The unions type name follows the pattern `_`. For example, the `SocialPost` object has a polymorphic relationship named `Who`, and so the union type name is `SocialPost_Who`. Each concrete type in the schema that participates in the polymorphic relationship becomes a possible type of the union. If no object types that participate in the polymorphic relationship are mappable into the schema, then the field for the relationship isn’t added to the type. ``` type SocialPost { Who: SocialPost_Who # the polymorphic relationship becomes a field that has a Union type WhoId: IDValue # The ID field of the parent relationship is included } union SocialPost_Who = Account | Contact | Lead # the union has one possible type for each concrete type that participates in the polymorphic relationship ``` ## Child Relationships Each child relationship that points at an sObject type that participates in the schema is added as a field with a [Relay Record Connection](https://relay.dev/graphql/connections.htm) type to the GraphQL object. The name of the field matches the name of the child relationship. For example, `Account` has a field named `Contacts` of type `ContactConnection`. ``` type Account { Contacts( # the object will have a field for each child relationship first: Int after: String orderBy: Contact_OrderBy where: Contact_Filter ): ContactConnection # the field type will be a Relay Connection for the child object type } ``` Construct the arguments `where` and `orderBy` using the rules outlined in [Filtering](https://developer.salesforce.com/docs/platform/graphql/filter/filter.md) and [Ordering](https://developer.salesforce.com/docs/platform/graphql/order.md), respectively. Scopes can’t be applied to querying child relationships, and as a result the field doesn’t have a `scope` argument. ## See Also [Relationship Filters](https://developer.salesforce.com/docs/platform/graphql/filter/filter-parent.md) [Polymorphic Relationship Filters](https://developer.salesforce.com/docs/platform/graphql/filter/filter-polymorphic.md) # Query Objects Examples | AVAILABLE API VERSION | | ------------------------------------------------ | | API v56.0 and later | | Optional fields available in API v65.0 and later | Use queries to load record data from Salesforce objects. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for querying. ## Query an Object To query an object, request a field with the same name under [the `RecordQuery` type](https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.md). This example queries accounts with their IDs and names. ``` query accounts { uiapi { query { Account { edges { node { Id Name { value } } } } } } } ``` The query returns only objects and fields that the user has access to. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0015f000007wCAWAA2", "Name": { "value": "Enfield Tennis Academy" } } }, { "node": { "Id": "0015f000007vRRVAA2", "Name": { "value": "Ennet House" } } } ] } } } } } ``` ### Query an Object With Optional fields This example queries users with their IDs and employee numbers. The employee number field is marked as optional. ``` query optional { uiapi { query { User { edges { node { Id EmployeeNumber @optional { value } } } } } } } ``` If the user executing the query has access to the employee number field, the query returns all the data as expected. If the user executing the query doesn’t have access to the employee number field, the query succeeds and returns the `Id` field but not the `EmployeeNumber` field or any subfields of `EmployeeNumber`. ## Query Multiple Objects You can query multiple objects in one call. ``` uiapi { query { Account { ... } Case { ... } Contact { ... } Opportunity { ... } } } ``` Send your query in a separate call if the query depends on a field or value from an earlier query. Alternatively, work with semi-joins or auto-joins to query parent and child relationships. This example queries accounts and cases. The second query includes a semi-join using the reference field `AccountId`, which filters cases whose account parent records match the given Name pattern and Industry field value. ``` query AccountsAndCases { uiapi { query { Account { edges { node { Name { value } Industry { value } } } } Case(where: { AccountId: { inq: { Account: { and: [ { Name: { like: "United%" } }, { Industry: { eq: "Energy" } } ]}, ApiName:"Id" } } }) { edges { node { AccountId { value } Priority { value } Subject { value } } } } } } } ``` The query returns the first 10 results of each query. ``` { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Name": { "value": "GenePoint" }, "Industry": { "value": "Biotechnology" } } }, { "node": { "Name": { "value": "United Oil & Gas, UK" }, "Industry": { "value": "Energy" } } }, { "node": { "Name": { "value": "Edge Communications" }, "Industry": { "value": "Electronics" } } }, { "node": { "Name": { "value": "United Oil & Gas Corp" }, "Industry": { "value": "Energy" } } } // 6 more results ] }, "Case": { "edges": [ { "node": { "AccountId": { "value": "0011a000005slmlAAA" }, "Priority": { "value": "High" }, "Subject": { "value": "Performance inadequate for second consecutive week" } } }, { "node": { "AccountId": { "value": "0011a000005slmlAAA" }, "Priority": { "value": "High" }, "Subject": { "value": "Seeking guidance on electrical wiring installation for GC5060" } } }, { "node": { "AccountId": { "value": "0011a000005slmcAAA" }, "Priority": { "value": "Medium" }, "Subject": { "value": "Mechanical maintenance guidelines for generator misleading" } } }, { "node": { "AccountId": { "value": "0011a000005slmlAAA" }, "Priority": { "value": "High" }, "Subject": { "value": "Design issue with mechanical rotor" } } } // 6 more results ] } } } }, "errors": [] } ``` The first query returns accounts with the Name and Industry fields, similar to this SOQL statement. ``` SELECT Name, Industry FROM Account ``` The second query is similar to this SOQL statement. ``` SELECT AccountId, Priority, Subject FROM Case WHERE AccountId IN ( SELECT Id FROM Account WHERE Name LIKE 'United%' and Industry = 'Energy' ) ``` **note:** Multiple query execution where a query requires field or value dependencies on another query within the same execution isn’t supported. # Query Records with GraphQL The GraphQL API schema contains a subset of types that allow you to query records. With the `RecordQuery` type, each Salesforce object corresponds to a `RecordQuery` field of the same name, such as `Account` or `Case`. You can [filter](https://developer.salesforce.com/docs/platform/graphql/filter/filter.md) records with the `where` argument, [order](https://developer.salesforce.com/docs/platform/graphql/order.md) results with the `orderBy` argument, and [paginate](https://developer.salesforce.com/docs/platform/graphql/paginate.md) through the response using the Relay Connection specification. # Query Your Data The `lightning/graphql` module has two functions, `gql` and `graphql`, for executing GraphQL queries. - `gql`—A JavaScript tagged template literal used to indicate the presence and location of GraphQL queries within your LWC component. All GraphQL queries passed to `graphql` wire adapter must be wrapped with the `gql` tagged template literal. Salesforce uses `gql` to understand and apply special processing to your GraphQL queries at different stages of the component lifecycle. - `graphql`—The identifier of the GraphQL wire adapter. The graphql wire adapter emits the results of executing a GraphQL query as a stream of values in the private function defined by the developer. Values emitted by `graphql` can contain `data` and `errors` properties. These properties follow the [GraphQL Response specification](https://graphql.org/learn/serving-over-http/#response). **note:** The `lightning/graphql` module supersedes the `lightning/uiGraphQLApi` module. We recommend that you use `lightning/graphql` if possible. Newer features, such as optional fields and dynamic query construction, require `lightning/graphql`. Use `lightning/uiGraphQLApi` only if you’re supporting Mobile Offline use cases. ## Send a GraphQL Query from LWC By default, GraphQL returns the first 10 results of a query. Here’s how you can fetch the first 50 account names. ```javascript //simpleGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class SimpleGQL extends LightningElement { results; errors; @wire(graphql, { query: gql` query AccountWithName { uiapi { query { Account(first: 50) { edges { node { Id Name { value } } } } } } } `, }) graphqlQueryResult({ data, errors }) { if (data) { this.results = data.uiapi.query.Account.edges.map((edge) => edge.node); } this.errors = errors; } } ``` The wire adapter returns a JSON response that looks like this. ```json { "data": { "uiapi": { "query": { "Account": { "edges": [ { "node": { "Id": "0011a00000cR4wuAAC", "Name": { "value": "Edge Communications" } } }, { "node": { "Id": "0011a00000cQvEwAAK", "Name": { "value": "United Oil" } } }, { "node": { "Id": "0011a00000cRQ1wAAG", "Name": { "value": "Apple" } } }, # more data here ] } } } }, "errors": [] } ``` The data returned from the GraphQL wire adapter has the same structure as the GraphQL query. While this structure works fine for programmatic use, it can be difficult to consume inside your component’s template. This line of code in the example removes extra layers in the response data to make it easier to consume in the template. ```js this.results = data.uiapi.query.Account.edges.map((edge) => edge.node); ``` Your component then renders the results using the `for:each` directive with the `Id` as the key. ## Display Your Data Display the query results in your component. This example uses the `lightning-card` base component to group the returned accounts with a title you retrieve with the `Name { value }` node. ```html ``` You can make your component [reactive to data changes](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-reactive.md), such as adding a dropdown that enables different query selection. ## See Also [GraphQL Wire Adapter Best Practices](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-best.md) [_Lightning Web Components Developer Guide_: lightning/graphql Wire Adapter (v2)](https://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-graphql-module.html) [_Lightning Web Components Developer Guide_: lightning/uiGraphQLApi (v1)](https://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-graphql-api.html) # Quick Starts: GraphQL API Each of these quick starts connects a REST client to Salesforce so you can make GraphQL calls. - [Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-graphql.md) - [Salesforce Postman Collection](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-postman.md) **tip:** After you use a quick start to set up a client, use the [Query Records with GraphQL](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-records.md) guide to find sample queries for many use cases. # Schema Conventions Within the Salesforce GraphQL schema, there are several conventions that the types adopt to make sure that the schema performs as expected for your record data. Fundamentally, GraphQL API defines types that describe the set of data you can query from the UI API family. It also provides pagination, error querying, and versioning support. ## Operation Types Several operation types are available with GraphQL API. ``` schema { query: Query mutation: Mutation } ``` - `Query`- Provides an entry point for read operations. - `Mutation`- Provides an entry point for create, update, and delete operations. `Mutation` is available as a Beta Service in API v59.0–65.0 and is generally available in API v66.0 and later. ## API Families Each API family has a top-level field on the `Query` operation type, which serves as the entry point to that API family. The `Query` operation type has a `uiapi` field, a `managed_content` field, and a `rateLimit` field. The `rateLimit` field is deprecated. ``` type Query { uiapi: UIAPI! managed_content: ManagedContent__ManagedContent! rateLimit: RateLimit } ``` The [`Mutation` operation type](https://developer.salesforce.com/docs/platform/graphql/guide/mutations/mutations-intro.md) has a `uiapi` field with a `UIAPIMutationsInput` argument. The `UIAPIMutationsInput` has a boolean argument `allOrNone` that has a default value of `true`. When `true`, if one or more operations fails, all operations are rolled back and not executed. ``` type Mutation { uiapi(input: UIAPIMutationsInput): UIAPIMutations! } input UIAPIMutationsInput { allOrNone: Boolean } ``` ## UI API Family Access the User Interface API (UI API) family via the `uiapi` field of type `UIAPI`. ``` ``` **tip:** UI API enables developers to build user interfaces so that users can work with records, list views, actions, favorites, and so on. It’s the API that powers Lightning Experience, Salesforce for Android, iOS, and mobile web. See the [UI API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/). ### UIAPI Type The `UIAPI` type includes these fields. ``` type UIAPI { query: RecordQuery! aggregate: RecordQueryAggregate! objectInfos(apiNames, locale, objectInfoInputs): [ObjectInfo] relatedListByName(parentApiName, relatedListName): RelatedListInfo currentUser: RecordRepresentation recordLayouts(objectApiName: String!, recordTypeIds: [ID!], layoutConfigs: [LayoutConfig!], layoutType = "FULL": LayoutType, formFactor = "LARGE": FormFactor, mode = "VIEW": LayoutMode, first: Int, after: String): LayoutConnection recordCreateDefaults(objectApiName: String!, recordTypeIds: [ID!], formFactor = "LARGE": FormFactor, mode = "LAYOUT": CreateDefaultsMode, configs: [CreateDefaultsConfig!], optionalFields: [String!], first: Int, after: String): CreateDefaultsConnection lookupValues(objectApiName: String!, fieldApiName: String!, q: String, searchType: LookupSearchType, targetApiName: String, sourceRecord: RecordSnapshotInput): [LookupValues!] platform: Platform! } ``` Use the `UIAPI` type to: - [Query records](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-record-objects.md) - [Aggregate queries](https://developer.salesforce.com/docs/platform/graphql/guide/aggregate/aggregate.md) - [Get object metadata](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-objectinfo.md) - [Get related list metadata](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-related-list-info.md) - [Get the current user’s User record](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-current-user-record.md) - [Get object layouts](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-record-layouts.md) - [Get record create defaults](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-record-create-defaults.md) - [Get lookup values](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-lookup-values.md) - [Use platform capabilities](https://developer.salesforce.com/docs/platform/graphql/guide/query/platform.md) ## Managed Content Family Use the Managed Content family to search and retrieve Salesforce CMS content. Access the Managed Content API family via the `managed_content` field of type `ManagedContent__ManagedContent`. The Managed Content API family is available in v67.0 and later. See [Managed Content GraphQL API Family](https://developer.salesforce.com/docs/platform/cms/guide/managed-content-intro.html) in the _CMS Developer Guide_ for use cases and examples. ## Pagination The GraphQL server adopts the [Relay Connection Specification](https://relay.dev/graphql/connections.htm) for pagination. [Pagination](https://graphql.org/learn/pagination/) is a common way for a GraphQL server to structure types when dealing with a result set that requires iteration. See [Paginate Results](https://developer.salesforce.com/docs/platform/graphql/guide/paginate.md). ## Query Errors When reading data via the `Query` type, if an error occurs accessing a field, then the [Errors](https://developer.salesforce.com/docs/platform/graphql/guide/requests-and-responses.md#response) list of the response includes the error. The error contains a path that associates the error with the originally requested field. See [Status Codes and Errors Responses](https://developer.salesforce.com/docs/platform/graphql/guide/query/query-status.md). ## Versioning While most GraphQL servers don’t include a version in the URL to the GraphQL endpoint, the Salesforce GraphQL schema does. Various types of objects, such as sObjects, depend on the version for their construction. These objects require some version of the API to bind the request to. All new types and fields added to the Salesforce platform have an associated version. The API version dictates what capabilities the application server has when processing the request. For this reason, the GraphQL endpoint includes a version, which is the version of the API used during the request. # Schema Structure Send your query via a POST HTTP request to the [`graphql` endpoint](/docs/platform/graphql/references/graphql?meta=Send%2BQuery): ``` https://{MyDomainName}.my.salesforce.com/services/data/v{version}/graphql ``` Replace these values: - `MyDomainName`: A custom subdomain specific to a Salesforce org. For example, `companyname` creates the URL `https://companyname.my.salesforce.com`. - `version`: A Salesforce API version in the format XX.X. For example, 57.0. Within the Salesforce GraphQL schema, there are [a number of conventions](https://developer.salesforce.com/docs/platform/graphql/guide/schema-conventions.md) that the types adopt to ensure the schema performs as expected for your record data. For example, while most GraphQL servers don't include a version in the url to the GraphQL endpoint, the Salesforce GraphQL schema does. **tip:** Explore and learn GraphQL API using [Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-graphql.md) or using our [Postman Collection](https://developer.salesforce.com/docs/platform/graphql/guide/get-started-postman.md). # Semi-Join and Anti-Join Filters | AVAILABLE API VERSION | | --------------------- | | API v56.0 and later | A semi-join is a subquery on another object in an `in` clause that restricts the records returned by the primary query. Conversely, an anti-join is a subquery on another object in a `nin` clause that restricts the records returned. The subquery can filter by ID or a [reference field](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/field_types.htm). - If you filter by an ID field, you can create parent-to-child semi-joins and anti-join, such as Account to Contact or Account to Opportunity. - If you filter by a reference field, you can create child-to-child semi- or anti-joins, such as Contact to Opportunity. You can also create child-to-parent semi- or anti-joins, such as Opportunity to Account. ## Semi-Join Filter Semi-join filters help you narrow your query, such as returning only accounts whose opportunities match a specific criterion. ### Semi-Join with ID Field You can include a semi-join in a `where` argument. With the `inq` filter type for the ID field, you can restrict the records returned by the primary query. This example returns accounts if an associated opportunity is closed won. ``` query { uiapi { query { Account (where: { Id: { inq: { Opportunity: { StageName: { eq: "Closed Won" } }, ApiName:"AccountId" } } }) { edges { node { Id Name { value } } } } } } } ``` This example is a parent-to-child semi-join from Account to Opportunity, which uses Id on the Account and AccountId on the opportunity. The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Opportunity WHERE StageName = 'Closed Won' ) ``` You can also filter the subquery with multiple `where` conditions like this. ``` query { uiapi { query { Account(where: { Id: { inq: { Opportunity: { and: [ { StageName: { eq: "Prospecting" } }, { Probability: { eq: 20.0 } } ]}, ApiName:"AccountId" } } }) { edges { node { Id Name { value displayValue } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Opportunity WHERE StageName = 'Prospecting' and Probability = 20.0 ) ``` To restrict the records to show only those records with associated child records, use empty curly brackets `{}` or filter the Id on the subquery with `ne: null`. ``` query { uiapi { query { Account(where: { and: [{ BillingCountry : { eq: "USA" }}, { Id: { inq: { Contact: { AccountId: { ne: null } }, ApiName:"AccountId" } } }] }) { edges { node { Id Name { value displayValue } BillingCountry { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name, BillingCountry FROM Account WHERE BillingCountry='USA' AND Id IN ( SELECT AccountId FROM Contact ) ``` ### Semi-Join with RecordTypeId Field To filter records based on a record type, pass the `RecordTypeId` field to the `inq` filter. This example returns cases that match a specified `DeveloperName` value on the `RecordType` field. ``` query accounts { uiapi { query { Case (where: { RecordTypeId: { inq: { RecordType: { DeveloperName: { eq: "My_Developer_Name" }}, ApiName:"Id" } } }) { edges { node { Id Subject { value } RecordType { Name { value } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Subject, RecordType.Name FROM Case WHERE RecordTypeId IN ( SELECT Id FROM RecordType WHERE DeveloperName = 'My_Developer_Name' ) ``` ### Semi-Join with a Reference Field A reference field contains an Id value that points to a record on another object. The name of a reference field ends with `Id`, such as `AccountId` or `CaseId`. For example, the `AccountId` field on a contact identifies a unique account record. Some objects have `WhoId` or `WhatId` reference fields, which can point to one of several other objects. The `WhoId` field can point to a contact or lead. See [Reference Field Type](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/field_types.htm). This example returns contact requests for all contacts whose first name starts with "R". ``` query { uiapi { query { ContactRequest (where: { WhoId: { inq: { Contact: { FirstName: { like: "R%" } }, ApiName:"Id" } } }) { edges { node { Id Who { ... on Contact { Name { value } } } } } } } } } ``` The `WhoId` field in the semi-join is a [polymorphic reference field](https://developer.salesforce.com/docs/platform/graphql/guide/filter-polymorphic.md) because it can point to a contact or a lead. In this case, we restrict the subquery to contact records. ## Anti-Join Filter Anti-join filters help you narrow your query, such as returning only accounts that don’t match a certain criteria. ### Anti-Join with ID Field You can include an anti-join in a `where` argument. With the `ninq` filter type for the ID field, you can restrict the records returned by the primary query. This example returns accounts that don’t have any open opportunities. ``` query { uiapi { query { Account (where: { Id: { ninq: { Opportunity: { IsClosed: { eq: false } }, ApiName:"AccountId" } } }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id FROM Account WHERE Id NOT IN ( SELECT AccountId FROM Opportunity WHERE IsClosed = false ) ``` You can also query accounts with associated opportunities that aren’t in prospecting stage. ``` query { uiapi { query { Account(where: { Id: { ninq: { Opportunity: { StageName: { eq: "Prospecting" }} , ApiName:"AccountId" } } }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id NOT IN ( SELECT AccountId FROM Opportunity WHERE StageName = 'Prospecting' ) ``` ### Anti-Join with a Reference Field This example returns opportunities for all contacts whose source isn’t Web. It shows a child-to-child anti-join from Opportunity to Contact. ``` query { uiapi { query { Opportunity (where: { AccountId: { ninq: { Contact: { LeadSource: { eq: "Web" } }, ApiName:"AccountId" } } }) { edges { node { Id Name { value } } } } } } } ``` ## Multiple Semi-Joins or Anti-Joins You can combine semi-join or anti-join clauses in a query. This example returns accounts that have open opportunities if the last name of the associated account starts with "G". ``` query { uiapi { query { Account (where: { and: [{ Id: { inq: { Contact: { LastName: { like: "G%" } }, ApiName:"AccountId" }, }, Id: { inq: { Opportunity : { IsClosed : { eq : false } }, ApiName:"AccountId" } } }] }) { edges { node { Id Name { value } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, Name FROM Account WHERE Id IN ( SELECT AccountId FROM Contact WHERE LastName LIKE 'G%' ) AND Id IN ( SELECT AccountId FROM Opportunity WHERE isClosed = false ) ``` ## Evaluate Relationship Queries with Semi-Joins or Anti-Joins You can create a semi-join or anti-join that evaluates a relationship query. This type of query returns object of one type based on criteria that applies to objects of another type. This example returns accounts and their associated contacts if the contact lead source is Web. ``` query { uiapi { query { Account (where: { Id: { inq: { Contact: { LeadSource: { eq: "Web" } }, ApiName:"AccountId" }, }, }) { edges { node { Id Contacts { edges { node { Id } } } } } } } } } ``` The previous query is similar to this SOQL statement. ``` SELECT Id, (SELECT Id from Contacts) FROM Account WHERE Id IN ( SELECT AccountId FROM Contact WHERE LeadSource = 'Web' ) ``` ## See Also [SOQL and SOSL Reference: Semi-Joins with IN and Anti-Joins with NOT IN](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_comparisonoperators.htm) # Send Mutation Requests | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally Available v66.0 and later | A mutation request modifies your record data by either creating, updating, or deleting the data. When you send a [record create request](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-create.md), you can also request for fields from the newly created record in one request. However, you can’t query fields with record [update](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-update.md) and [delete](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-delete.md) requests. Your request can fail if you have multiple fields with the same name, which results in naming conflicts. To avoid conflicts, use [aliases](https://graphql.org/learn/queries/#aliases) to rename the result of a field. ``` first: AccountCreate(input: { ... }) second: AccountCreate(input: { ... }) ``` ## All or None Requests The `uiapi` field of `UIAPIMutations` type has an input field for an `allOrNone` boolean argument. The default is `true`. ``` mutation OperationName { uiapi(input: { allOrNone: false }) { first: AccountCreate(input: { ... }) second: AccountCreate(input: { ... }) } } ``` When `allOrNone` is `true`, all operations are rolled back if any operation fails, or all operations are executed within a transaction. When `allOrNone` is set to `false`, only operations that fail are rolled back along with any operations that depend on those failed operations, allowing other successful operations to execute. ### Example: Successful Multiple Account Creation If you set `allOrNone` to `false` when creating multiple accounts, a failed operation doesn’t prevent the other operations from successfully executing. In this example, the second operation successfully executes while the first one fails. ``` mutation MutipleAccounts{ uiapi(input: { allOrNone: false }) { AccountCreate(input: { Account: { NumberOfEmployees: 100 } }) { Record { Id Name { value } } } second: AccountCreate(input: { Account: { Name: "Amazing Account" } }){ Record { Id Name { value } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "AccountCreate": null, "second": { "Record": { "Id": "001RM000005eoXGYAY", "Name": { "value": "Amazing Account" } } } } }, "errors": [ { "extensions": { "ErrorType": "DataFetchingException" }, "locations": [ { "column": 5, "line": 3 } ], "message": "Required fields are missing: [Name]", "paths": ["uiapi", "AccountCreate"] } ] } ``` ### Example: Unsuccessful Multiple Account Creation If `allOrNone` is `true` when you’re creating multiple accounts, all account creation fails if any single operation fails. In this example, the first account create operation fails because `Name` if a required field on accounts, so the other operation also fails. ``` mutation MutipleAccounts{ uiapi(input: { allOrNone: true }) { AccountCreate(input: { Account: { NumberOfEmployees: 100 } }) { Record { Id Name { value } } } second: AccountCreate(input: { Account: { Name: "Amazing Account" } }){ Record { Id Name { value } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "AccountCreate": null, "second": null } }, "errors": [ { "extensions": { "ErrorType": "DataFetchingException" }, "locations": [ { "column": 5, "line": 3 } ], "message": "Required fields are missing: [Name]", "paths": ["uiapi", "AccountCreate"] }, { "extensions": { "ErrorType": "DataFetchingException" }, "locations": [ { "column": 5, "line": 13 } ], "message": "The transaction was rolled back since another operation in the same transaction failed.", "paths": ["uiapi", "second"] } ] } ``` ## Order of Operations The order of operations depends on each operation’s dependencies. To enable an operation to use a field from another operation in the same execution, use the `@{alias}` syntax. See [Mutation Field References](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-references.md). ``` FieldName: "@{aliasName}" ``` ### Example: Multiple Account Creation and Updates You can create multiple accounts and update them in a single request. The update operation requires the `Id` field value from the create operation. In this example, the account create operation with the `second` alias is successful, followed by a successful update on the same account. The first account create fails because a required field is missing. ``` mutation MutipleCreateWithUpdate{ uiapi(input: { allOrNone: false }) { AccountCreate(input: { Account: { NumberOfEmployees: 100 } }) { Record { Id Name { value } } } second: AccountCreate(input: { Account: { Name: "Amazing Account" } }){ Record { Id Name { value } } } AccountUpdate(input: { Account: { Name: "Awesome Account" } Id: "@{second}" }) { Record { Id Name { value } } } } } ``` The response looks like this. ``` { "data": { "uiapi": { "AccountCreate": null, "second": { "Record": { "Id": "001RM000005eoYEYAY", "Name": { "value": "Amazing Account" } } }, "AccountUpdate": { "Record": { "Id": "001RM000005eoYEYAY", "Name": { "value": "Amazing Account" } } } } }, "errors": [ { "extensions": { "ErrorType": "DataFetchingException" }, "locations": [ { "column": 5, "line": 3 } ], "message": "Required fields are missing: [Name]", "paths": ["uiapi", "AccountCreate"] } ] } ``` # Status Codes and Error Responses GraphQL API queries return HTTP status codes or error responses that describe the query status. ## 200 OK Success with HTTP POST request. The response contains the query result. GraphQL API can also return a `200 OK` in cases where the request contains an error, such as an invalid object name or field. The [GraphQLErrorRepresentation](/docs/platform/graphql/references/graphql?meta=type%3AGraphQLErrorRepresentation) type represents the error. ``` { "data": {}, "errors": [ { "extensions": { "ErrorType": "ValidationError" }, "locations": [ { "column": 7, "line": 4 } ], "message": "Validation error of type FieldUndefined: Field 'Accounts' in type 'RecordQuery' is undefined @ 'uiapi/query/Accounts'", "paths": [] } ] } ``` A `200 OK` status code is returned even if the query doesn’t return any matching items or if you pass in an invalid record ID. ``` { "data": { "uiapi": { "query": { "Case": { "edges": [] } } } }, "errors": [] } ``` The `ErrorType` field returns one of these errors. - `InvalidSyntax` - The request contains a syntax error. - `ValidationError` - The request isn’t valid against the GraphQL API schema. For example, this error can occur if an object or field name included in the query doesn’t exist. - `DataFetchingException` - An exception occurred while fetching data, for example, invalid credentials. - `OperationNotSupported` - Although the request is valid against the GraphQL API schema and successfully parsed, the server can’t resolve which operation to run. - `ExecutionAborted` - The request didn’t complete successfully. ## 4XX Status Codes The 4XX status codes signify issues with your network, connection to a Salesforce org, or access to GraphQL API. - 401 Unauthorized - : The session ID or OAuth token has expired or is invalid. For more information about the error, review the `message` and `errorCode` descriptions in the response body. - 403 Forbidden - : Unauthenticated guest users don’t have access to GraphQL API in the org. Starting in API v67.0, admins can turn on guest user access from Setup. In the Quick Find box, enter and select **API Access Controls**, and then turn on guest user access. - 404 Not Found - : The specified endpoint wasn’t found. Only the [`graphql` endpoint](/docs/platform/graphql/references/graphql?meta=Send%2BQuery) is supported. **note:** GraphQL API usually returns a `200 OK` status code even if a record isn’t found or is deleted. Contrastingly, UI API returns a 404 error if a resource isn’t found or is deleted. See the previous [`200 OK`](#200-ok) section for details. ## 5XX Status Codes 5XX status codes usually mean there’s an internal Salesforce error. To resolve this issue, try your request again or contact Salesforce Customer Support if the issue persists. - 500 Internal Server Error - : An error has occurred within Lightning Platform, so the request didn’t complete. - 503 Service Unavailable - : Too many requests in an hour or the server is down for maintenance. See [Rate Limiting](https://developer.salesforce.com/docs/platform/graphql/rate-limit.md). # Update a Record | AVAILABLE API VERSION | | ----------------------------------- | | Beta v59.0–65.0 | | Generally Available v66.0 and later | Use `mutations` to update a record. Within `mutations`, the [`RecordUpdate` field](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-schema.md) enables you to update all object types your Salesforce user has access to. Only [objects supported by UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_get_started_supported_objects.htm) are available for mutations. ## Example Update Request To update a record, use `RecordUpdate` with the `Id` and field values for the record you want to update. **note:** The `RecordUpdatePayload` type includes the `Record` field in API v66.0 and later. In API v59–65, the `RecordUpdatePayload` type includes a `success` field returning `true` or `false` to denote if the update is successful. A response is returned when record creation is successful. To define the fields you want the response body to return, use the `Record` field. You can return the `Id` and selected fields from your record update. ``` mutation ContactUpdateExample{ uiapi { ContactUpdate(input: { Contact: { FirstName: "Sam" LastName: "Smith" } Id: "003RM000008AAAAAA4" }) { Record { Id FirstName { value } LastName { value } } } } } ``` ## Example Response on Successful Update The response body returns the fields you request under `Record`. ``` { "data": { "uiapi": { "ContactUpdate": { "Record": { "Id": "003RM000008AAAAAA4", "FirstName": { "value": "Sam" }, "LastName": { "value": "Smith" } } } } }, "errors": [] } ``` ## Record Update Guidelines Consider these guidelines for updating a record. - For compound fields, use the constituent fields. For example use `FirstName` and `LastName` instead of `Name`. - For numerical field values, such as integers or currency, use the raw values. For example, use `80000` instead of `80,000` and don’t include currency symbols. - Sending an update request with field values that don’t match the supported format returns a [`ValidationError`](https://developer.salesforce.com/docs/platform/graphql/query/query-status.md). Use the appropriate format for the field, such as [`YYYY-MM-DD` for date fields](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm). - Sending an update request with an incorrect `Id` value returns a `DataFetchingException` error. ## See Also [Send Mutation Requests](https://developer.salesforce.com/docs/platform/graphql/guide/mutations-use.md) # Update Cached Query Results The GraphQL wire adapter automatically caches your query results to improve the loading performance of subsequent queries. You can trigger a refresh of the query results and update the cache by calling the refresh method on the emitted data from the GraphQL wire adapter. If you use a wire function, you can assign `data` and `errors` to a `result` variable like this. ```javascript @wire(graphql, { query: ... }) graphqlQueryResults(result) { const { data, errors, refresh } = result; } ``` ## Implement Cache Refresh in LWC **tip:** The [`graphqlRefresh` component](https://github.com/trailheadapps/lwc-recipes/tree/main/force-app/main/default/lwc/graphqlRefresh) in the [lwc-recipes repo](https://github.com/trailheadapps/lwc-recipes) demonstrates how to refresh a query using the refresh method. Here's an example that adds a refresh button to the example in [Make Your Variables Reactive](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-reactive.md). ```javascript //refreshAccountsGQL.js import { LightningElement, wire } from "lwc"; import { gql, graphql } from "lightning/graphql"; export default class AccountsGQL extends LightningElement { records; errors; graphqlRefresh; minAmount = "5000000"; minAmounts = [ { label: "All", value: "0" }, { label: "$5,000,000", value: "5000000" }, { label: "$50,000,000", value: "50000000" }, { label: "$500,000,000", value: "500000000" }, ]; @wire(graphql, { query: gql` query bigAccounts($minAmount: Currency) { uiapi { query { Account(where: { AnnualRevenue: { gte: $minAmount } }) { edges { node { Id Name { value } AnnualRevenue { displayValue } } } } } } } `, variables: "$variables", }) graphqlQueryResult({ data, errors, refresh }) { if (data) { this.records = data.uiapi.query.Account.edges.map((edge) => edge.node); } this.errors = errors; // Store the refresh method to call later this.graphqlRefresh = refresh; } async handleRefresh() { return this.graphqlRefresh(); } get variables() { return { minAmount: this.minAmount, }; } // Called when the user selects a new minimum amount handleMinAmountChange(event) { this.minAmount = event.detail.value; } } ``` If a record that's contained in a query result changes, Lightning Data Service emits a new value to the GraphQL wire adapter. However, Lightning Data Service doesn't reevaluate the query to see if the record still matches the query. To ensure that Lightning Data Service reevaluates your query, use the refresh method. This example adds a button that enables you to trigger a refresh of the query results. ```html ``` # Use a Namespace and Alias in Managed Packages Before you package your components and distribute them on AppExchange, register a namespace in your org. A namespace prefix prevents naming conflicts in the installer's organization. See [Developing Second-Generation Managed Packages](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev_2gp_developing_2gp_packages.htm). Just like component names include a namespace prefix in managed packages, GraphQL API queries in your components must include a namespace prefix on custom objects and fields. For example, a custom object, `MyCustomObject__c`, in an org with the namespace, `example_ns`, would become `example_ns__MyCustomObject__c`. **note:** If your org uses a namespace, namespacing is resolved _automatically_ for custom objects and fields in your query when deploying your Lightning Web component. Namespace resolution isn't affected if you add it yourself. Let's look at an example with a GraphQL query that works correctly as-is in a non-namespaced developer org. The example is followed by a package-ready query that includes an org's namespace and preserves referential integrity. The GraphQL query uses a custom object, `Custom_Object__c`, and a custom field, `Custom_Object_Field__c`, in the example developer org with the `my_namespace` namespace. **important:** If you’re referencing objects and fields from another namespace, you must include the namespace as part of the object or field name. ``` @wire(graphql, { query: gql` query { uiapi { query { Custom_Object__c { edges { node { Custom_Object_Field__c { value } } } } } } }` }) ``` During development, you push the component to a scratch org for testing. The original component source is unchanged. The updated query is sent to the client, which is also what a subscriber's org executes when it runs. ``` @wire(graphql, { query: gql` query { uiapi { query { my_namespace__Custom_Object__c { edges { node { my_namespace__Custom_Object_Field__c { value } } } } } } }` }) ``` **note:** References to objects and fields outside of the `gql` template literal aren’t updated. Since the query is updated, the component is likely to fail at runtime. To resolve this issue, apply [GraphQL alias syntax](https://graphql.org/learn/queries/#aliases) on your custom objects and fields. See [Use Aliases with Custom Objects and Fields](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-best.md#use-aliases-with-custom-objects-and-fields). Let's add aliasing to the base query, and update how you retrieve data from the response. ``` @wire(graphql, { query: gql` query { uiapi { query { Custom_Object: Custom_Object__c { edges { node { Custom_Object_Field: Custom_Object_Field__c { value } } } } } } }` }) graphqlQueryResult({ data, errors }) { if (data) { // Use the Custom_Object alias when you retrieve the query results this.results = data.uiapi.query.Custom_Object.edges.map((edge) => edge.node); } this.errors = errors; } ``` When you push the component to a scratch org with aliasing, the resulting query looks like this. ``` @wire(graphql, { query: gql` query { uiapi { query { Custom_Object: my_namespace__Custom_Object__c { edges { node { Custom_Object_Field: my_namespace__Custom_Object_Field__c { value } } } } } } }` }) ``` Using GraphQL alias maintains referential integrity and preserves the names that are used for custom objects and fields in the GraphQL result. ## Referential Integrity Referential integrity is built in to the Salesforce platform development experience. Referential integrity includes: - Spidering: automatically including dependencies in packages and changesets - Delete blocked: preventing or issuing a warning on the deletion of dependencies - Rename cascades: updating source code on the renaming of dependencies These capabilities simplify working across technologies and concepts on the Salesforce platform. For example, when you apply custom objects and fields to your query and package the Lightning Web component, it automatically includes the custom objects and fields. When the developer tries to delete the custom object, the operation is blocked because it can break the Lightning web component. **note:** When the custom object gets renamed, the reference to that object in the query is updated. To preserve referential integrity, we strongly recommend using GraphQL aliases for your custom objects and fields. Using GraphQL aliases also prevent your component from breaking if a subscriber org renames your custom objects or fields. ## See Also [Use Aliases with Custom Objects and Fields](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-best.md#use-aliases-with-custom-objects-and-fields) [Second-Generation Managed Packages](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp.htm) [Salesforce DX Project Configuration](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) # Use Platform Capabilities | AVAILABLE API VERSION | | --------------------- | | API v67.0 and later | The `platform` field on the `UIAPI` type provides capabilities to complement the `RecordQuery` type. Use platform capabilities to: - Check specific permissions for the current user - Resolve authenticated file-asset URLs for Salesforce content assets in batch - Resolve canonical URLs for static resources - Get the current user’s internationalization properties - Resolve custom and standard label values in the current user’s locale ## Platform Schema Access `platform` in the `uiapi` field. ``` type UIAPI { platform: Platform! } type Platform { userPermissions(names: [String!]!): [UserPermission]! customPermissions(names: [String!]!): [CustomPermission]! contentAssetUrls(names: [String!]!): [ContentAssetUrl]! resourceUrls(names: [String!]!): [ResourceUrl]! i18n: I18nData labels( namespace: String = "c" names: [String!]! locale: String fallback: LabelFallback ): [LabelResult]! } ``` ## userPermissions and customPermissions Fields The `userPermissions` and `customPermissions` fields return permission grants for the calling user. Use these fields to determine whether the current user has specific permissions without querying the User object or making more API calls. This functionality mirrors the LWC [`@salesforce/userPermission`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforceuserpermission) and [`@salesforce/customPermission`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforcecustompermission) imports. Pass permission names as a list in the `names` argument to return the grant status for each named permission in a single request. You can pass up to 25 permission names per call. A failure on one name doesn’t cause the operation to fail. Partial successes show failed names in the returned `errors` object. ``` { uiapi { platform { userPermissions(names: ["ManageUsers", "ViewSetup"]) { name hasAccess } customPermissions(names: ["My_Custom_Permission"]) { name hasAccess } } } } ``` ### Permissions Schema ``` type Platform { userPermissions(names: [String!]!): [UserPermission]! customPermissions(names: [String!]!): [CustomPermission]! } type UserPermission { name: String! hasAccess: Boolean! } type CustomPermission { name: String! hasAccess: Boolean! } ``` #### UserPermissions Field The `userPermissions` field returns a list of `UserPermission` types, one per name in the `names` argument. - `names` - A list of user permission API names to check for the calling user. This argument is required. The `UserPermission` type contains these fields. - `name` - The API name of the user permission. - `hasAccess` - Indicates whether the calling user has the permission. #### CustomPermissions Field The `customPermissions` field returns a list of `CustomPermission` types, one per name in the `names` argument. - `names` - A list of custom permission API names to check for the calling user. This argument is required. The `CustomPermission` type contains these fields. - `name` - The API name of the custom permission. - `hasAccess` - Indicates whether the calling user has the permission. ### Example: Check User and Custom Permissions This example checks whether the current user has two user permissions and one custom permission. ``` { uiapi { platform { userPermissions(names: ["ManageUsers", "ViewSetup"]) { name hasAccess } customPermissions(names: ["My_Custom_Permission"]) { name hasAccess } } } } ``` The response includes a result for each named permission. ``` { "data": { "uiapi": { "platform": { "userPermissions": [ { "name": "ManageUsers", "hasAccess": false }, { "name": "ViewSetup", "hasAccess": true } ], "customPermissions": [ { "name": "My_Custom_Permission", "hasAccess": true } ] } } }, "errors": [] } ``` ## contentAssetUrls Field The `contentAssetUrls` field returns resolved URLs for content assets in the calling org. Use this field to retrieve the URL for one or more content assets by name without constructing URLs manually. This functionality mirrors the LWC [`@salesforce/contentAssetUrl`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforcecontentasseturl) import. Pass asset names as a list in the `names` argument to return the URL for each asset in a single request. A failure on one name doesn’t cause the operation to fail. Partial successes show failed names in the returned `errors` object. ``` { uiapi { platform { contentAssetUrls(names: ["companyLogo", "acme__heroBanner"]) { name url } } } } ``` ### contentAssetUrls Schema ``` type Platform { contentAssetUrls(names: [String!]!): [ContentAssetUrl]! } type ContentAssetUrl { name: String! url: String! } ``` The `contentAssetUrls` field returns a list of `ContentAssetUrl` types, one per name in the `names` argument. - `names` - A list of up to 25 content asset names to resolve. Use the same canonical form as the LWC import. Unmanaged assets use the developer name. Managed package assets include the namespace prefix, such as `__`. This argument is required. The `ContentAssetUrl` type contains these fields. - `name` - The name of the content asset. - `url` - The authenticated file-asset servlet URL for the content asset. ### Example: Get Content Asset URLs This example retrieves the URLs for two content assets. ``` { uiapi { platform { contentAssetUrls(names: ["companyLogo", "acme__heroBanner"]) { name url } } } } ``` The response includes the resolved URL for each named asset. ``` { "data": { "uiapi": { "platform": { "contentAssetUrls": [ { "name": "companyLogo", "url": "https://example.my.salesforce.com/file-asset/companyLogo?v=1" }, { "name": "acme__heroBanner", "url": "https://example.my.salesforce.com/file-asset/acme__heroBanner?v=3" } ] } } }, "errors": [] } ``` ## resourceUrls Field The `resourceUrls` field returns resolved URLs for static resources in the calling org. Use this field to retrieve the URL for one or more static resources by name without constructing URLs manually. This functionality mirrors the LWC [`@salesforce/resourceUrl`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforceresourceurl) import. Pass resource names as a list in the `names` argument to return the URL for each resource in a single request. A failure on one name doesn’t cause the operation to fail. Partial successes show failed names in the returned `errors` object. ``` { uiapi { platform { resourceUrls(names: ["myResource", "acme__logo"]) { name url } } } } ``` ### resourceUrls Schema ``` type Platform { resourceUrls(names: [String!]!): [ResourceUrl]! } type ResourceUrl { name: String! url: String! } ``` The `resourceUrls` field returns a list of `ResourceUrl` types, one per name in the `names` argument. - `names` - A list of up to 25 static resource names to resolve. Use the same canonical form as the LWC import. Unmanaged assets use the developer name. Managed package assets include the namespace prefix, such as `__`. This argument is required. The `ResourceUrl` type contains these fields. - `name` - The name of the static resource. - `url` - The resolved URL for the static resource. ### Example: Get Static Resource URLs This example retrieves the URLs for two static resources. ``` { uiapi { platform { resourceUrls(names: ["myResource", "acme__logo"]) { name url } } } } ``` The response includes the resolved URL for each named resource. ``` { "data": { "uiapi": { "platform": { "resourceUrls": [ { "name": "myResource", "url": "/resource/1234567890000/myResource" }, { "name": "acme__logo", "url": "/resource/1234567890001/acme__logo" } ] } } }, "errors": [] } ``` ## i18n Field The `i18n` field returns internationalization (i18n) data for the current user, mirroring the values available through LWC [`@salesforce/i18n`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforcei18n) imports. Use this field to get locale, currency, time zone, and date and number format data for the calling user in a single request. ``` { uiapi { platform { i18n { lang locale currency timeZone dateTime { shortDateFormat longDateTimeFormat } number { currencySymbol decimalSeparator groupingSeparator } } } } } ``` ### i18n Schema ``` type Platform { i18n: I18nData } type I18nData { lang: String dir: String locale: String currency: String timeZone: String firstDayOfWeek: Int showJapaneseCalendar: Boolean isEasternNameStyle: Boolean defaultCalendar: String defaultNumberingSystem: String calendarData: JSON dateTime: I18nDateTimeData number: I18nNumberData common: I18nCommonData } type I18nDateTimeData { shortDateFormat: String mediumDateFormat: String longDateFormat: String shortDateTimeFormat: String mediumDateTimeFormat: String longDateTimeFormat: String shortTimeFormat: String longTimeFormat: String } type I18nNumberData { currencyFormat: String currencySymbol: String decimalSeparator: String exponentialSign: String groupingSeparator: String infinity: String minusSign: String nan: String numberFormat: String perMilleSign: String percentFormat: String percentSign: String plusSign: String superscriptExponentSign: String } type I18nCommonData { calendarData: JSON digits: JSON } ``` The `I18nData` type contains top-level locale and user preferences. - `lang` - The language code for the current user’s language, for example, `en`. - `dir` - The text direction for the current user’s language, either `ltr` (left-to-right) or `rtl` (right-to-left). - `locale` - The locale code for the current user, for example, `en_US`. - `currency` - The ISO 4217 currency code for the current user, for example, `USD`. - `timeZone` - The IANA time zone name for the current user, for example, `America/Los_Angeles`. - `firstDayOfWeek` - The first day of the week for the user’s locale, where `0` is Sunday and `1` is Monday. - `showJapaneseCalendar` - Indicates whether the Japanese calendar is used for this user’s locale. - `isEasternNameStyle` - Indicates whether the user’s locale uses eastern name style (family name before given name). - `defaultCalendar` - The default calendar system for the user’s locale, for example, `gregorian`. - `defaultNumberingSystem` - The default numbering system for the user’s locale, for example, `latn`. - `calendarData` - More calendar data for the user’s locale as a JSON object. - `dateTime` - Date and time format strings for the current user’s locale. See [I18nDateTimeData](#i18ndatetimedata-type). - `number` - Number format strings and symbols for the current user’s locale. See [I18nNumberData](#i18nnumberdata-type). - `common` - Supplementary calendar and digit data for the user’s locale. See [I18nCommonData](#i18ncommondata-type). #### I18nDateTimeData Type The `I18nDateTimeData` type contains date and time format strings for the current user’s locale. - `shortDateFormat` - Short date format pattern, for example, `M/d/yyyy`. - `mediumDateFormat` - Medium date format pattern, for example, `MMM d, yyyy`. - `longDateFormat` - Long date format pattern. - `shortDateTimeFormat` - Short date and time format pattern. - `mediumDateTimeFormat` - Medium date and time format pattern. - `longDateTimeFormat` - Long date and time format pattern. - `shortTimeFormat` - Short time format pattern, for example, `h:mm a`. - `longTimeFormat` - Long time format pattern. #### I18nNumberData Type The `I18nNumberData` type contains number format strings and symbols for the current user’s locale. - `currencyFormat` - Currency format pattern, for example, `¤#,##0.00`. - `currencySymbol` - The currency symbol, for example, `$`. - `decimalSeparator` - The character used as the decimal separator, for example, `.`. - `exponentialSign` - The character used to denote exponential notation. - `groupingSeparator` - The character used as the grouping (thousands) separator, for example, `,`. - `infinity` - The string representing infinity. - `minusSign` - The character used as the minus sign. - `nan` - The string representing not-a-number. - `numberFormat` - General number format pattern. - `perMilleSign` - The character used for parts-per-thousand notation. - `percentFormat` - Percent format pattern. - `percentSign` - The character used as the percent sign. - `plusSign` - The character used as the plus sign. - `superscriptExponentSign` - The character used as the superscript exponent sign. #### I18nCommonData Type The `I18nCommonData` type contains supplementary calendar and digit data. - `calendarData` - Supplementary calendar data as a JSON object. - `digits` - Locale-specific digit characters as a JSON object. ### Example: Get Locale and Date Format Data This example fetches the current user’s locale, time zone, and date format patterns. ``` { uiapi { platform { i18n { lang locale timeZone firstDayOfWeek dateTime { shortDateFormat mediumDateFormat longDateFormat shortTimeFormat } number { currencySymbol decimalSeparator groupingSeparator } } } } } ``` The response includes the i18n data for the current user. ``` { "data": { "uiapi": { "platform": { "i18n": { "lang": "en", "locale": "en_US", "timeZone": "America/Los_Angeles", "firstDayOfWeek": 0, "dateTime": { "shortDateFormat": "M/d/yyyy", "mediumDateFormat": "MMM d, yyyy", "longDateFormat": "MMMM d, yyyy", "shortTimeFormat": "h:mm a" }, "number": { "currencySymbol": "$", "decimalSeparator": ".", "groupingSeparator": "," } } } } }, "errors": [] } ``` ## labels Field The `labels` field returns resolved custom label values for the calling user. Use this field to get one or more custom labels by name, optionally specifying a locale and a fallback strategy if a translation isn’t available. This functionality mirrors the LWC [@salesforce/label](https://developer.salesforce.com/docs/platform/lwc/guide/reference-salesforce-modules.html#salesforcelabel) import. ``` { uiapi { platform { labels(names: ["greeting", "submit_button"]) { namespace name value resolvedLocale wasFallback } } } } ``` ### Labels Schema ``` type Platform { labels( namespace: String = "c" names: [String!]! locale: String fallback: LabelFallback ): [LabelResult]! } type LabelResult { namespace: String! name: String! value: String resolvedLocale: String wasFallback: Boolean! } enum LabelFallback { USER_DEFAULT BASE_VALUE NONE } ``` The `labels` field has these arguments. - `namespace` - The namespace for custom labels or framework section name, such as `LightningForm`, for standard labels. Defaults to `c` to resolve unmanaged custom labels. - `names` - A list of up to 100 custom label API names to retrieve. This argument is required. - `locale` - The locale to use when resolving label translations, for example, `fr`. Defaults to the calling user’s locale. - `fallback` - The fallback behavior when a translation isn’t available for the requested locale. Defaults to `USER_DEFAULT`. See [LabelFallback](#labelfallback-enum). ### LabelResult Type The `LabelResult` type represents a resolved custom label value. - `namespace` - The namespace of the custom label. - `name` - The API name of the custom label. - `value` - The resolved label value for the requested locale, or `null` if the label doesn’t exist and `fallback` is `NONE`. - `resolvedLocale` - The locale that was used to resolve the label value. This locale can differ from the requested locale if a fallback occurred. - `wasFallback` - Indicates whether a fallback resolved the `value` rather than a direct translation match. ### LabelFallback Enum The `LabelFallback` enumeration controls how the API handles missing translations. ``` enum LabelFallback { USER_DEFAULT BASE_VALUE NONE } ``` - `USER_DEFAULT` - Falls back first to the user’s default language translation, then to the base label value if no language-level translation is available. This value is the default. - `BASE_VALUE` - Falls back directly to the base label value, skipping the user’s language. - `NONE` - Doesn’t fall back. If a translation for the requested locale is missing, `value` is `null` and the response includes a GraphQL error. ### Example: Get Labels in a Specific Locale This example fetches two custom labels in French. ``` { uiapi { platform { labels(names: ["greeting", "submit_button"], locale: "fr", fallback: USER_DEFAULT) { namespace name value resolvedLocale wasFallback } } } } ``` The response includes the resolved label value and the locale. ``` { "data": { "uiapi": { "platform": { "labels": [ { "namespace": "c", "name": "greeting", "value": "Bonjour", "resolvedLocale": "fr", "wasFallback": false }, { "namespace": "c", "name": "submit_button", "value": "Submit", "resolvedLocale": "en", "wasFallback": true } ] } } }, "errors": [] } ``` ### Example: Get Standard Framework Labels This example fetches labels from the `LightningForm` framework namespace. ``` { uiapi { platform { labels(namespace: "LightningForm", names: ["edit", "save"]) { name value resolvedLocale } } } } ``` # Use the GraphQL Wire Adapter Retrieve specific records, fields, and object information in a single server call using the GraphQL wire adapter. With built-in shared caching, Lightning Data Service manages your data and you don’t need different wire adapters for each GraphQL query you define. The GraphQL wire adapter provides access to the Salesforce GraphQL API, enabling you to work with UI API enabled objects with the object-level security and field-level security of the context user. The schema exposed by the GraphQL API dictates what you can do with the GraphQL wire adapter. The GraphQL wire adapter supports the same capabilities as the GraphQL API, except as noted in [GraphQL API Wire Adapter Limitations](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-wire-lwc-limitations.md). To get started, you can view the schema for your org using the [Altair GraphQL Client](https://developer.salesforce.com/docs/platform/graphql/get-started-graphql.md). The client provides a query editor that includes field auto-completion, enabling you to add fields easily for a given type on any Salesforce object. We recommend that you use this client to help you build your queries quickly and accurately. **tip:** The [lwc-recipes repo](https://github.com/trailheadapps/lwc-recipes) presents helpful examples to help you quickly get started on the GraphQL wire adapter. This documentation assumes that you already have your [LWC development environment set up](https://developer.salesforce.com/docs/platform/lwc/guide/install-setup-develop.html). # What is GraphQL API? GraphQL addresses many pain points for application developers. All GraphQL servers adhere to a [specification](https://spec.graphql.org/), which features patterns that make it easier to build complex experiences across a wide variety of platforms and devices. Salesforce GraphQL API is available in **Enterprise**, **Performance**, **Unlimited**, and **Developer** Editions. It adheres to the [June 2018](https://spec.graphql.org/June2018/) version of the spec. These patterns are available for Salesforce developers. - Field selection - Resource aggregation - Schema introspection Field selection requires the client generating the GraphQL query to explicitly declare which fields to receive in the response. This technique reduces the size of the payload, as the client receives only fields that the query includes. Aggregation allows the client to specify a traversal across the fields in the GraphQL schema. Aggregations reduce round trips between the client and server, returning a set of related resources within a single response. Introspection sends a query to the GraphQL server to ask questions about the types, fields, and their relationships within the schema. Combining all these patterns results in more responsive, higher-quality applications. GraphQL API includes: - Concrete representations of your [UI API Enabled](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_all_supported_objects.htm) sObjects, honoring the [object-level security and field-Level security](https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/security_data_access.htm) of the context user. Therefore, two different users can have two different views of the GraphQL schema based on their access permissions. Starting in API version 68.0, admins can control unauthenticated guest user access to GraphQL API from Setup. In the Quick Find box, enter **API Access Controls** and select it, and then update guest user access. GraphQL API honors object-level and field-level security for guest user context users. - Adherence to the [Relay Connection Specification](https://relay.dev/graphql/connections.htm) if working with paged resources. For more information about getting started with GraphQL API, we recommend these resources. - [Introducing the Salesforce GraphQL API](https://developer.salesforce.com/blogs/2022/03/introducing-the-salesforce-graphql-api) (Salesforce Developers Blog) - [Exploring the Salesforce GraphQL API – Part Two](https://developer.salesforce.com/blogs/2022/05/exploring-the-salesforce-graphql-api-part-two) (Salesforce Developers Blog) - [codeLive: GraphQL for Salesforce Developers](https://www.youtube.com/watch?v=A9_E7_EM9Vw) (YouTube Video) # When to Use GraphQL Wire Adapter The GraphQL wire adapter provides numerous game changing benefits, such as a single endpoint with data aggregation across multiple resources. It speeds up your UI development for working with Salesforce data, and it’s a great tool for these popular use cases. - Optimize your apps by minimizing the number of requests that’s needed to fetch specific data for users with bandwidth and speed constraints. - Your Lightning web components can query exact objects and fields without any redundant data, making your app transactions lightweight and performant. - Pagination with cursor and offset information enables you to query and present your data with ease and efficiency, especially when working with large data sets. ## GraphQL Wire Adapter Alternatives LWC provides several other ways to work with Salesforce records, such as the Lightning Data Service (LDS) wire adapters, `lightning-*-form` base components, and Apex. The LDS adapters in [the `lightning/ui*Api` module](https://developer.salesforce.com/docs/platform/lwc/guide/reference-ui-api.html) provide the only way to create, edit, or delete records. You can work with multiple records using multiple functions where each operation is an independent transaction. Using LDS wire adapters can require multiple round trips to the server and a combination of several wire adapters to request your data. Other adapters in the `lightning/ui*Api` module provide the ability to retrieve record data if you know the IDs of the records. When these adapters perform the function you need, they’re more efficient than the GraphQL wire adapter. They can’t, however, express the complex filtering, sorting, and relationship traversals that are possible with a single GraphQL query. Apex is helpful if your object isn’t supported by UI API or if you want to run an operation in system context without user permissions, sharing rules, or field-level security. You can use Apex to work with multiple records in a single transaction. ## See Also [LWC Dev Guide: Data Guidelines](https://developer.salesforce.com/docs/platform/lwc/guide/data-guidelines.html)