Being a Salesforce developer, you often get requirements which needs customization. You choose Triggers, Batch, Visualforce, Lightning Components and what not, depending on the need.

In case of Apex Triggers, before developing, you must be sure of,

  • On which object the trigger has to be written
  • Context (Eg: after insert, before update)
  • Content as per technical approach

Say, you have to update the description when an opportunity’s probability is greater than 50% but less than 100%. You write trigger on Opportunity (before insert, before update).

Let’s consider another scenario:

You have requirement of performing a action on creation of record for any object. You want to use Trigger and you write an utility class which can work for any object. The challenge is, you are unaware of the objects(specially custom objects) presented. How can you write a trigger beforehand which works for admin selected object!

You may provide two options for the Admin:

  1. Build a VF page to select from list of triggerable objects. On selection, generate and show the intended snippet of trigger body to use the utility code on the page. Admin can copy the snippet and create a respective trigger manually and paste the code as the trigger body(or embed the snippet in an existing trigger at the right place, if he has bit of technical knowledge)
  2. Build a VF page to select from list of triggerable objects. On selection, enable “Create Trigger” button. On click of the button, create the trigger in backend with respective snippet and show the status of the trigger creation for the selected objects.

Basically, you want to write a trigger dynamically, if we stick to the second option. You cannot do this programmatically as you don’t have any built in Apex method to do such stuff. But, Salesforce provides set of REST resources which we can make use of.

Below is the utility class to create dynamic trigger:

public class ApexTrigger_REST
{
    /* NOTE: Make sure you add  https://YOUR_INSTANCE.salesforce.com or https://DOMAIN_NAME in remote setting.*/
    private static String endPoint = URL.getSalesforceBaseUrl().toExternalForm()  + '/services/data/v41.0/sobjects';
    /* This method creates apex trigger via callout to ApexTrigger REST Resource */
    public static String createApexTrigger(TriggerInfoWrapper objTriggerInfo)
    {
        // create a Http request with post method
        HttpRequest req = createHttpRequest(endPoint+'/ApexTrigger','POST');
        // set body with serialized trigger info
        req.setBody(JSON.serialize(objTriggerInfo));
        // send request and receive response
        String response = fetchResponse(req);
        return response;
    }
     /* This method returns only triggerable object infos via callout to sobjects REST Resource */
    public static Map<String, String> fetchTriggerableObjInfo()
    {
        // hold returned response objects info
        Map<String, String> mapObjectMapping = new Map<String, String>();
        // create a Http request with post method
        HttpRequest req = createHttpRequest(endPoint, 'GET');
        // send request and receive response
        String response = fetchResponse(req);
        // extract triggerable info
        Map<String, Object> body = (Map<String, Object>)JSON.deserializeUntyped(response);
        List<Object> objs = (List<Object>) body.get('sobjects');
        for (Object obj : objs)
        {
            Map<String, Object> objDesc = (Map<String, Object>)(obj);
            String name = (String) objDesc.get('name');
            Boolean isTriggerable = (Boolean) objDesc.get('triggerable');
            if(isTriggerable)
            {
                // construct mapping
                mapObjectMapping.put(name, (String) objDesc.get('label'));
            }
            System.debug(System.LoggingLevel.ERROR, name + ': ' + isTriggerable);
        }
        return mapObjectMapping;
    }
    /* This method returns response of an http request */
    private static String fetchResponse(HttpRequest req)
    {
        Http objHttp = new Http();
        HttpResponse res = objHttp.send(req);
        return res.getBody();
    }
    /* This method creates a http request with required endpoint and request method */
    private static HttpRequest createHttpRequest(String endpoint, String method)
    {
        HttpRequest req = new HttpRequest();
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type', 'application/json');
        req.setEndpoint(endpoint);
        req.setMethod(method);
        return req;
    }
    /* Wraper class to hold trigger information which needs to be set as body while creating trigger */
    public class TriggerInfoWrapper
    {
        // Trigger Name
   public String Name;
        // Object Name on which trigger has to be created
        public String TableEnumOrId;
        // Trigger body
        public String Body;
        public TriggerInfoWrapper(String objName, String triggerName, String triggerBody)
        {
            this.Name = triggerName;
            this.TableEnumOrId = objName;
            this.Body = triggerBody;
        }
    }
}

Let’s say you want to write a trigger on Account with the name “MyTestTrigger”, invocation will be like this:

ApexTrigger_REST.TriggerInfoWrapper obj = new ApexTrigger_REST.TriggerInfoWrapper('Account','MyTestTrigger','trigger MyTestTrigger on Account (after insert) {/*Your trigger body goes here*/}');

ApexTrigger_REST.createApexTrigger(obj);

Before creating a trigger, make sure whether the object is triggerable using a callout to another sobject describe resource like this:

ApexTrigger_REST.fetchTriggerableObjInfo();

Happy Coding!