[SalesForce] Call out to an external SOAP Webservice

I am trying to learn SOAP integration and have been following the online resource so far.

https://developer.salesforce.com/page/Apex_Web_Services_and_Callouts

My objective is to consume a publicly available SOAP API and display the weather for a city in a country.

Step 1 : Add the site to remote site settings

I have added the remote site as shown below.

enter image description here

Step 2 : Consume the WSDL

Below is the WSDL.

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www.webserviceX.NET" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://www.webserviceX.NET" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://www.webserviceX.NET">
      <s:element name="GetWeather">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="CityName" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="CountryName" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetWeatherResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="GetWeatherResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetCitiesByCountry">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="CountryName" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetCitiesByCountryResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="GetCitiesByCountryResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="string" nillable="true" type="s:string" />
    </s:schema>
  </wsdl:types>
  <wsdl:message name="GetWeatherSoapIn">
    <wsdl:part name="parameters" element="tns:GetWeather" />
  </wsdl:message>
  <wsdl:message name="GetWeatherSoapOut">
    <wsdl:part name="parameters" element="tns:GetWeatherResponse" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountrySoapIn">
    <wsdl:part name="parameters" element="tns:GetCitiesByCountry" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountrySoapOut">
    <wsdl:part name="parameters" element="tns:GetCitiesByCountryResponse" />
  </wsdl:message>
  <wsdl:message name="GetWeatherHttpGetIn">
    <wsdl:part name="CityName" type="s:string" />
    <wsdl:part name="CountryName" type="s:string" />
  </wsdl:message>
  <wsdl:message name="GetWeatherHttpGetOut">
    <wsdl:part name="Body" element="tns:string" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountryHttpGetIn">
    <wsdl:part name="CountryName" type="s:string" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountryHttpGetOut">
    <wsdl:part name="Body" element="tns:string" />
  </wsdl:message>
  <wsdl:message name="GetWeatherHttpPostIn">
    <wsdl:part name="CityName" type="s:string" />
    <wsdl:part name="CountryName" type="s:string" />
  </wsdl:message>
  <wsdl:message name="GetWeatherHttpPostOut">
    <wsdl:part name="Body" element="tns:string" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountryHttpPostIn">
    <wsdl:part name="CountryName" type="s:string" />
  </wsdl:message>
  <wsdl:message name="GetCitiesByCountryHttpPostOut">
    <wsdl:part name="Body" element="tns:string" />
  </wsdl:message>
  <wsdl:portType name="GlobalWeatherSoap">
    <wsdl:operation name="GetWeather">
      <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get weather report for all major cities around the world.</wsdl:documentation>
      <wsdl:input message="tns:GetWeatherSoapIn" />
      <wsdl:output message="tns:GetWeatherSoapOut" />
    </wsdl:operation>
    <wsdl:operation name="GetCitiesByCountry">
      <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get all major cities by country name(full / part).</wsdl:documentation>
      <wsdl:input message="tns:GetCitiesByCountrySoapIn" />
      <wsdl:output message="tns:GetCitiesByCountrySoapOut" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="GlobalWeatherSoap" type="tns:GlobalWeatherSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="GetWeather">
      <soap:operation soapAction="http://www.webserviceX.NET/GetWeather" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="GetCitiesByCountry">
      <soap:operation soapAction="http://www.webserviceX.NET/GetCitiesByCountry" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="GlobalWeather">
    <wsdl:port name="GlobalWeatherSoap" binding="tns:GlobalWeatherSoap">
      <soap:address location="http://www.webservicex.net/globalweather.asmx" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Intially I encountered "multiple porttypes error" and I have removed all the porttypes except the one shown above in the WSDL.

Step 3 : Generated Apex classes from WSDL

I went to "Setup->Develop->Apex Classes" and clicked on "Generate from WSDL".

And I choose the WSDL from above.

It got successfully parsed and created two classes for me.

Class 1 :

//Generated by wsdl2apex

