Implement a Data Provider

A data provider is a reference to a source of data. It's implemented as a function within an Apex class.

To pull data into a view, bind the view to a data provider. To reference the data throughout a view, use an expression.

Apex Data Types

You can use these data types for input and output in Apex methods.

Data Type Description Examples
Primitive Boolean, Date, DateTime, Decimal, Double, Integer, Long, and String - Primitive Input and Primitive Output<br> - Primitive Input and List<Primitive> Output
sObject A row of data declared using the SOAP API name of the object. Both standard and custom objects are supported. - Standard Object Input and List Output<br> - Custom Object Output<br> - List<sObject> Output<br> - Map with Contact List Output
Apex An instance of an Apex class Apex Class Output
Collection A list, set, or map - Standard Object Input and List Output<br> -List<sObject> Output<br> - Primitive Input and List<Primitive> Output<br> - Map with Contact List Output

Bind Apex Methods to Components

To bind a data provider to a component, follow this syntax for the definition value.

apex__[ApexNamespace].ApexClassName.ApexMethod

For example:

dataproviders:
  yourData:
    definition: "apex__MyDataProvider.getYourDataFromApexClass"

The arguments passed to the Apex method are specified as properties to the data provider. The property key must match the name of the parameter in the Apex method signature.

Data Providers for Select and External Select Components

The Select component uses the dataproviders property to bind a data provider to the view.

To create a data provider for a Select component, construct a List<Slack.Option> or List<Slack.OptionGroup> for your view definition.

The External Select component uses the datasource property to bind a data provider to the view. For the External Select component, your Apex methods must follow certain method signature restrictions.

  • Must have a String value as the first parameter in addition to any other parameters already present.
  • Must return Slack.OptionDataResponse. Construct Slack.OptionDataResponse with List<Slack.OptionGroup> or List<Slack.Option>. All items in the same Slack.OptionDataResponse must be of the same type.

important: Constructing a Slack.OptionDataResponse with a combination of Slack.Option and Slack.OptionGroup isn’t supported.

The optional value parameter provides the input string entered into the select component that's used to perform the lookup. The value you provide preselects an option from the options identifier or from your data provider.

components:
  - definition: select
    properties:
      name: "StageName"
      value: "Prospecting"
      placeholder: "Select a stage."
      options:
        - identifier: "Prospecting"
          label: "Prospecting"
        - identifier: "Qualification"
          label: "Qualification"

See more examples.

Examples

These examples show you how to create a data provider with Apex data types.

Primitive Input and Primitive Output

Apex method:

public class EchoExample {
    public static String echo(String echoStr) {
        return echoStr;
    }
}

View:

description: "This simple view contains an Apex echo data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "Echo ApexDataProvider"
    myString:
      type: string
      default: "Hello, World!"
dataproviders:
  echoStr:
    definition: "apex__EchoExample.echo"
    properties:
      echoStr: "{!view.properties.myString}"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: section
        properties:
          text: "{!echoStr}" # will render Hello, World!

Standard Object Input and List Output

Apex method:

public class ObjectInputListOutputExample {
    public static List<Contact> getAccountContacts(Account acct) {
        List<Contact> contacts = [
            SELECT Id, Name, Title, Phone, Email
            FROM Contact
            WHERE AccountId = :acct.Id
            WITH SECURITY_ENFORCED
            LIMIT 10
        ];

        return contacts;
    }
}

View:

description: "This list view contains an Apex Contact list data provider for an Account"
schema:
  properties:
    title:
      type: string
      defaultValue: "Account Contacts ApexDataProvider"
    accountId:
      type: string
      defaultValue: "001xx000003GYQRAA4"
dataproviders:
  contacts:
    definition: "apex__ObjectInputListOutputExample.getAccountContacts"
    properties:
      acct:
        Id: "{!view.properties.accountId}"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: header
        properties:
          text: "My Contacts"
      - definition: iteration
        properties:
          foreach: "{!contacts}"
          foritem: "contact"
        components:
          - definition: divider
          - definition: section
            properties:
              text: "{!contact.Name}"
          - definition: section
            properties:
              text:
                text: "*Id:* {!contact.Id}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Title:* {!contact.Title}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Phone:* {!contact.Phone}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Email:* {!contact.Email}"
                type: mrkdwn

Apex Class Output

Apex method:

