Apex Recipes

repository·main·Indexed 22 days ago

https://github.com/trailheadapps/apex-recipes

A sample app and library of concise Apex and LWC code examples demonstrating enterprise patterns and best practices for Salesforce developers. It includes implementations of the Service Layer pattern, TriggerHandler framework, and custom Comparators for SObjects, along with guides for installation via Scratch Orgs, Unlocked Packages, and the Salesforce CLI.

Tokens
47.3K
Snippets
249
Records
293
Agent score
77%

What's inside Apex Recipes

  1. Use the ApiServiceRecipes class to interact with the Google Books API

    main

    The ApiServiceRecipes class is a specialized implementation of the RestClient class designed to interact with the Google Books API. It handles the serialization and deserialization of Data Transfer Objects (Model Objects) required for communication between the Salesforce org and the third-party Google Books service.

    Key responsibilities include:

    • Managing communication with the Google Books API endpoints.
    • Mapping API request/response data to internal Model Objects.
    • Utilizing a specific Named Credential for authentication and URL routing.
    // Note: This class extends RestClient to provide Google Books specific integration logic.
  2. Use MDTAccountTriggerHandler for metadata-driven trigger execution

    main
    The MDTAccountTriggerHandler class is a specialized trigger handler for the Account object. It implements a custom metadata-driven approach, allowing multiple trigger handler classes to be ordered and controlled via Custom Metadata. This class inherits from TriggerHandler and provides the specific implementation for Account-related logic, such as beforeUpdate().
  3. Use the CanTheUser class for CRUD and FLS checks

    main

    The CanTheUser class is a reusable library designed to simplify security checks in Apex. It provides an intuitive syntax for determining if the current user has permissions to perform CRUD (Create, Read, Update, Delete) operations on objects or has Field-Level Security (FLS) access to specific fields. Instead of complex schema describes, you can use readable calls like CanTheUser.read(new Account()).

    if(CanTheUser.read(new Account())) {
      // Perform read logic
    }
  4. How the Safely class works

    main

    The Safely class is a utility designed to wrap DML calls with automatic Field Level Security (FLS) and CRUD checks. It uses a fluent API pattern where you construct your requirements by chaining configuration methods before executing the final DML operation.

    Workflow:

    1. Instantiate the class: new Safely()
    2. Chain configuration options (e.g., .allOrNothing(), .throwIfRemovedFields()).
    3. Call an execution method (e.g., .doInsert(records)).

    This ensures that security decisions (like field access) are respected and provides options for how to handle partial successes or field removals during the process.

    new Safely().allOrNothing().doInsert(myRecords);
  5. Use the IterableApiClient class for paginated REST APIs

    main

    The IterableApiClient class is a specialized REST client designed to handle paginated API responses. It implements the Iterable<RecordPage> interface, allowing you to use an iterator to load paginated records (represented as strings) sequentially. This class inherits from RestClient and is useful when you need to traverse large datasets from an external service that uses pagination.

    To use it, instantiate the class by providing the name of a Salesforce Named Credential.

    // Example instantiation
    IterableApiClient client = new IterableApiClient('My_Named_Credential');
  6. How the TriggerHandler framework works

    main

    The TriggerHandler is a virtual base class designed to provide an opinionated framework for managing Apex triggers. It uses a brokering pattern where the trigger itself calls a single run() method on a handler implementation. The framework manages execution context (via TriggerContext), prevents infinite recursion through a loop counting mechanism, and allows for conditional bypassing of specific handlers globally.

    To use it, you create a subclass of TriggerHandler and override the specific context methods (like beforeInsert, afterUpdate, etc.) that contain your business logic. The trigger code then simply invokes the run() method of your handler class.

    // In your Trigger:
    AccountTriggerHandler.run();
    
    // In your Handler implementation:
    public class AccountTriggerHandler extends TriggerHandler {
        protected override void afterInsert() {
            // Your logic here
        }
    }
  7. How the MetadataTriggerHandler framework works

    main

    The MetadataTriggerHandler is a unified trigger handler class that uses Custom Metadata to drive execution. Instead of hardcoding logic in a single trigger, you use the Metadata_Driven_Trigger__mdt custom metadata type to define which handler classes should run for a specific sObject and in what order.

    Workflow

    1. The Trigger: An sObject trigger (e.g., AccountTrigger) invokes the handler using new MetadataTriggerHandler().run();.
    2. Metadata Lookup: The class queries Metadata_Driven_Trigger__mdt records associated with that sObject.
    3. Execution: The class loops through the metadata records based on their Execution_Order__c, instantiates the classes specified in Class__c, and calls the appropriate context methods (like afterUpdate()).

    Custom Metadata Schema (Metadata_Driven_Trigger__mdt)

    FieldTypeDescription
    Object__cMetadata LookupA lookup to the sObject (e.g., Account)
    Execution_Order__cIntegerDetermines the order of execution
    Class__cStringThe name of the Trigger Handler class to execute

    Best Practices

    • Single Responsibility: It is better to have many small, singularly focused trigger handler classes rather than a few large classes with multiple methods.
    • Ordering: This framework does not allow you to re-arrange the trigger work of managed packages or the order of methods within a single handler class.
    // Example: Invoking the handler from an sObject trigger
    AccountTrigger.trigger {
        new MetadataTriggerHandler().run();
    }
  8. TriggerHandler lifecycle methods

    main

    The TriggerHandler class (which PlatformEventRecipesTriggerHandler inherits) provides several virtual methods that can be overridden to handle different trigger contexts. These methods are marked as TESTVISIBLE and SUPPRESSWARNINGS:

    • beforeInsert()
    • beforeUpdate()
    • beforeDelete()
    • afterInsert()
    • afterUpdate()
    • afterDelete()
    • afterUndelete()
  9. Use the PermissionCache class to optimize FLS checks

    main

    The PermissionCache class implements the Cache.CacheBuilder interface to prevent redundant Schema.Describe* calls. It caches per-object Field Level Security (FLS) results, allowing the CanTheUser class to reuse previously calculated permissions for the same object type.

    Key functionality includes:

    • calculateFLS(objType): Computes the FLS for a specific object type.
    • doLoad(objType): The required interface method used to either calculate or retrieve the FLS from the cache. It returns a data structure mapping FieldName -> FLSType -> Boolean.
    // The return structure for doLoad is:
    // Map<String, Map<FLSType, Boolean>>
    // Representing: FieldName -> FLSType -> True/False