a tough nut to crack

With the Spring ‘13 release of Salesforce.com comes an exciting new way of working with development metadata — the Tooling API.  This modern web service API, though still in its infancy, is expected eventually to replace the existing file-based API.  It will give third parties more flexibility building tools to support development on the Salesforce.com platform.  As is often the case with the release of new Salesforce features, the official documentation is rather scant.  Here are some pointers to help guide your experiments with the Tooling API.

The new Tooling API has a variety of interesting capabilities.  This includes the ability to overlay Apex or SOQL code on top of the system and view detailed debug log and heap dump information, which will facilitate rapid debugging.  Salesforce also provides detailed data on the structure of code, opening the door for tools to diagram your org, navigate your codebase, and highlight and autocomplete syntax. Utilizing such developer tools has the potential to significantly increase your team’s productivity, so it’s well worth making an investment in tooling.

The current Metadata API is primarily intended for deployments.  The Tooling API has been designed from the ground up to support the entire development lifecycle, including design, implementation, deployment, and maintenance.  This means many development tasks are much easier — things like incrementally modifying classes and debugging.

As with all of the REST-based APIs, the Tooling API requires that you authenticate before making requests.  While matters of authentication are outside the scope of this post, I found a tutorial from The Gazler to be quite helpful.  Once you’ve authenticated, it’s pretty straightforward to access and interact with the REST resources.

The examples below assume some familiarity with the command-line, but the ideas should be clear to anyone with experience developing on Force.com.  You can find the helper scripts we’ll use to make the low-level API calls on GitHub.

The Tooling API, as of the Spring ‘13 release, has support for only Apex classes, components, pages and triggers.  It is my assumption that future releases will support more types of metadata.  There are three categories of resources available from the Tooling API which represent the code files, deployment operations and support functions.

# list the Tooling API resources
./get.sh tooling/sobjects

The result of this call is the list of resources as JSON.

{
  "encoding": "UTF-8",
  "maxBatchSize": 200,
  "sobjects":
  [
    {
      "name": "ApexClassMember",
      "label": "Metadata Container Member",
      "keyPrefix":"400"
      …

Look at the field information for an sObject.

# describe a resource type
./get.sh tooling/sobjects/ApexClassMember/describe

Getting into the workflow of using the Tooling API takes a bit.  The objects provided do not directly represent the underlying Apex components, but rather a theoretical deployment item.  Creating an ApexClassMember, for instance, does not create the corresponding ApexClass immediately, but rather waits for the deployment to be executed.

# find a class and create a deployment item for it
./get.sh tooling/query?q=SELECT+Id,+Name,+Body+FROM+ApexClass
vim updatedClassInfo.json
./post.sh tooling/sobjects/ApexClassMember updatedClassInfo.json POST

That deployment execution is taken care of with two more resource types.  First is the MetadataContainer object, which simply holds all the components that will be deployed together.  These containers must have a unique name, but have no other properties.  Once you have created a container, you can begin to add various deployment components to it, and after adding the components create a ContainerAsyncRequest, which notifies the system that you are ready to deploy.

# create the container
echo ‘{ “name”: “My New Metadata Container” }’ > data.json
./post.sh tooling/sobjects/MetadataContainer data.json POST

The deployment request object has several important fields.  You may set the IsCheckOnly flag to indicate that the package should be validated but not deployed, and a reserved field named IsRunTests may be available in the future for ensuring that tests are run.

# create the deployment request
vim deploymentRequest.json
./post.sh tooling/sobjects/ContainerAsyncRequest deploymentRequest.json POST

The status of the request is obtained by querying for the newly inserted request object: the State field will change from ‘Queued’ to ‘Completed’ once the request has been successfully processed.  If there are any compilation failures or other errors, they will be recorded in the CompilerErrors and ErrorMsg fields.

# query for the results
./get.sh tooling/sobjects/ContainerAsyncRequest/REQUEST_ID

Once you’ve successfully validated or deployed a metadata container, the container contents are updated with some useful information.  On a successful deployment, the MetadataContainerId field will be updated with the id of the deployment request.  This means you cannot simply make further updates to the ApexClassMember and redeploy, you must insert a new one.

In addition, an exciting field called SymbolTable will be populated, which holds a JSON representation of all variable, function, and class references in the file.  Access to the symbol table enables developers to reliably determine line and column numbers of each symbol, which opens the door for syntax highlighters, code navigators, and tools that analyze the cohesion and coupling of Apex classes.

# query for the symbol table
./get.sh tooling/query?q=SELECT+Id,+ApexClass.Name,+SymbolTable+FROM+ApexClassMember

Using the Force.com Tooling API is not easy.  The API is still rough, and the documentation is terse.  However, the possibilities afforded by this new API may make the effort of investigation well worth it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>