Coming 2/25: New Trailhead Login Experience & Account Merge. Check out all the details here!.
close

Apex SOAP Callouts

Learning Objectives

After completing this module, you’ll be able to:
  • Generate Apex classes using WSDL2Apex.
  • Perform a callout to send data to an external service using SOAP.
  • Test callouts by using mock callouts.

Use WSDL2Apex to Generate Apex Code

In addition to REST callouts, Apex can also make callouts to SOAP web services using XML. Working with SOAP can be a painful (but necessary) experience. Fortunately, we have tools to make the process easier.

WSDL2Apex automatically generates Apex classes from a WSDL document. You download the web service’s WSDL file, and then you upload the WSDL and WSDL2Apex generates the Apex classes for you. The Apex classes construct the SOAP XML, transmit the data, and parse the response XML into Apex objects. Instead of developing the logic to construct and parse the XML of the web service messages, let the Apex classes generated by WSDL2Apex internally handle all that overhead. If you are familiar with WSDL2Java or with importing a WSDL as a Web Reference in .NET, this functionality is similar to WSDL2Apex. You’re welcome.

Note

Note

Use outbound messaging to handle integration solutions when possible. Use callouts to third-party web services only when necessary.

For this example, we’re using a simple calculator web service to add two numbers. It’s a groundbreaking service that is all the rage! The first thing we need to do is download the WSDL file to generate the Apex classes. Click this link and download the calculator.xml file to your computer. Remember where you save this file, because you need it in the next step.

Generate an Apex Class from the WSDL

  1. From Setup, enter Apex Classes in the Quick Find box, then click Apex Classes.
  2. Click Generate from WSDL.
  3. Click Choose File and select the downloaded calculator.xml file.
  4. Click Parse WSDL. The application generates a default class name for each namespace in the WSDL document and reports any errors.

    For this example, use the default class name. However, in real life it is highly recommended that you change the default names to make them easier to work with and make your code more intuitive.

    It’s time to talk honestly about the WSDL parser. WSDL2Apex parsing is a notoriously fickle beast. The parsing process can fail for several reasons, such as an unsupported type, multiple bindings, or unknown elements. Unfortunately, you could be forced to manually code the Apex classes that call the web service or use HTTP.

  5. Click Generate Apex code. The final page of the wizard shows the generated classes, along with any errors. The page also provides a link to view successfully generated code.

The generated Apex classes include stub and type classes for calling the third-party web service represented by the WSDL document. These classes allow you to call the external web service from Apex. For each generated class, a second class is created with the same name and the prefix Async. The calculatorServices class is for synchronous callouts. The AsyncCalculatorServices class is for asynchronous callouts.

Execute the Callout

Prerequisites

Before you run this example, authorize the endpoint URL of the web service callout, https://th-apex-soap-service.herokuapp.com, using the steps from the Authorize Endpoint Addresses section.

Now you can execute the callout and see if it correctly adds two numbers. Have a calculator handy to check the results.

  1. Open the Developer Console from the Setup gear (Setup gear icon).
  2. In the Developer Console, select Debug | Open Execute Anonymous Window.
  3. Delete all existing code and insert the following snippet.
    calculatorServices.CalculatorImplPort calculator = new  calculatorServices.CalculatorImplPort();
    Double x = 1.0;
    Double y = 2.0;
    Double result = calculator.doAdd(x,y);
    System.debug(result);
  4. Select Open Log, and then click Execute.
  5. After the debug log opens, click Debug Only to view the output of the System.debug statements. The log should display 3.0.

Test Web Service Callouts

All experienced Apex developers know that to deploy or package Apex code, at least 75% of that code must have test coverage. This coverage includes our classes generated by WSDL2Apex. You might have heard this before, but test methods don’t support web service callouts, and tests that perform web service callouts fail. So, we have a little work to do. To prevent tests from failing and to increase code coverage, Apex provides a built-in WebServiceMock interface and the Test.setMock method. You can use this interface to receive fake responses in a test method, thereby providing the necessary test coverage.

Specify a Mock Response for Callouts

When you create an Apex class from a WSDL, the methods in the autogenerated class call WebServiceCallout.invoke, which performs the callout to the external service. When testing these methods, you can instruct the Apex runtime to generate a fake response whenever WebServiceCallout.invoke is called. To do so, implement the WebServiceMock interface and specify a fake response for the testing runtime to send.

Instruct the Apex runtime to send this fake response by calling Test.setMock in your test method. For the first argument, pass WebServiceMock.class. For the second argument, pass a new instance of your WebServiceMock interface implementation.

Test.setMock(WebServiceMock.class, new MyWebServiceMockImpl());

That’s a lot to grok, so let’s look at some code for a complete example. In this example, you create the class that makes the callout, a mock implementation for testing, and the test class itself.

  1. In the Developer Console, select File | New | Apex Class.
  2. For the class name, enter AwesomeCalculator and then click OK.
  3. Replace autogenerated code with the following class definition.
    public class AwesomeCalculator {
        public static Double add(Double x, Double y) {
            calculatorServices.CalculatorImplPort calculator = 
                new calculatorServices.CalculatorImplPort();
            return calculator.doAdd(x,y);
        }
    }
  4. Press CTRL+S to save.

    Create your mock implementation to fake the callout during testing. Your implementation of WebServiceMock calls the doInvoke method, which returns the response you specify for testing. Most of this code is boilerplate. The hardest part of this exercise is figuring out how the web service returns a response so that you can fake a value.

  5. In the Developer Console, select File | New | Apex Class.
  6. For the class name, enter CalculatorCalloutMock and then click OK.
  7. Replace the autogenerated code with the following class definition.
    @isTest
    global class CalculatorCalloutMock implements WebServiceMock {
       global void doInvoke(
               Object stub,
               Object request,
               Map<String, Object> response,
               String endpoint,
               String soapAction,
               String requestName,
               String responseNS,
               String responseName,
               String responseType) {
            // start - specify the response you want to send
            calculatorServices.doAddResponse response_x = 
                new calculatorServices.doAddResponse();
            response_x.return_x = 3.0;
            // end
            response.put('response_x', response_x); 
       }
    }
  8. Press CTRL+S to save.

    Lastly, your test method needs to instruct the Apex runtime to send the fake response by calling Test.setMock before making the callout in the AwesomeCalculator class. Like any other test method, we assert that the correct result from our mock response was received.

  9. In the Developer Console, select File | New | Apex Class.
  10. For the class name, enter AwesomeCalculatorTest and then click OK.
  11. Replace the autogenerated code with the following class definition.
    @isTest
    private class AwesomeCalculatorTest {
        @isTest static void testCallout() {              
            // This causes a fake response to be generated
            Test.setMock(WebServiceMock.class, new CalculatorCalloutMock());
            // Call the method that invokes a callout
            Double x = 1.0;
            Double y = 2.0;
            Double result = AwesomeCalculator.add(x, y);
            // Verify that a fake result is returned
            System.assertEquals(3.0, result); 
        }
    }
  12. Press CTRL+S to save.
  13. To run the test, select Test | Run All.

The AwesomeCalculator class should now display 100% code coverage!

Resources

Flower icon used to indicate that the content is for Salesforce Classic

Remember, this module is meant for Salesforce Classic. When you launch your hands-on org, switch to Salesforce Classic to complete this challenge.

retargeting