public class ClassOutputExample {
    public static TestClass getApexClass() {
        return new TestClass();
    }
}

// User-defined Apex class
public class TestClass {
    public final String myString = 'Hello from TestClass class!';
}

View:

description: "This simple view contains an Apex user type data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "UserType ApexDataProvider"
dataproviders:
  apexClass:
    definition: "apex__ClassOutputExample.getApexClass"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: section
        properties:
          text: "{!apexClass.myString}"

Custom Object Output

Apex method:

public class CutomObjectOutputExample {
    public static MyCustomObject__c getCustomObject(Id objectId) {
        MyCustomObject__c customObject = [
            SELECT Id, Name, CustomTextField__c, CustomDateField__c, CustomNumberField__c
            FROM MyCustomObject__c
            WHERE Id = :objectId
            WITH SECURITY_ENFORCED
        ];

        return customObject;
    }
}

View:

description: "This simple view contains an Apex single custom object data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "CustomObject ApexDataProvider"
    objectId:
      type: string
      defaultValue: "a00xx000000boMTAAY"
dataproviders:
  customobject:
    definition: "apex__CutomObjectOutputExample.getCustomObject"
    properties:
      objectId: "{!view.properties.objectId}"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: header
        properties:
          text: "CustomObject: {!view.properties.objectId}"
      - definition: section
        properties:
          text: "{!customobject.Name}"
      - definition: section
        properties:
          text:
            text: "*Id:* {!customobject.Id}"
            type: mrkdwn
      - definition: section
        properties:
          text:
            text: "*Custom Text Field:* {!customobject.CustomTextField__c}"
            type: mrkdwn
      - definition: section
        properties:
          text:
            text: "*Custom Date Field:* {!customobject.CustomDateField__c}"
            type: mrkdwn
      - definition: section
        properties:
          text:
            text: "*Custom Number Field:* {!customobject.CustomNumberField__c}"
            type: mrkdwn

sObject List Output

Apex method:

public class ListOutputExample {
    public static List<Contact> getContactList() {
        List<Contact> contacts = [
            SELECT Id, Name, Title, Phone, Email
            FROM Contact
            WITH SECURITY_ENFORCED
            LIMIT 10
        ];

        return contacts;
    }
}

View:

description: "This is a simple list view containing an Apex contact list data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "Contacts ApexDataProvider"
dataproviders:
  contacts:
    definition: "apex__ListOutputExample.getContactList"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: header
        properties:
          text: "My Contacts"
      - definition: iteration
        properties:
          foreach: "{!contacts}"
          foritem: "contact"
        components:
          - definition: divider
          - definition: section
            properties:
              text: "{!contact.Name}"
          - definition: section
            properties:
              text:
                text: "*Id:* {!contact.Id}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Title:* {!contact.Title}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Phone:* {!contact.Phone}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Email:* {!contact.Email}"
                type: mrkdwn

Primitive Input and Primitive List Output

Apex method:

public class StringListExample {
    public static String[] echoMultiple(String string1, String string2, String string3) {
        List<String> myList = new List<String>();
        myList.add(string1);
        myList.add(string2);
        myList.add(string3);
        return myList;
    }
}

View:

description: "This is a simple list view containing an Apex echo list data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "EchoMultiple ApexDataProvider"
    string1:
      type: string
      required: true
    string2:
      type: string
      required: true
    string3:
      type: string
      required: true
dataproviders:
  echoStrings:
    definition: "apex__StringListExample.echoMultiple"
    properties:
      string1: "{!view.properties.string1}"
      string2: "{!view.properties.string2}"
      string3: "{!view.properties.string3}"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: iteration # iterate through list of strings
        properties:
          foreach: "{!echoStrings}"
          foritem: "echoStr"
        components:
          - definition: section
            properties:
              text: "{!echoStr}"

Map with Contact List Output

Apex method:

public class MapContactListExample {
    publicstatic Map<Id, List<Contact>> getAccountContactMap() {
        List<Contact> contacts = [
            SELECT Id, Name, Title, Phone, Email, AccountId
            FROM Contact
            WITH SECURITY_ENFORCED
            LIMIT 10
        ];
        Map<Id, List<Contact>> contactMap = new Map<Id, List<Contact>>();
        for (Contact contact : contacts) {
            Id acctId = contact.AccountId;
            if (!contactMap.containsKey(acctId)) {
                contactMap.put(acctId, new List<Contact>());
            }
            contactMap.get(acctId).add(contact);
        }

        return contactMap;
    }
}

