This interface allows Valence to interrogate your custom Adapter for information about what tables and fields are accessible in an external system.

You will sometimes hardcode your schema into your Adapter, for example if you’re working against an API that rarely changes shape (or changing shape would require code changes anyways). Generally, we recommend that you try to make your schema inspection dynamic such that if the database structure changes your Adapter can report on the new structure without having its coding updated. Think about how Salesforce custom fields and objects are so easily added, and information about them exposed through the Metadata API or Schema Describe. Try to do that with your Adapter.

For additional documentation, see the pages on Table and Field.

If you are dynamically inspecting external system schema, you will likely also want to implement NamedCredentialAdapter.


Two valuable things to be aware of:

  1. Not every Adapter has to implement SchemaAdapter. It is perfectly fine for an Adapter to not have a schema. The Adapter will be treated by Valence as if it only accesses a single, unnamed table. Users will not be shown a choice of tables. Fields for mapping will be discovered by Valence (see #2).
  2. Whether you implement SchemaAdapter or not, Valence always inspects record shape as records go by and will surface potential fields to Valence users as mapping targets. If you miss fields in your getFields() call, Valence can still spot them.


 * Implement this interface if your Adapter has a structured schema and you want to allow the User to select
 * from a list of specific tables and fields that they can interact with.
global interface SchemaAdapter extends Adapter {

     * We will interrogate your adapter and ask it what tables can be interacted with.
     * @return A List of Table definitions that will be provided to Users.
    List<Table> getTables();

     * A natural follow-on from getTables, we will interrogate your adapter to
     * find out which fields can be interacted with on a table.
     * @param tableApiName The specific table a User is interested in, comes from your list returned by getTables()
     * @return A List of Field definitions that will be provided to Users for consideration.
    List<Field> getFields(String tableApiName);

Example Usage - Hardcoded

public List<valence.Table> getTables() {
    return new List<valence.Table>{
        valence.Table.create('Company').withLabel('Company').withDescription('Definitions of businesses.').build(),
        valence.Table.create('Person').withLabel('Person').withDescription('People that are associated with a business.').build()

Example Usage - Dynamic

public List<valence.Table> getTables() {

    // Send the request
    Map<String,String> serverTables = fetchTablesFromExternalServer();

    List<valence.Table> tables = new List<valence.Table>();

    // iterate through response elements
    for(String key : serverTables.keySet()) {

    return tables;