public class AsyncWwwWebservicexNet {
    public class GetCitiesByCountryResponse_elementFuture extends System.WebServiceCalloutFuture {
        public String getValue() {
            wwwWebservicexNet.GetCitiesByCountryResponse_element response = (wwwWebservicexNet.GetCitiesByCountryResponse_element)System.WebServiceCallout.endInvoke(this);
            return response.GetCitiesByCountryResult;
        }
    }
    public class GetWeatherResponse_elementFuture extends System.WebServiceCalloutFuture {
        public String getValue() {
            wwwWebservicexNet.GetWeatherResponse_element response = (wwwWebservicexNet.GetWeatherResponse_element)System.WebServiceCallout.endInvoke(this);
            return response.GetWeatherResult;
        }
    }
    public class AsyncGlobalWeatherSoap {
        public String endpoint_x = 'http://www.webservicex.net/globalweather.asmx';
        public Map<String,String> inputHttpHeaders_x;
        public String clientCertName_x;
        public Integer timeout_x;
        private String[] ns_map_type_info = new String[]{'http://www.webserviceX.NET', 'wwwWebservicexNet'};
        public AsyncWwwWebservicexNet.GetCitiesByCountryResponse_elementFuture beginGetCitiesByCountry(System.Continuation continuation,String CountryName) {
            wwwWebservicexNet.GetCitiesByCountry_element request_x = new wwwWebservicexNet.GetCitiesByCountry_element();
            request_x.CountryName = CountryName;
            return (AsyncWwwWebservicexNet.GetCitiesByCountryResponse_elementFuture) System.WebServiceCallout.beginInvoke(
              this,
              request_x,
              AsyncWwwWebservicexNet.GetCitiesByCountryResponse_elementFuture.class,
              continuation,
              new String[]{endpoint_x,
              'http://www.webserviceX.NET/GetCitiesByCountry',
              'http://www.webserviceX.NET',
              'GetCitiesByCountry',
              'http://www.webserviceX.NET',
              'GetCitiesByCountryResponse',
              'wwwWebservicexNet.GetCitiesByCountryResponse_element'}
            );
        }
        public AsyncWwwWebservicexNet.GetWeatherResponse_elementFuture beginGetWeather(System.Continuation continuation,String CityName,String CountryName) {
            wwwWebservicexNet.GetWeather_element request_x = new wwwWebservicexNet.GetWeather_element();
            request_x.CityName = CityName;
            request_x.CountryName = CountryName;
            return (AsyncWwwWebservicexNet.GetWeatherResponse_elementFuture) System.WebServiceCallout.beginInvoke(
              this,
              request_x,
              AsyncWwwWebservicexNet.GetWeatherResponse_elementFuture.class,
              continuation,
              new String[]{endpoint_x,
              'http://www.webserviceX.NET/GetWeather',
              'http://www.webserviceX.NET',
              'GetWeather',
              'http://www.webserviceX.NET',
              'GetWeatherResponse',
              'wwwWebservicexNet.GetWeatherResponse_element'}
            );
        }
    }
}

Class 2 :

//Generated by wsdl2apex

public class wwwWebservicexNet {
    public class GetCitiesByCountryResponse_element {
        public String GetCitiesByCountryResult;
        private String[] GetCitiesByCountryResult_type_info = new String[]{'GetCitiesByCountryResult','http://www.webserviceX.NET',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.webserviceX.NET','true','false'};
        private String[] field_order_type_info = new String[]{'GetCitiesByCountryResult'};
    }
    public class GetCitiesByCountry_element {
        public String CountryName;
        private String[] CountryName_type_info = new String[]{'CountryName','http://www.webserviceX.NET',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.webserviceX.NET','true','false'};
        private String[] field_order_type_info = new String[]{'CountryName'};
    }
    public class GetWeatherResponse_element {
        public String GetWeatherResult;
        private String[] GetWeatherResult_type_info = new String[]{'GetWeatherResult','http://www.webserviceX.NET',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.webserviceX.NET','true','false'};
        private String[] field_order_type_info = new String[]{'GetWeatherResult'};
    }
    public class GetWeather_element {
        public String CityName;
        public String CountryName;
        private String[] CityName_type_info = new String[]{'CityName','http://www.webserviceX.NET',null,'0','1','false'};
        private String[] CountryName_type_info = new String[]{'CountryName','http://www.webserviceX.NET',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://www.webserviceX.NET','true','false'};
        private String[] field_order_type_info = new String[]{'CityName','CountryName'};
    }
    public class GlobalWeatherSoap {
        public String endpoint_x = 'http://www.webservicex.net/globalweather.asmx';
        public Map<String,String> inputHttpHeaders_x;
        public Map<String,String> outputHttpHeaders_x;
        public String clientCertName_x;
        public String clientCert_x;
        public String clientCertPasswd_x;
        public Integer timeout_x;
        private String[] ns_map_type_info = new String[]{'http://www.webserviceX.NET', 'wwwWebservicexNet'};
        public String GetCitiesByCountry(String CountryName) {
            wwwWebservicexNet.GetCitiesByCountry_element request_x = new wwwWebservicexNet.GetCitiesByCountry_element();
            request_x.CountryName = CountryName;
            wwwWebservicexNet.GetCitiesByCountryResponse_element response_x;
            Map<String, wwwWebservicexNet.GetCitiesByCountryResponse_element> response_map_x = new Map<String, wwwWebservicexNet.GetCitiesByCountryResponse_element>();
            response_map_x.put('response_x', response_x);
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              'http://www.webserviceX.NET/GetCitiesByCountry',
              'http://www.webserviceX.NET',
              'GetCitiesByCountry',
              'http://www.webserviceX.NET',
              'GetCitiesByCountryResponse',
              'wwwWebservicexNet.GetCitiesByCountryResponse_element'}
            );
            response_x = response_map_x.get('response_x');
            return response_x.GetCitiesByCountryResult;
        }
        public String GetWeather(String CityName,String CountryName) {
            wwwWebservicexNet.GetWeather_element request_x = new wwwWebservicexNet.GetWeather_element();
            request_x.CityName = CityName;
            request_x.CountryName = CountryName;
            wwwWebservicexNet.GetWeatherResponse_element response_x;
            Map<String, wwwWebservicexNet.GetWeatherResponse_element> response_map_x = new Map<String, wwwWebservicexNet.GetWeatherResponse_element>();
            response_map_x.put('response_x', response_x);
            WebServiceCallout.invoke(
              this,
              request_x,
              response_map_x,
              new String[]{endpoint_x,
              'http://www.webserviceX.NET/GetWeather',
              'http://www.webserviceX.NET',
              'GetWeather',
              'http://www.webserviceX.NET',
              'GetWeatherResponse',
              'wwwWebservicexNet.GetWeatherResponse_element'}
            );
            response_x = response_map_x.get('response_x');
            return response_x.GetWeatherResult;
        }
    }
}

Questions

a) Why two classes have been generated for me by WSDL2Apex ?

b) Can someone tell me how am I to actually perform the callout ?.