View:

description: "This is a simple list view containing an Apex account contact map data provider"
schema:
  properties:
    title:
      type: string
      defaultValue: "Account Contacts ApexDataProvider"
dataproviders:
  contacts:
    definition: "apex__MapContactListExample.getAccountContactMap"
components:
  - definition: modal
    properties:
      title: "{!view.properties.title}"
    components:
      - definition: header
        properties:
          text: "My Contacts for 001xx000003GYQRAA4"
      - definition: iteration
        properties:
          foreach: "{!contacts.001xx000003GYQRAA4}"
          foritem: "contact"
        components:
          - definition: divider
          - definition: section
            properties:
              text: "{!contact.Name}"
          - definition: section
            properties:
              text:
                text: "*Id:* {!contact.Id}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Title:* {!contact.Title}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Phone:* {!contact.Phone}"
                type: mrkdwn
          - definition: section
            properties:
              text:
                text: "*Email:* {!contact.Email}"
                type: mrkdwn

tip: This example is from view_contact.view in the sample app.

External Select

Apex data provider using List<Slack.Option> and returning Slack.OptionDataResponse:

global class AccountDataProvider {
 global static Slack.OptionDataResponse getAccountsByName(String value) {
    String name = '%'+ value + '%';
    List<Account> accounts = [
      SELECT Id, Name
      FROM Account
      WHERE Name LIKE :name
      WITH SECURITY_ENFORCED
      LIMIT 10
    ];
     System.debug('retrieved accounts');
     List<Slack.Option> accountOptions = new List<Slack.Option>();
     for(Account account: accounts) {
         Slack.Option option = new Slack.Option(account.Name, account.Id);
         System.debug(option.getText());
         accountOptions.add(option);
     }
    return new Slack.OptionDataResponse(accountOptions);
  }
}

Apex data provider using List<Slack.OptionGroup> and returning Slack.OptionDataResponse:

global class ContactDataProvider {
 global static Slack.OptionDataResponse getContactGroupsByName(String value) {
    String name = '%'+ value + '%';
    List<Contact> contacts = [
      SELECT Name, Id, AccountId, Account.name
      FROM Contact
      WHERE Name LIKE :name
      LIMIT 10
    ];
     Map<Id, List<Slack.Option>> contactsByAccount = new Map<Id, List<Slack.Option>>();
     Map<Id, String> accountNames = new Map<Id,String>();
     for(Contact contact: contacts) {
         List<Slack.Option> options = contactsByAccount.get(contact.AccountId);
         Slack.Option currentOption = new Slack.Option(contact.name, contact.id);
         if (options == null) {
            List<Slack.Option> newList = new List<Slack.Option>();
            newList.add(currentOption);
            contactsByAccount.put(contact.AccountId, newList);
            accountNames.put(contact.AccountId, contact.Account.name);
         } else {
             options.add(currentOption);
        }
     }
     List<Slack.OptionGroup> contactOptionGroups = new List<Slack.OptionGroup>();
     for(Id key : contactsByAccount.keySet()) {
         String accountName = accountNames.get(key);
         System.debug(key);
         Slack.OptionGroup optionGroup = new Slack.OptionGroup(accountName, contactsByAccount.get(key));
         System.debug(optionGroup.getLabel());
         contactOptionGroups.add(optionGroup);
     }
    return new Slack.OptionDataResponse(contactOptionGroups);
  }
}

View:

description: "View with external select examples."
components:
  - definition: modal
    properties:
      title: "External Select"
    components:
      - definition: section
        properties:
          text: "Select an Account"
      - definition: actions
        name: "external_select_accounts"
        components:
          - definition: externalSelect
            properties:
              placeholder: "Look up an account by name"
              name: "account_lookup"
              datasource:
                definition: "apex__AccountDataProvider.getAccountsByName"
      - definition: section
        properties:
          text: "Select a Contact"
      - definition: actions
        name: "external_select_contacts"
        components:
          - definition: externalSelect
            properties:
              placeholder: "Look up a Contact by name"
              name: "contact_lookup"
              datasource:
                definition: "apex__ContactDataProvider.getContactGroupsByName"

tip: This example is from create_opportunity.view in the sample app.