How do I use the Tooling API to create a new Apex Trigger?

How do I use the Tooling API to create a new Apex Trigger (rather than update an existing one)?

According to the documentation I need to specify the ContentEntityId as an existing Trigger Id. But in my case I don’t have an Id because I’ve trying to create a new sObject.

If I omit the ContentEntityId I get an error back in the SaveResult:

Status Code: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY
Message: “insufficient access rights on cross-reference id”

The following is more or less a test case in C# that attempts to use the SOAP tooling API to create the new trigger.

SforceService toolingService = //... Get instance of the Tooling API

MetadataContainer container = new MetadataContainer();
container.Name = "Test" + DateTime.Now.Ticks;

SaveResult[] saveResult = toolingService.create(new sObject[] { container });
string metaDataContainerId = saveResult[0].id;

ApexTriggerMember apexTriggerMember = new ApexTriggerMember();
apexTriggerMember.MetadataContainerId = metaDataContainerId;
apexTriggerMember.Body = "trigger TestOpportunityBeforeUpdate on Opportunity (before update) {\n//Horray\n}";
    // Adding this will successfuly update the existing trigger
//apexTriggerMember.ContentEntityId = "01q70000000GuzP";

SaveResult[] triggerSaveResults = toolingService.create(new sObject[] { apexTriggerMember });
Assert.AreEqual(1, triggerSaveResults.Length);
SaveResult triggerSaveResult = triggerSaveResults[0];
if (!triggerSaveResult.success)
{
    Assert.Fail(triggerSaveResult.errors[0].message);
}
Assert.IsTrue(triggerSaveResult.success);

ContainerAsyncRequest containerRequest = new ContainerAsyncRequest();
containerRequest.MetadataContainerId = metaDataContainerId;
containerRequest.IsCheckOnly = false;

SaveResult[] containerResults = toolingService.create(new sObject[] { containerRequest });

Answer

It turns out that https://[instance].salesforce.com/services/data/v27.0/tooling/sobjects/ApexClass is a special case, and, in the general case (ApexComponent, ApexPage, ApexTrigger) you use the regular REST API sobject URL with the appropriate sObject type.

For ApexTrigger, this would be https://[instance].salesforce.com/services/data/v27.0/sobjects/ApexTrigger. So to create a trigger:

$ curl -H 'X-PrettyPrint: 1' -H 'Authorization: Bearer 00D...' \
    -H 'Content-Type: application/json' \
    -d '{ "Name" : "TestTrigger", \
          "TableEnumOrId" : "Opportunity",\
          "Body" : "trigger TestTrigger on Opportunity (after insert){}" }' \
    https://na15.salesforce.com/services/data/v27.0/sobjects/ApexTrigger
{
  "id" : "01qi0000000DKwyAAG",
  "success" : true,
  "errors" : [ ]
}

You can see all the code artifact sObject types listed if you GET https://[instance].salesforce.com/services/data/v27.0/sobjects:

$ curl -H 'X-PrettyPrint: 1' -H 'Authorization: Bearer 00Di0000000I4NV!ARgAQDLUBCU38O9RXONyu5C99tcHYYQCc7dOHW8i6ZiGEgPBxyKZwumKsdE69ElKM0ipCD4oCDYbOsmZKNJ3FUqUhsyFk3zu' https://na15.salesforce.com/services/data/v27.0/sobjects | grep \"name\"\ :\ \"Apex
    "name" : "ApexClass",
    "name" : "ApexComponent",
    "name" : "ApexLog",
    "name" : "ApexPage",
    "name" : "ApexTestQueueItem",
    "name" : "ApexTestResult",
    "name" : "ApexTrigger",

Attribution
Source : Link , Question Author : Daniel Ballinger , Answer Author : metadaddy

Leave a Comment