.Apologies if this is something trivial :)..

I have been following the resource so far and the actual call out step is not mentioned there :(.

Best Answer

Salesforce provides a WSDL (Web Service Description Language) files. They are called "Enterprise WSDL" and "Partner WSDL". A WSDL is an XML-document which contains a standardized description on how to communicate using a web service (the Salesforce API is exposed as a web service). The WSDL is used by developers to aid in the creation of Salesforce integration pieces. A typical process involves using the Development Environment (eg, Eclipse for Java, or Visual Studio for .Net) to consume the WSDL, and generate classes which are then referenced in the integration.

Enterprise WSDL:

This WSDL document is for customers who want to build an integration with their Salesforce organization only. It is strongly typed, which means that it contains objects and fields with specific data types, such as integer and string. Customers who use the enterprise WSDL document must download and re-consume it whenever their organization makes a change to its custom objects or fields or whenever they want to use a different version of the API. For the reasons outlined above, the Enterprise WSDL is intended primarily for Customers.

Partner WSDL:

This WSDL document is for customers, partners, and ISVs who want to build an integration that can work across multiple Salesforce organizations, regardless of their custom objects or fields. It is loosely typed, which means that you work with name-value pairs of field names and values instead of specific data types. The partner WSDL document only needs to be downloaded and consumed once per version of the API.

https://help.salesforce.com/apex/HTViewSolution?id=000004760&language=en_US

https://developer.salesforce.com/page/Apex_Web_Services_and_Callouts

You have to use methods of thoose generated files for CRUD operation.

Check out methods for CRUD http://developer.force.com/cookbook/recipe/calling-salesforce-web-services-using-apex

Callout Example

// here lstAccountToUpdate the list of Account records

partnerSoapSforceCom.Soap obj = new partnerSoapSforceCom.Soap();
partnerSoapSforceCom.LoginResult loginResult = obj.login('org@username.com', 'Password');   //your org username and pass
obj.SessionHeader = new partnerSoapSforceCom.SessionHeader_element();
obj.endpoint_x =loginResult.ServerUrl;
obj.Sessionheader.sessionid = loginResult.sessionid;
List<sobjectPartnerSoapSforceCom.sObject_x> lst = new List<sobjectPartnerSoapSforceCom.sObject_x>();
for(Account ac:lstAccountToUpdate)
{
    sobjectPartnerSoapSforceCom.sObject_x tmpObj = new sobjectPartnerSoapSforceCom.sObject_x();
    tmpObj.type_x = 'Account';
    tmpObj.Id = ac.Id;
    lst.add(tmpObj);
}

partnerSoapSforceCom.SaveResult[] lst1 =obj.update_x(lst);

Yes Related to above WSDL.

You just need to use generated class.

like

wwwWebservicexNet.GlobalWeatherSoap obj = new wwwWebservicexNet.GlobalWeatherSoap(); 

system.debug(obj.GetCitiesByCountry('INDIA')); // this will return all the cities 

system.debug(obj.GetWeather('Bombay / Santacruz', 'INDIA')); // this will return the Weather of Bombay / Santacruz city.

try this code in execute anonymous.

Related Topic