# 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](/docs/platform/salesforce-slack-sdk/guide/expressions.md).

## Apex Data Types

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

| Data Type                                                                                                           | Description                                                                                                   | Examples                                                                                                                                                                                                                                                                                               |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Primitive](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_primitives.htm)   | Boolean, Date, DateTime, Decimal, Double, Integer, Long, and String                                           | - [Primitive Input and Primitive Output](#primitive-input-and-primitive-output)<br> - [Primitive Input and List<Primitive> Output](#primitive-input-and-primitive-list-output)                                                                                                                         |
| [sObject](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SObject_types.htm)  | 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](#standard-object-input-and-list-output)<br> - [Custom Object Output](#custom-object-output)<br> - [List<sObject> Output](#sobject-list-output)<br> - [Map with Contact List Output](#map-with-contact-list-output)                                           |
| [Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_understanding.htm)     | An instance of an Apex class                                                                                  | [Apex Class Output](#apex-class-output)                                                                                                                                                                                                                                                                |
| [Collection](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections.htm) | A list, set, or map                                                                                           | - [Standard Object Input and List Output](#standard-object-input-and-list-output)<br> -[List<sObject> Output](#sobject-list-output)<br> - [Primitive Input and List<Primitive> Output](#primitive-input-and-primitive-list-output)<br> - [Map with Contact List Output](#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.

```yaml
apex__[ApexNamespace].ApexClassName.ApexMethod
```

For example:

```yaml
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](/docs/platform/salesforce-slack-sdk/guide/elements.md#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>`](/docs/platform/salesforce-slack-sdk/guide/apex_ref_options.md) for your view definition.

The [External Select](/docs/platform/salesforce-slack-sdk/guide/elements.md#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`](/docs/platform/salesforce-slack-sdk/guide/apex_ref_options.md). 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.

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

[See more examples](#external-select).

## Examples

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

### Primitive Input and Primitive Output

Apex method:

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

View:

```yaml
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:

```java
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:

```yaml
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:

```java
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:

```yaml
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:

```java
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:

```yaml
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:

```java
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:

```yaml
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:

```java
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:

```yaml
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:

```java
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:

```yaml
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](/docs/platform/salesforce-slack-sdk/guide/setup-install-app.md).
:::

### External Select

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

```java
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`:

```java
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:

```yaml
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](/docs/platform/salesforce-slack-sdk/guide/setup-install-app.md).
:::
