Newer Version Available

This content describes an older version of this product. View Latest

SOAP Calls

Use SOAP if you’re using a strongly typed language like Java that generates Web service client code. For details about usage, syntax, and authentication, see the SOAP API Developer's Guide.

To access the Tooling API WSDL, from Setup, enter API in the Quick Find box, then select API and click Generate Tooling WSDL.

Like the Salesforce SOAP API, Tooling API uses the following calls.

create()
Adds one or more records to your organization’s data.
delete()
Deletes one or more records from your organization’s data.
describeLayout()
Retrieve metadata about page layouts for a specified SOjbect.
describeGlobal()
Lists the available Tooling API objects and their metadata.
describeSObjects()
Describes the metadata (field list and object properties) for the specified object or array of objects.

Call describeGlobal() to retrieve a list of all Tooling API objects for your organization, then iterate through the list and use describeSObjects() to obtain metadata about individual objects.

describeValueType()
Describes the metadata for a specified namespace and value type. For information about describeValueType, see the Metadata API Developer Guide.
describeWorkitemActions()
Describes which actions are available for a specified work item.
executeanonymous(string apexcode)
Executes the specified block of Apex anonymously and returns the result.
query()
Executes a query against a Tooling API object and returns data that matches the specified criteria.
queryMore()
Retrieves the next batch of objects from a query().
retrieve()
Retrieves one or more records based on the specified IDs.
runTests()
Runs one or more methods within an Apex class, using the synchronous test execution mechanism. All test methods in a synchronous test run must be in the same class.
The synchronous runTests() call accepts a RunTestsRequest object.
For sample code and more information, see Apex Developer Guide: runTests().
runTestsAsynchronous()
Runs one or more methods within one or more Apex classes, using the asynchronous test execution mechanism.
This example shows the structure of a call to a class that calls the runTestsAsynchronous endpoint.
1conn.runTestsAsynchronous(classids, suiteids, maxFailedTests, testLevel.value)

For more runTestsAsynchronous() example code, see ApexTestQueueItem.

The classids and suiteids parameters must both be specified for runTestsAsynchronous. To provide a value for only one of the two, specify the other as null. To use TestLevel.RunLocalTests or TestLevel.RunAllTestsInOrg, specify both classids and suiteids as null.

A value for maxFailedTests is mandatory. To allow all tests in your org to run, regardless of how many tests fail, set maxFailedTests to -1. To stop the test run from executing new tests after a given number of tests fail, set maxFailedTests to an integer value from 0 to 1,000,000. This integer value sets the maximum allowable test failures. A value of 0 causes the test run to stop if any failure occurs. A value of 1 causes the test run to stop on the second failure, and so on. Keep in mind that high values can cause slow performance. Each 1,000 tests that you add to your maxFailedTests value adds about 3 seconds to your test run, not including the time that the tests take to execute.

The testLevel parameter is available and required in API version 37.0 and later, but its value can be null. Other permissible values include:
RunSpecifiedTests
Only the tests that you specify are run.
RunLocalTests
All tests in your org are run, except the ones that originate from installed managed packages.
Omit identifiers for specific tests when you use this value.
RunAllTestsInOrg
All tests are run. The tests include all tests in your org, including tests of managed packages.
Omit identifiers for specific tests when you use this value.

The testLevel parameter isn’t available in API version 36.0 and earlier.

search()
Search for records that match a specified text string.
update()
Updates one or more existing records in your org’s data.
upsert()
Creates records and updates existing records; uses a custom field to determine the presence of existing records.

SOAP Headers

The SOAP headers available in the Tooling API WSDL are described in SOAP Headers for Tooling API.

Examples

These examples use C#, but you can use any language that supports Web services.

To compile Apex classes or triggers in Developer Edition or sandbox organizations, use create(). The next sample uses ApexClass to compile a simple class with a single method called SayHello.
1String classBody = "public class Messages {\n"
2      + "public string SayHello() {\n"
3      + " return 'Hello';\n" + "}\n"
4      + "}";
5
6   // create an ApexClass object and set the body 
7   ApexClass apexClass = new ApexClass();
8   apexClass.Body = classBody;
9   ApexClass[] classes = { apexClass };
10
11   // call create() to add the class
12   SaveResult[] saveResults = sforce.create(classes);
13   for (int i = 0; i < saveResults.Length; i++)
14      {
15      if (saveResults[i].success)
16         {
17           Console.WriteLine("Successfully created Class: " +
18            saveResults[i].id);
19         }
20      else
21         {
22            Console.WriteLine("Error: could not create Class ");
23            Console.WriteLine("   The error reported was: " +
24            saveResults[i].errors[0].message + "\n");
25         }
26      }

The IsCheckOnly parameter on ContainerAsyncRequest indicates whether an asynchronous request compiles code but doesn’t execute or save it (true), or compiles and save the code (false).

The next example expands upon the first by modifying the SayHello() method to accept a person’s first and last name. This example uses MetadataContainer with ApexClassMember to retrieve and update the class, and ContainerAsyncRequest to compile and deploy the changes to the server. You can use the same method with ApexTriggerMember, ApexComponentMember, and ApexPageMember.
To test your code, modify the IsCheckOnly parameter in the next sample, and log in to your organization after a successful execution to verify the results.
  • When IsCheckOnly = true, the SayHello() method remains the same. ApexClassMember contains the compiled results, but the class on the server remains the same.
  • When IsCheckOnly = false, the SayHello() method shows the change to accept a person’s first and last name.

Note

