If you are not already a member of the Force.com developer community, go to http://developer.force.com/join and follow the instructions for signing up for a Developer Edition organization. Even if you already have Enterprise Edition or Unlimited Edition, use Developer Edition for developing, staging, and testing your solutions against sample data to protect your organization’s live data. This is especially true for applications that insert, update, or delete data (as opposed to simply reading data).
If you already have a Developer Edition organization, verify that you have the “API Enabled” permission. This permission is enabled by default, but may have been changed by an administrator. For more information, see the help in the Salesforce user interface.
To access the Force.com Web service, you need a Web Service Description Language (WSDL) file. The WSDL file defines the Web service that is available to you. Your development platform uses this WSDL to generate an API to access the Force.com Web service it defines. You can either obtain the WSDL file from your organization’s Salesforce administrator or you can generate it yourself if you have access to the WSDL download page in the Salesforce user interface. You can navigate to the most recent WSDL for your organization by clicking .
For more information about WSDL, see http://www.w3.org/TR/wsdl.
Any user with the “Modify All Data” permission can download the Web Services Description Language (WSDL) file to integrate and extend Salesforce using the API. (The System Administrator profile has this permission.)
The WSDL file is dynamically generated based on which type of WSDL file (enterprise or partner) you download. The generated WSDL defines all of the API calls, objects (including standard and custom objects), and fields that are available for API access for your organization.
To generate the WSDL file for your organization:
Once you have the WSDL file, you need to import it into your development platform so that your development environment can generate the necessary objects for use in building client Web service applications in that environment. This section provides sample instructions for WSC and Microsoft Visual Studio. For instructions about other development platforms, see your platform’s product documentation.
Java environments access the API through Java objects that serve as proxies for their server-side counterparts. Before using the API, you must first generate these objects from your organization’s WSDL file.
Each SOAP client has its own tool for this process. For WSC, use the wsdlc utility.
The basic syntax for wsdlc is:
java –classpath pathToJAR/wsc-20.jar com.sforce.ws.tools.wsdlc pathToWsdl/WsdlFilenamepathToJar/JarFilename
This command will generate a set of folders and Java source code files in the same directory in which it was run. After these files are compiled, they can be included in your Java programs for use in creating client applications.
Visual Studio languages access the API through objects that serve as proxies for their server-side counterparts. Before using the API, you must first generate these objects from your organization's WSDL file.
Once you have the proxy classes for the server-side objects, you need to ensure that you specify whether you have set any values on non-string fields. For more information, see Implementation Considerations.
Visual Studio provides two approaches for importing your WSDL file and generating an XML Web service client: an IDE-based approach and a command line approach.
An XML Web service client is any component or application that references and uses an XML Web service. This does not necessarily need to be a client-based application. In fact, in many cases, your XML Web service clients might be other Web applications, such as Web Forms or even other XML Web services. When accessing XML Web services in managed code, a proxy class and the .NET Framework handle all of the infrastructure coding.
To access an XML Web service from managed code:
file:///c:\WSDLFiles\enterprise.wsdl
Unfortunately, in the definition of the SObject class, Visual Studio does not wrap these to class references in the System.Xml.Serialization.XmlIncludeAttribute that are part of the SObject definition. To work around this problem in Visual Studio, you need to edit the XmlIncludeAttribute settings for Case and Event as shown below. This does not apply to C# and only applies when using the enterprise version of the WSDL.
Once you have imported your WSDL file, you can begin building client applications that use the API. Use the following samples to create a basic client application. Comments embedded in the sample explain each section of code.
This section walks through a sample Java client application that uses the WSC SOAP client. The purpose of this sample application is to show the required steps for logging into the login server and to demonstrate the invocation and subsequent handling of several API calls. This sample application performs the following main tasks:
Note the error handling code that follows each API call.
package com.example.samples; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.InputStreamReader; import java.io.IOException; import com.sforce.soap.enterprise.DeleteResult; import com.sforce.soap.enterprise.DescribeGlobalResult; import com.sforce.soap.enterprise.DescribeGlobalSObjectResult; import com.sforce.soap.enterprise.DescribeSObjectResult; import com.sforce.soap.enterprise.EnterpriseConnection; import com.sforce.soap.enterprise.Error; import com.sforce.soap.enterprise.Field; import com.sforce.soap.enterprise.FieldType; import com.sforce.soap.enterprise.GetUserInfoResult; import com.sforce.soap.enterprise.LoginResult; import com.sforce.soap.enterprise.PicklistEntry; import com.sforce.soap.enterprise.QueryResult; import com.sforce.soap.enterprise.SaveResult; import com.sforce.soap.enterprise.sobject.Account; import com.sforce.soap.enterprise.sobject.Contact; import com.sforce.soap.enterprise.sobject.SObject; import com.sforce.ws.ConnectorConfig; import com.sforce.ws.ConnectionException; public class QuickstartApiSample { private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); EnterpriseConnection connection; String authEndPoint = ""; public static void main(String[] args) { if ( args.length < 1 ) { System.out.println("Usage: com.example.samples." + "QuickstartApiSamples <AuthEndPoint>"); System.exit(-1); } QuickstartApiSample sample = new QuickstartApiSample(args[0]); if ( sample.login() ) { sample.describeGlobalSample(); sample.describeSample(); sample.querySample(); } } public QuickstartApiSample(String authEndPoint) { this.authEndPoint = authEndPoint; } public String getUserInput(String prompt) { String result = ""; try { System.out.print(prompt); result = reader.readLine(); } catch (IOException ioe) { ioe.printStackTrace(); } return result; } public boolean login() { boolean success = false; String userId = getUserInput("UserID: "); String passwd = getUserInput("Password: "); try { ConnectorConfig config = new ConnectorConfig(); config.setUsername(userId); config.setPassword(passwd); System.out.println("AuthEndPoint: " + authEndPoint); config.setAuthEndpoint(authEndPoint); config.setTraceFile("traceLogs.txt"); config.setTraceMessage(true); config.setPrettyPrintXml(true); connection = new EnterpriseConnection(config); GetUserInfoResult userInfo = connection.getUserInfo(); System.out.println("\nLogging in ...\n"); System.out.println("UserID: " + userInfo.getUserId()); System.out.println("User Full Name: " + userInfo.getUserFullName()); System.out.println("User Email: " + userInfo.getUserEmail()); System.out.println(); System.out.println("SessionID: " + config.getSessionId()); System.out.println("Auth End Point: " + config.getAuthEndpoint()); System.out.println("Service End Point: " + config.getServiceEndpoint()); System.out.println(); success = true; } catch (ConnectionException ce) { ce.printStackTrace(); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); } return success; } public void logout() { try { connection.logout(); System.out.println("Logged out"); } catch (ConnectionException ce) { ce.printStackTrace(); } } /** * To determine the objects that are available to the logged-in * user, the sample client application executes a describeGlobal * call, which returns all of the objects that are visible to * the logged-in user. This call should not be made more than * once per session, as the data returned from the call likely * does not change frequently. The DescribeGlobalResult is * simply echoed to the console. */ public void describeGlobalSample() { try { DescribeGlobalResult describeGlobalResult = connection.describeGlobal(); DescribeGlobalSObjectResult[] sobjectResults = describeGlobalResult.getSobjects(); for (int i = 0; i < sobjectResults.length; i++) { System.out.println(sobjectResults[i].getName()); } } catch (ConnectionException ce) { ce.printStackTrace(); } } /** * The following code segment illustrates the type of metadata * information that can be obtained for each object available * to the user. The sample client application executes a * describeSObject call on a given object and then echoes * the returned metadata information to the console. Object * metadata information includes permissions, field types * and length and available values for picklist fields * and types for referenceTo fields. */ private void describeSample() { String objectToDescribe = getUserInput("\nType the name of the object to " + "describe (try Account): "); try { DescribeSObjectResult describeSObjectResult = connection.describeSObject(objectToDescribe); if (describeSObjectResult != null) { Field[] fields = describeSObjectResult.getFields(); System.out.println("Metadata for the " + describeSObjectResult.getName() + " SObject" ); System.out.println("\tActivateable: " + describeSObjectResult.isActivateable() ); System.out.println("\tNumber of fields: " + fields.length ); if (fields != null) { for (Field field : fields) { String name = field.getName(); System.out.println("\tField name: " + field.getName() ); PicklistEntry[] picklistValues = field.getPicklistValues(); if (picklistValues != null && picklistValues.length > 0) { System.out.println("\t\tPicklist values: "); for (int j = 0; j < picklistValues.length; j++) { if (picklistValues[j].getLabel() != null) { System.out.println("\t\tValue: " + picklistValues[j].getLabel() ); } } } String[] referenceTos = field.getReferenceTo(); if (referenceTos != null && referenceTos.length > 0) { System.out.println("\t\tThis field references the " + "following objects:" ); for (int j = 0; j < referenceTos.length; j++) { System.out.println("\t\t" + referenceTos[j]); } } } } } } catch (ConnectionException ce) { ce.printStackTrace(); } } public void querySample() { try { String soqlQuery = "SELECT FirstName, LastName FROM Contact"; QueryResult result = connection.query(soqlQuery); boolean done = false; if (result.getSize() > 0) { System.out.println("\nLogged-in user can see " + result.getRecords().length + " contact records." ); while (! done) { SObject[] records = result.getRecords(); for ( int i = 0; i < records.length; ++i ) { Contact con = (Contact) records[i]; String fName = con.getFirstName(); String lName = con.getLastName(); if (fName == null) { System.out.println("Contact " + (i + 1) + ": " + lName ); } else { System.out.println("Contact " + (i + 1) + ": " + fName + " " + lName ); } } if (result.isDone()) { done = true; } else { result = connection.queryMore(result.getQueryLocator()); } } } else { System.out.println("No records found."); } System.out.println("\nQuery succesfully executed."); } catch (ConnectionException ce) { ce.printStackTrace(); } } }
This section walks through a sample C# client application. The purpose of this sample application is to show the required steps for logging in and to demonstrate the invocation and subsequent handling of several API calls.
This sample application performs the following main tasks:
All client applications that access the API must complete the tasks in this step before attempting any subsequent API calls.
In the following sample code, API calls and other significant code are identified in a bold font. In addition, note the error handling code that follows each API call.
The following code begins the sample C# client application.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Services.Protocols;
using Walkthrough.sforce;
namespace Walkthrough
{
class WalkthroughSample
{
private SforceService binding;
static private WalkthroughSample walkthroughSample;
[STAThread]
static void Main(string[] args)
{
walkthroughSample = new WalkthroughSample();
walkthroughSample.run();
}
public void run()
{
//Call the login call
if (login())
{
//Do a describe global
describeGlobal();
//describe an account object
describeSObject("account");
//retrieve some data using query
querySample();
}
}
private bool login()
{
Console.Write("Enter username: ");
string username = Console.ReadLine();
Console.Write("Enter password: ");
string password = Console.ReadLine();
// Create a service object
binding = new SforceService();
// Timeout after a minute
binding.Timeout = 60000;
// Try logging in
LoginResult lr;
try
{
Console.WriteLine("LOGGING IN NOW...");
lr = binding.login(username, password);
}
// ApiFault is a proxy stub generated from the WSDL contract when
// the web service was imported
catch (SoapException e)
{
// Write the fault code to the console
Console.WriteLine(e.Code);
// Write the fault message to the console
Console.WriteLine("An unexpected error has occurred: " + e.Message);
// Write the stack trace to the console
Console.WriteLine(e.StackTrace);
// Return False to indicate that the login was not successful
return false;
}
// Check if the password has expired
if (lr.passwordExpired)
{
Console.WriteLine("An error has occurred. Your password has expired.");
return false;
}
/** Once the client application has logged in successfully, it will use
* the results of the login call to reset the endpoint of the service
* to the virtual server instance that is servicing your organization
*/
binding.Url = lr.serverUrl;
/** The sample client application now has an instance of the SforceService
* that is pointing to the correct endpoint. Next, the sample client
* application sets a persistent SOAP header (to be included on all
* subsequent calls that are made with SforceService) that contains the
* valid sessionId for our login credentials. To do this, the sample
* client application creates a new SessionHeader object and persist it to
* the SforceService. Add the session ID returned from the login to the
* session header
*/
binding.SessionHeaderValue = new SessionHeader();
binding.SessionHeaderValue.sessionId = lr.sessionId;
// Return true to indicate that we are logged in, pointed
// at the right URL and have our security token in place.
return true;
}
private void describeGlobal()
{
//describeGlobal returns an array of object results that
//includes the object names that are available to the logged-in user
DescribeGlobalResult dgr = binding.describeGlobal();
Console.WriteLine("\nDescribe Global Results:\n");
//Loop through the array echoing the object names to the console
for (int i = 0; i < dgr.sobjects.Length; i++)
{
Console.WriteLine(dgr.sobjects[i].name);
}
Console.WriteLine("\n\nHit enter to continue...");
Console.ReadLine();
}
private void describeSObject(string objectType)
{
//Call the describeSObject passing in the object type name
DescribeSObjectResult dsr =
binding.describeSObject(objectType);
//The first properites we will echo are on the object itself
//First we will output some Descriptive info on the object
Console.WriteLine("\n\nObject Name: " + dsr.name);
if (dsr.custom) Console.WriteLine("Custom Object");
if (dsr.label != null) Console.WriteLine("Label: " + dsr.label);
//now the permissions on the object
if (dsr.activateable) Console.WriteLine("Activateable");
if (dsr.createable) Console.WriteLine("Createable");
if (dsr.deletable) Console.WriteLine("Deleteable");
if (dsr.queryable) Console.WriteLine("Queryable");
if (dsr.replicateable) Console.WriteLine("Replicateable");
if (dsr.retrieveable) Console.WriteLine("Retrieveable");
if (dsr.searchable) Console.WriteLine("Searchable");
if (dsr.undeletable) Console.WriteLine("Undeleteable");
if (dsr.updateable) Console.WriteLine("Updateable");
//Now we will retrieve meta-data about each of the fields
for (int i = 0; i < dsr.fields.Length; i++)
{
//Create field object for readability
Field field = dsr.fields[i];
//Echo some useful information
Console.WriteLine("Field name: " + field.name);
Console.WriteLine("\tField Label: " + field.label);
//This next property indicates that this
//field is searched when using
//the name search group in SOSL
if (field.nameField)
Console.WriteLine("\tThis is a name field.");
if (field.restrictedPicklist)
Console.WriteLine("This is a RESTRICTED picklist field.");
Console.WriteLine("\tType is: " + field.type.ToString());
if (field.length > 0)
Console.WriteLine("\tLength: " + field.length);
if (field.scale > 0)
Console.WriteLine("\tScale: " + field.scale);
if (field.precision > 0)
Console.WriteLine("\tPrecision: " + field.precision);
if (field.digits > 0)
Console.WriteLine("\tDigits: " + field.digits);
if (field.custom)
Console.WriteLine("\tThis is a custom field.");
//Output the permission on this field.
if (field.nillable) Console.WriteLine("\tCan be nulled.");
if (field.createable) Console.WriteLine("\tCreateable");
if (field.filterable) Console.WriteLine("\tFilterable");
if (field.updateable) Console.WriteLine("\tUpdateable");
//If this is a picklist field, we will show the values
if (field.type.Equals(fieldType.picklist))
{
Console.WriteLine("\tPicklist Values");
for (int j = 0; j < field.picklistValues.Length; j++)
Console.WriteLine("\t\t" + field.picklistValues[j].value);
}
//If this is a foreign key field (reference),
//we will show the values
if (field.type.Equals(fieldType.reference))
{
Console.WriteLine("\tCan reference these objects:");
for (int j = 0; j < field.referenceTo.Length; j++)
Console.WriteLine("\t\t" + field.referenceTo[j]);
}
Console.WriteLine("");
}
Console.WriteLine("\n\nHit enter to continue...");
Console.ReadLine();
}
private void querySample()
{
//The results will be placed in qr
QueryResult qr = null;
//We are going to increase our return batch size to 250 items
//Setting is a recommendation only, different batch sizes may
//be returned depending on data, to keep performance optimized.
binding.QueryOptionsValue = new QueryOptions();
binding.QueryOptionsValue.batchSize = 250;
binding.QueryOptionsValue.batchSizeSpecified = true;
try
{
qr = binding.query("select FirstName, LastName from Contact");
bool done = false;
if (qr.size > 0)
{
Console.WriteLine("Logged-in user can see "
+ qr.records.Length + " contact records.");
while (!done)
{
Console.WriteLine("");
for (int i = 0; i < qr.records.Length; i++)
{
Contact con = (Contact)qr.records[i];
string fName = con.FirstName;
string lName = con.LastName;
if (fName == null)
Console.WriteLine("Contact " + (i + 1) + ": " + lName);
else
Console.WriteLine("Contact " + (i + 1) + ": " + fName
+ " " + lName);
}
if (qr.done)
{
done = true;
}
else
{
qr = binding.queryMore(qr.queryLocator);
}
}
}
else
{
Console.WriteLine("No records found.");
}
}
catch (Exception ex)
{
Console.WriteLine("\nFailed to execute query succesfully," +
"error message was: \n{0}", ex.Message);
}
Console.WriteLine("\n\nHit enter to exit...");
Console.ReadLine();
}
}
}