Simple Salesforce Apex Connector Framework

Simple Salesforce Apex Connector Framework

Salesforce Connect uses Apex Connector Framework to sync, query, search, etc. data from External Data Source. The External Data Source can be creating using the Apex Connector Framework.

Follow these steps to create Apex Connector Framework for External Data Source.

1. Create a Sample DataSource.Connection Class.

2. Create a Sample DataSource.Provider Class.

3. Go to External Data Source in Salesforce Setup to create the External Data Source and External Objects using the above classes.

4. Create a Remote Site setting for your API.

Sample API:

https://ghibliapi.herokuapp.com/

Remote Site Setting:

Sample Apex Classes:

DataSourceConnection Class:

global class DataSourceConnectionController extends DataSource.Connection {

    global DataSourceConnectionController( DataSource.ConnectionParams connectionParams ) {
    
    }
    
    override global List<DataSource.Table> sync() {
    
        List < DataSource.Table > tables = new List < DataSource.Table >();
        List < DataSource.Column > columns = new List < DataSource.Column >();
        columns.add( DataSource.Column.integer( 'Age', 3 ) );
        columns.add( DataSource.Column.url( 'DisplayUrl' ) );
        columns.add( DataSource.Column.text( 'ExternalId', 255 ) );
        columns.add( DataSource.Column.text( 'Gender', 255 ) );
        columns.add( DataSource.Column.text( 'Name', 255 ) );
        tables.add( DataSource.Table.get( 'People', 'Name', columns ) );
        return tables;
        
    }
    
    override global DataSource.TableResult query( DataSource.QueryContext context ) {
    
        DataSource.Filter filter = context.tableSelection.filter;
        String strURL;
        
        if ( filter != null ) {
        
            String thisColumnName = filter.columnName;
            
            if ( thisColumnName != null && thisColumnName.equals( 'ExternalId' ) ) {
            
                strURL = 'https://ghibliapi.herokuapp.com/people/' + filter.columnValue;
            
            } else {
            
                strURL = 'https://ghibliapi.herokuapp.com/people';
                
            }
            
        } else {
        
            strURL = 'https://ghibliapi.herokuapp.com/people';
            
        }

        List < Map < String, Object > > rows = DataSource.QueryUtils.process( context, getData( strURL ) );
        return DataSource.TableResult.get( true, null, context.tableSelection.tableSelected, rows );
                
    }
    
    public List< Map < String, Object > > getData( String strURL ) {
    
        String response = getResponse( strURL );
        List < Map < String, Object > > rows = new List < Map < String, Object > >();

        if ( !response.contains( '"items":' ) ) {
            
            if ( response.substring(0,1).equals( '{') ) {
                
                response = '[' + response  + ']';
                
            }
            
            response = '{"items": ' + response + '}';
            
        }

        Map < String, Object> responseBodyMap = ( Map < String, Object > ) JSON.deserializeUntyped( response );
        List < Object > fileItems = ( List < Object > )responseBodyMap.get( 'items' );
        Map < String, Object > error = ( Map < String, Object > ) responseBodyMap.get( 'error' );
        
        if ( error!=null ) {
        
            List < Object > errorsList = ( List < Object > ) error.get( 'errors' );
            Map < String, Object > errors = ( Map < String, Object > ) errorsList[ 0 ];
            String errorMessage = ( String ) errors.get( 'message' );
            throw new DataSource.OAuthTokenExpiredException( errorMessage );
        
        }
        
        if ( fileItems != null ) {
        
            for ( Integer i=0; i < fileItems.size(); i++ ) {
            
                Map < String, Object > item = ( Map < String, Object > )fileItems[ i ];
                rows.add( createRow( item ) );
                
            }
        } else {
        
            rows.add( createRow ( responseBodyMap ) );
            
        }

        return rows;
    }
    
    public String getResponse( String strURL ) {
    
        Http httpProtocol = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndPoint( strURL );
        request.setMethod( 'GET' );
        HttpResponse response = httpProtocol.send( request );
        return response.getBody();
        
    }

    public Map < String, Object > createRow( Map < String, Object > item ) {
    
        Map < String, Object > row = new Map < String, Object >();
        
        for ( String key : item.keySet() ) {
        
            if ( key == 'id') {
            
                row.put('ExternalId', item.get( key ) );
                
            } else if ( key == 'url' ) {
            
                row.put( 'DisplayUrl', item.get( key ) );
                
            } else if ( key == 'name' ) {
            
                row.put( 'Name', item.get( key ) );
                
            } else if ( key == 'age' ) {
            
                String tempAge = ( String )item.get( key );
            
                if ( tempAge.isNumeric() ) {
            
                    row.put( 'Age', item.get( key ) );
                
                }
                
            } else if ( key == 'gender' ) {
            
                row.put( 'Gender', item.get( key ) ); 
                
            }
            
        }
        
        return row;
        
    }
    
}

DataSourceProvider Class:

global class DataSourceProviderController extends DataSource.Provider {

    override global List < DataSource.AuthenticationCapability > getAuthenticationCapabilities() {
    
        List < DataSource.AuthenticationCapability > capabilities = new List < DataSource.AuthenticationCapability >();
        capabilities.add( DataSource.AuthenticationCapability.ANONYMOUS );
        return capabilities;
        
    }

    override global List < DataSource.Capability > getCapabilities() {
    
        List < DataSource.Capability > capabilities = new List < DataSource.Capability >();
        capabilities.add( DataSource.Capability.ROW_QUERY );
        return capabilities;
        
    }
    
    override global DataSource.Connection getConnection( DataSource.ConnectionParams connectionParams ) {
    
        return new DataSourceConnectionController( connectionParams );
        
    }

}

External Data Source:

External Object:

External Object fields:

External Object Tab:

Reference Article:

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_connector_start.htm

Leave a Reply