1String updatedClassBody = "public class Messages {\n"
2    + "public string SayHello(string fName, string lName) {\n"
3    + " return 'Hello ' + fName + ' ' + lName;\n" + "}\n"
4    + "}";
5
6 //create the metadata container object
7 MetadataContainer Container = new MetadataContainer();
8 Container.Name = "SampleContainer";
9
10 MetadataContainer[] Containers = { Container };
11 SaveResult[] containerResults = sforce.create(Containers);
12 if (containerResults[0].success)
13 {
14    String containerId = containerResults[0].id;
15
16    //create the ApexClassMember object
17    ApexClassMember classMember = new ApexClassMember();
18    //pass in the class ID from the first example
19    classMember.ContentEntityId = classId;
20    classMember.Body = updatedClassBody;
21    //pass the ID of the container created in the first step
22    classMember.MetadataContainerId = containerId;
23    ApexClassMember[] classMembers = { classMember };
24
25    SaveResult[] MembersResults = sforce.create(classMembers);
26    if (MembersResults[0].success)
27    {
28       //create the ContainerAsyncRequest object
29       ContainerAsyncRequest request = new ContainerAsyncRequest();
30       //if the code compiled successfully, save the updated class to the server
31       //change to IsCheckOnly = true to compile without saving 
32       request.IsCheckOnly = false;
33       request.MetadataContainerId = containerId;
34       ContainerAsyncRequest[] requests = { request };
35       SaveResult[] RequestResults = sforce.create(requests);
36       if (RequestResults[0].success)
37       {
38          string requestId = RequestResults[0].id;
39
40          //poll the server until the process completes
41          QueryResult queryResult = null;
42          String soql = "SELECT Id, State, ErrorMsg 
43                         FROM ContainerAsyncRequest 
44                         Where id = '" + requestId + "'";
45          queryResult = sforce.query(soql);
46          if (queryResult.size > 0)
47          {
48             ContainerAsyncRequest _request = (ContainerAsyncRequest)queryResult.records[0];
49             while (_request.State.ToLower() == "queued")
50             {
51                //pause the process for 2 seconds
52                Thread.Sleep(2000);
53
54                //poll the server again for completion
55                queryResult = sforce.query(soql);
56                _request = (ContainerAsyncRequest)queryResult.records[0];
57             }
58
59             //now process the result
60             switch (_request.State)
61             {
62                case "Invalidated":
63                   break;
64
65                case "Completed":
66                //class compiled successfully
67                //see the next example on how to process the SymbolTable 
68                   break;
69
70                case "Failed":
71             . .   break;
72
73                case "Error":
74                   break;
75
76                case "Aborted":
77                   break;
78
79                }
80             }
81             else
82             {
83                //no rows returned
84             }
85          }
86          else
87          {
88             Console.WriteLine("Error: could not create ContainerAsyncRequest object");
89             Console.WriteLine("   The error reported was: " +
90             RequestResults[0].errors[0].message + "\n");
91          }
92       }
93       else
94       {
95          Console.WriteLine("Error: could not create Class Member ");
96          Console.WriteLine("   The error reported was: " +
97          MembersResults[0].errors[0].message + "\n");
98       }
99    }
100    else
101    {
102    .. Console.WriteLine("Error: could not create MetadataContainer ");
103       Console.WriteLine("   The error reported was: " +
104       containerResults[0].errors[0].message + "\n");
105    }
106 }

To access Apex class and trigger data in a structured format, use a SymbolTable.

The next sample queries the ApexClassMember object created in the previous example to obtain the SymbolTable of the modified class.

The SOQL statement used depends on when the data is retrieved.

  • To execute the query from within the previous sample, use the ID of the ContainerAsyncRequest. For example, SELECT Body, ContentEntityId, SymbolTable FROM ApexClassMember where MetadataContainerId = '" + requestId + "'"
  • Otherwise, use the ID of the modified class as shown in the next sample. For example, SELECT ContentEntityId, SymbolTable FROM ApexClassMember where ContentEntityId = '" + classId + "'"

Note

1//use the ID of the class from the previous step
2   string classId = "01pA00000036itIIAQ";
3   QueryResult queryResult = null;
4   String soql = "SELECT ContentEntityId, SymbolTable FROM ApexClassMember where ContentEntityId = '" + classId + "'";
5
6   queryResult = sforce.query(soql);
7   if (queryResult.size > 0)
8   {
9      ApexClassMember apexClass = (ApexClassMember)queryResult.records[0];
10      SymbolTable symbolTable = apexClass.SymbolTable;
11
12      foreach (Method _method in symbolTable.methods)
13      {
14         //here's the SayHello method
15         String _methodName = _method.name;
16
17         //report the modifiers on the method such as global, public, private, or static
18         String _methodVisibility = _method.modifiers;
19
20         //get the method's return type
21         string _methodReturnType = _method.returnType;
22
23         //get the fName & lName parameters
24         foreach (Parameter _parameter in _method.parameters)
25         {
26            string _paramName = _parameter.name;
27            string _parmType = _parameter.type;
28         }
29      }
30   }
31   else
32   {
33      //unable to locate class
34   }

To add checkpoints to your code for debugging, use ApexExecutionOverlayAction.

This sample adds a checkpoint to the class from the previous samples:
1//use the ID of the class from the first sample.
2   string classId = "01pA00000036itIIAQ";
3
4   ApexExecutionOverlayAction action = new ApexExecutionOverlayAction();
5   action.ExecutableEntityId = classId;
6   action.Line = 3;
7   action.LineSpecified = true;
8   action.Iteration = 1;
9   action.IterationSpecified = true;
10   ApexExecutionOverlayAction[] actions = { action };
11
12   SaveResult[] actionResults = sforce.create(actions);
13   if (actionResults[0].success)
14   {
15      // checkpoint created successfully
16   }
17   else
18   {
19      Console.WriteLine("Error: could not create Checkpoint ");
20      Console.WriteLine("   The error reported was: " +
21      actionResults[0].errors[0].message + "\n");
22   }