Part One: SOAP-based APIs
Simple Object Access Protocol (SOAP) is a messaging protocol based on requests and responses using an XML format. Although some legacy systems still use SOAP over SMTP, the transport method typically used for SOAP requests is HTTP. As an API protocol, SOAP is platform- and language-agnostic, allowing for two applications running on completely different systems to communicate with one another.
This post is part of a two-part series covering how to create custom API endpoints in Salesforce with APEX. In Part One, we’ll walk through how to create a SOAP-based API endpoint for other applications to use when communicating with your Salesforce org.
A Brief Introduction to SOAP
Each SOAP message is contained in an “envelope” which has a header and a body. The header contains application-related information, such as the date when the message was generated or ids related to the message context. The body contains the actual message. Here is an example SOAP message with a format that would be used for authenticating to Salesforce:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
<soapenv:Header>
<urn:LoginScopeHeader>
<urn:organizationId>12345</urn:organizationId>
<urn:portalId>abcde</urn:portalId>
</urn:LoginScopeHeader>
</soapenv:Header>
<soapenv:Body>
<urn:login>
<urn:username>johndoe</urn:username>
<urn:password>mypassword</urn:password>
</urn:login>
</soapenv:Body>
</soapenv:Envelope>
Since each message has the same structure, SOAP is system agnostic. For example, an application running on a Windows 11 machine can send a message to another application running on a Unix-based web server.
Though the message can be sent using SMTP or HTTP, SOAP messages should ideally be sent with HTTPS, with either simple or mutual authentication.
SOAP is mostly used to create an API or web service to exchange server-to-server information. Therefore, it is very important for the two systems to establish trust. Salesforce provides multiple ways to accomplish authentication.
The relationship between SOAP and WSDL
Although all SOAP messages have the same structure, the SOAP specification doesn’t define other aspects, such as message format or transport protocol. The Web Services Description Language (WSDL) describes the message formats, transport details, and operations of the web service. The WSDL file can be considered a contract between the client and the service.
How to Create a SOAP-based API in Salesforce
Now that we have covered the fundamentals, let’s begin implementing our SOAP API.
Set up a Salesforce org
First, you need a Salesforce org. Salesforce provides free Developer edition orgs, and signing up for one is straightforward. Go to the sign-up page and provide your details. You should receive an invite link within a few minutes.
Creating a global class with Apex
To create a SOAP web service in Salesforce, we will need to create a globally defined Apex custom class. In our class, we’ll use the webservice
keyword and static
definition modifier for every method we want to expose. Adding the webservice
keyword automatically gives global access to the method it is added to.
In order to create this class in our shiny, new org, we go to Setup, and then find Custom Code -> Apex Classes. In the table listing existing classes, we click New.
To learn more about Apex and how to create classes, check out this Trailhead page and the Apex documentation.
Below, we have a sample ContactAPI
class that exposes a createContact
method used to create new Contact records in Salesforce. The method accepts a Contact’s details as parameters and inserts a new Contact record.
If successful, it returns the ID of the newly created Contact along with a message. In case of a failure, it returns an error message. Please copy the code and paste it into the newly created empty class.
global class ContactAPI {
webservice static String createContact (String firstName, String lastName, String contactEmail, String salutation) {
try {
Contact newContact = new Contact();
newContact.Salutation = salutation;
newContact.FirstName = firstName;
newContact.LastName = lastName;
newContact.Email = contactEmail;
insert newContact;
return 'Successfully inserted new Contact! Id:' + String.valueOf(newContact.Id);
} catch (Exception e) {
return 'Error:' + e.getMessage();
}
}
}
Next, we click Save.
That’s it! Our web service is ready for operations. We have successfully created a SOAP API in Salesforce.
Generate the WSDL
We now need to generate a WSDL file and provide it to the external application or third-party developers which can then consume it to call our createContact
method.
Salesforce provides two out-of-the-box WSDL files to integrate client applications with Salesforce:
- The Enterprise WSDL is optimized for a single Salesforce org. It’s strongly typed, meaning it contains objects and field definitions for this particular org. Whenever there is a change in the metadata (object and/or fields) in the Salesforce org, a new WSDL needs to be generated and provided to the client (to consume again).
- The Partner WSDL is optimized for use with many Salesforce orgs. It’s loosely typed, and it doesn’t change based on an org’s specific configuration.
In order to utilize our web service, we’ll use the WSDL for our Apex class (to actually call our web service), and we’ll use the Enterprise WSDL to authenticate to Salesforce.
After creating our ContactAPI
class, we see it show up in the list of Apex classes. In the row for ContactAPI, we click on the WSDL link to generate a WSDL.
This will open a new tab with our WSDL, which will look similar to this:
We save this file to our local machine, naming it contactAPI-wsdl.xml
.
To generate the Enterprise WSDL for our Salesforce org, we go to the Setup page, and then find Integrations -> API. Then, we click on Generate Enterprise WSDL.
Your generated WSDL should look similar to this:
We save this file to our local machine, naming it enterprise_wsdl.xml
.
To generate the WSDL for your Apex Class:
- Go to the Setup page.
- Type and select Apex Classes.
- Find your class. In our case it’s ContactAPI. Click on the name.
- On the next screen you will have the class page where you have the Generate WSDL button.
Test and validate
To ensure that the web service works, we’ll consume it by calling it from our web application and see if it responds correctly. We’ll also cover how to validate our API with unit testing.
Consume the API
For the purpose of this demo, we’ll use SoapUI, which is an open-source tool to test SOAP (and other protocols) web services. With SoapUI installed and running, we create a new SOAP Project, providing a name and selecting our enterprise_wsdl.xml
file as the initial WSDL.
We now have all available Salesforce SoapBindings listed on the left.
First, we need to authenticate our web application to Salesforce. We do this by using the login
call and providing our login credentials.
Use a security token
For added security, we also need to add a Security Token to our password to authenticate. We can get a security token by going to the Settings page and selecting Reset My Security Token on the left. Then, press the button with the same name. We will then receive our security token by email.
Log in with the token and credentials
With our token in hand, we select the login
SoapBinding in SoapUI. Ensure you have the correct URL depending on your org. If you just signed up for a developer account, the URL should be https://login.salesforce.com. If you are testing this in a Sandbox, then the URL should be https://test.salesforce.com. Ideally, the generated Enterprise WSDL will already have the correct URL.
For demo testing, we can comment out all other parameters except username and password.
We press the green Play button on the top left of the window to send the request. We receive a response that looks like this:
The critical pieces that we are looking for in the response are sessionId
and serverUrl
. In order to call our web service, we need to provide the sessionId
together with other parameters in our call. We copy down this sessionId
, as we will need this later.
Call our SOAP API
Let’s call our ContactAPI
class and create a Contact in Salesforce. To do this, we need to add our ContactAPI WSDL file, contactAPI-wsdl.xml
, to our project. We right-click on the project folder and select Add WSDL.
After adding the WSDL, it also appears in the left menu like below. Double-click on Request 1 to see the request. For this example, we can remove everything from the SOAP envelope header except for the SessionHeader
with sessionId
node.
After removing the unwanted nodes, we provide the sessionId
that we copied from our login call earlier. Then, in the Body
section of the envelope, we provide the details of the contact to be created.
We press the green Play button on the top left. Vóila! We have successfully created a Contact in Salesforce and received its Id
.
Check Salesforce org for new contact
Let’s look inside our Salesforce org to see if everything was created correctly. We go to our Salesforce org, click the App Launcher waffle icon on the left and then type Contact
in the search bar to find and select Contacts.
By default, we land on the Contacts page with the Recently Viewed Contacts list view. Click the down arrow and select either All Contacts or My Contacts list view.
Note: If you are in a Developer org, you will see a bunch of dummy Contacts (and other records) that Salesforce creates for you to test the platform.
We type the name of our newly created contact in the list search box on the right, and we see our new contact!
When we click on the Contact name, we end up on the Details page for that Contact.
Call our SOAP API with invalid data
Lastly, in order to ensure that our API is working properly, let’s send a bad request to see what we get as a response. We’ll simply send another request to our SOAP web service, but this time replace the .
in the email address with a ,
instead.
This time, we receive an error message (as we programmed in the API).
The entire error message reads like this:
Error:Insert failed. First exception on row 0; first error: INVALID_EMAIL_ADDRESS, Email: invalid email address: sheila@gmail,com: [Email]
This shows that our SOAP-based API is working as designed. With this foundation, we can build other SOAP-based APIs to create records for different objects.
Unit Testing
Besides consuming our SOAP-based API, another way to validate it works properly is through testing. Test Driven Development (TDD) is at the core of Salesforce development. To ensure stability and reliability of the platform, Salesforce requires your custom code to have a minimum of 75% code coverage via unit tests in order to deploy it to a production environment.
Let’s create some unit tests for our web service.
@isTest
private class TestContactWebService {
static testMethod void testInsertNewContact() {
// Create test data for positive test
String salutation = 'Mr.';
String firstName = 'Max';
String lastName = 'Bond';
String emailAddress = 'm.bond@mi5.gov.uk';
Test.startTest();
//Call the method with parameters
String result = ContactAPI.createContact(firstName, lastName, emailAddress, salutation);
Test.stopTest();
Contact newContact = [SELECT FirstName FROM Contact WHERE LastName = 'Bond'];
System.assertEquals(newContact.FirstName, 'Max', 'Assert Error: Please check the ContactAPI class');
}
static testMethod void testInsertNewContactFail() {
// Create test data for failing test
String salutation = 'Mr.';
String firstName = 'Max';
String lastName = 'Bond';
// The email address has , instead of .
String badEmailAddress = 'm.bond@mi5,gov,uk';
Test.startTest();
//Call the method with parameters
String result = ContactAPI.createContact(firstName, lastName, badEmailAddress, salutation);
Test.stopTest();
// This should contain the Error substring that we added to the catch block above.
System.assert(result.contains('Error:'), 'Fail Assert Error: Please check the ContactAPI class');
}
}
In our unit test, we created two scenarios: a “happy path” that verifies valid inputs result in a newly created Contact record, and a “sad path” where we expect the API to return an error on invalid inputs. Salesforce also provides a Trailhead on unit testing in Apex.
Conclusion
In this post, we only scratched the surface in terms of the capabilities that Salesforce provides when it comes to SOAP. As we saw, the generated Enterprise WSDL makes a long list of SoapBindings available. In addition, we can create our own custom classes and SOAP-based web services.
If you have a (legacy) application that uses SOAP to communicate with other systems, you now have the tools to connect that application to your Salesforce org. With enterprise-level security baked into the platform, you can be sure that your connection is safe and your data is protected.
In Part Two of our series, we’ll cover REST APIs, demonstrating how to use Apex to create a custom REST API endpoint for our Salesforce org.
Top comments (0)