Closed afawcett closed 10 years ago
There is certainly a few interesting operations on the SOAP API, that are not documented. Considering the CRUD operations don't work on standard/custom objects and likewise Salesforce API doesn't work on the tooling api objects. The inclusion of the getUpdated and getDeleted (the Replication API operations) hints that we can get a history from the org of changes made, these don't feature in the REST API version.
Yep found a few more SOAP only ones, invalidateSessions, describeWorkitemActions, getServerTimestamp, getUserInfo. I guess we could provide these methods via the SOAP API, the consumer of the API need not necessarily be aware of us using the REST or SOAP end points.
I've asked Thomas Dvornik, the Salesforce developer working on this API to comment on the above findings. Lets see what thoughts he has.
Wow, nice find. In the mean time, I'm just hammering out the REST methods we can use. So far I've tackled the easy ones, next step is the slightly more complicated stuff for creating Apex Members, etc.
Now that I'm subscribed to this thread I should start being able to follow it more closely, rather than get back to you within 12 days :)
Ha no worries, i am also finding the REST API's (unless i'm missing something, may try list payload) are not bulkified, for example the Create,Update and Delete operations.... hmmmm....maybe have to consider hyrbid for some of these. Will press on for the mo with REST though, chat next time your online...
The completion call will eventually come to SOAP. It also doesn't currently support XML serialization, which will come sooner than a SOAP completion operation.
Supporting getUpdated and getDeleted calls in REST are not on the road map. I'm actually surprised they are there and would be even more surprised if they returned anything. I did a quick search and didn't find anything, so you'll probably have to try them to see if they do anything.
Like the previous two methods, invalidateSessions, describeWorkitemActions, getServerTimestamp, getUserInfo most likely got included since we are using the same SOAP infrastructure. In other words, we got them for free. There are also no plans to include these in REST. However, we want parity so they will get in there eventually, but most likely later than sooner.
Thanks @amphro much appreciated! I will for sure be trying out the getUpdated and getDeleted calls, some very cool use cases around those if they do what i hope they will do! ;-)
Oh btw, @amphro am i correct in thinking the REST API is not bulkified? As in we can only pass on record at a time for example on a POST?
Awesome. Keep me posted. If they don't work how you hope, maybe we can add it to the roadmap, especially depending on the use case.
You are correct, the REST API is not bulkified. That is one of the main purposes of containers, as well as to get rid of zip deploys. Multiple request, single transaction. However, this doesn't help for non-container member entities. For example, I want to delete all apex logs. No plan to solve that at the moment. Do you have a big need for it or just a nice to have?
As per @amphro feedback, these additional methods in SOAP are common to all SOAP API's in Salesforce. So not specifically related to Tooling API.
RE: getUpdated and getDeleted, these do work for things like ApexClass, ApexPage, StaticResource etc, but offer no more functionality than the native ones, both reject the CustomObject and CustomField object names if passed, which are the two i really wanted in order to implement a Setup Monitoring solution, shame! :-1:
For safe keeping, the following is the partial SOAP types and methods i added to ToolingAPI temporarily to test this out, just in case we want to add some SOAP operations back in in the future...
Test code...
ToolingAPI toolingAPI = new ToolingAPI();
toolingAPI.SessionHeader = new ToolingAPI.SessionHeader_element();
toolingAPI.SessionHeader.sessionId = UserInfo.getSessionId();
ToolingAPI.GetUpdatedResult updatedResult =
toolingAPI.getUpdated('CustomObject', Datetime.now().addHours(-1), Datetime.now());
System.debug(updatedResult);
Stub code...
public Map<String,String> inputHttpHeaders_x;
public Map<String,String> outputHttpHeaders_x;
public SessionHeader_element SessionHeader;
public Integer timeout_x;
private String SessionHeader_hns = 'SessionHeader=urn:tooling.soap.sforce.com';
private String[] ns_map_type_info = new String[]{'urn:tooling.soap.sforce.com', 'toolingSoapSforceCom'};
public class SessionHeader_element {
public String sessionId;
private String[] sessionId_type_info = new String[]{'sessionId','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:tooling.soap.sforce.com','true','false'};
private String[] field_order_type_info = new String[]{'sessionId'};
}
public class getUpdated_element {
public String sObjectType;
public DateTime start;
public DateTime end_x;
private String[] sObjectType_type_info = new String[]{'sObjectType','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] start_type_info = new String[]{'start','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] end_x_type_info = new String[]{'end','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:tooling.soap.sforce.com','true','false'};
private String[] field_order_type_info = new String[]{'sObjectType','start','end_x'};
}
public class getUpdatedResponse_element {
public GetUpdatedResult result;
private String[] result_type_info = new String[]{'result','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:tooling.soap.sforce.com','true','false'};
private String[] field_order_type_info = new String[]{'result'};
}
public class GetUpdatedResult {
public String[] ids;
public DateTime latestDateCovered;
private String[] ids_type_info = new String[]{'ids','urn:tooling.soap.sforce.com',null,'0','-1','false'};
private String[] latestDateCovered_type_info = new String[]{'latestDateCovered','urn:tooling.soap.sforce.com',null,'1','1','false'};
private String[] apex_schema_type_info = new String[]{'urn:tooling.soap.sforce.com','true','false'};
private String[] field_order_type_info = new String[]{'ids','latestDateCovered'};
}
public GetUpdatedResult getUpdated(String sObjectType,DateTime start,DateTime end_x) {
getUpdated_element request_x = new getUpdated_element();
getUpdatedResponse_element response_x;
request_x.sObjectType = sObjectType;
request_x.start = start;
request_x.end_x = end_x;
Map<String, getUpdatedResponse_element> response_map_x = new Map<String, getUpdatedResponse_element>();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
this,
request_x,
response_map_x,
new String[]{URL.getSalesforceBaseUrl().toExternalForm()+'/services/Soap/T/29.0',
'',
'urn:tooling.soap.sforce.com',
'getUpdated',
'urn:tooling.soap.sforce.com',
'getUpdatedResponse',
'ToolingAPI.getUpdatedResponse_element'}
);
response_x = response_map_x.get('response_x');
return response_x.result;
}
We have agree to close this for v1 release, it will not include update is the only significant omission, initial use cases around Apex UML (grabbing Symbol Table) are quite advanced and didn't need it in the end.
Just reviewing the REST vs SOAP docs, ironically further to our decision to go with REST, the SOAP version does not seem to support the 'completion' call? I was wondering about not bothering with some things like describe. However it feasible that someone may want to use this wrapper against another org, like a sandbox or other de org.