Consuming External Web Service in Apex – Salesforce

One of the feature we have in Salesforce is that we can easily consume External Web Services. In this article, we will learn step by step demo of consuming Web Service in Apex. There are many public websites available to consume Web Service and one of them, I am using in this article is http://www.webservicex.net , from this location we are using Stock Quote Webservice. To consume this, we need WSDL.

The Web Services Description Language (WSDL) is an XML-based interface description language that is used for describing the functionality offered by a Web Service.

WSDL have to be downloaded from this location. We need this WSDL in later part of this tutorial.

Once, WSDL is downloaded and saved on local drive. We have to go to Salesforce and navigate to “Setup | Develop | Apex Classes”. On right hand side, you will find button named as “Generate from WSDL”. This button will generate equivalent Apex class to support Webservice call. In some Programming languages, these classes are known as Proxy classes or Stubs.

When we click on “Generate from WSDL” button, it will prompt for WSDL File. Select WSDL file downloaded previously and click on “Parse WSDL” button. On next page you will get this error : “Failed to parse wsdl: Found more than one wsdl:portType. WSDL with multiple portType not supported”.

In some cases you may also get error like : “Failed to parse wsdl: Found more than one wsdl:binding. WSDL with multiple binding not supported”.

Intentionally, I have used this WSDL to explain that currently Salesforce supports only single portType and binding.

PortType : defines a web service, the operations that can be performed, and the messages that are involved.
Binding : WSDL bindings defines the message format and protocol details for a web service.

Reason, we are getting an error because “wsdltoApex” doesnt support multiple PortType, Binding, SOAP 1.2 and Schema imports. You can read more here from Salesforce documentation.

How to resolve multiple portType and Binding error in Apex while generating stubs ?

We have to modify downloaded WSDL to make sure it only contains Single Binding and single PortType. Before modifying I would suggest to read about WSDL elements. I have uploaded both versions of WSDL (Please change attached file extensions from txt to xml). First one is Actual WSDL and second I have modified to remove errors. You can compare both and check how I removed multiple PortType and Binding elements from WSDL.

  1. Stockquote Actual WSDL File (Change extension from txt to xml)
  2. Stockquote Updated WSDL File (Change extension from txt to xml)

Once, you modify your wsdl, try to generate Apex class again and this time you will be able to generate class without any error.

Generating Apex from WSDL in Salesforce
Generating Apex from WSDL in Salesforce

So, here we have successfully generated Stub classes for Webservice.

How to use generated web-service Apex stub ?

Before trying to use webservice, we have to inform Salesforce that our code will try to get some Data from External source (rather interact with external system). And therefore Remote Site Setting comes into picture.

Navigate to “Setup | Security Control | Remote Site Settings“.

Create new Site setting for URL “http://www.webservicex.net“. If we skip this step, we will endup with error like “Unauthorized Endpoint”.

We can use generated Apex class in Visualforce or some other location. To keep this tutorial simple, I am using “Developer Console”. Open Developer Console and press “Ctrl+E”.

wwwWebservicexNet.StockQuoteSoap proxyClass = new wwwWebservicexNet.StockQuoteSoap();
String retVal = proxyClass.GetQuote('CTSH');
System.debug(retVal);

In above code “CTSH” is Stock symbol for Cognizant Technology Solution. You can use any other valid Stock Symbol. Output will be visible in Console Log. We can use this output as per our need

How you will find that which Class to instantiate ?
As shown in above code, I have created Object for “wwwWebservicexNet.StockQuoteSoap”.  I was able to identify that which class to instantiate? I was able to identify by porttype element name from WSDL.

How to increase Time out in Webservice ?

You may get Timeout exception while calling webservice. Default time is 10sec (At time of writing this tutorial, may change in future release). we can use “timeout_x” property to increase time to wait for response from web service. So above code can be re-written as

wwwWebservicexNet.StockQuoteSoap proxyClass = new wwwWebservicexNet.StockQuoteSoap();
proxyClass.timeout_x = 20000 ; // timeout in milliseconds
String retVal = proxyClass.GetQuote('CTSH');
System.debug(retVal);

Some Known Limitations to WSDL2Apex :

  1. It does not support multiple port bindings.
  2. Inheritance is not supported in wsdl to APEX conversion.
  3. Complex Object types such as Enumeration are not supported.
  4. WSDL Import functionality is not supported.

I hope this tutorial will be helpful for newbies. Please post your comment and feedback about this tutorial. I will be delighted to answer your query about this article.

Related posts

43 thoughts on “Consuming External Web Service in Apex – Salesforce”

  1. Amazing tutorial..but i am struct up near removing the error related to MultiplePort binding because the 2 files given seems the same..not sure if i am looking at it correctly..pls help me

    1. Hi Gautam, If you compare both File, One is larger in size and one is smaller. Larger is original and will not work. Smaller size is updated and will work. You can use Notepad++ to compare XML Files

          1. Jitendra, I have tried one more WSDL from the same website which is for Currency Convertor, but i m getting an error while parsing..

            Error: Failed to parse wsdl: Parse error: Found invalid XML. end tag name must match start tag name
            from line 200 (position: TEXT seen …
            ZWD-Zimbabwe Dollar… @200:3628)

            But i see all the tags are properly matching ..kindly suggest me where i need to modify in order to PARSE.

  2. hi shiva,
    i was trying to do example of .net integration, But iam facing the below error

    System.CalloutException: Web service callout failed: WebService returned a SOAP Fault: System.Web.Services.Protocols.SoapException: Server was unable to process request. —> System.IO.IOException: There is not enough space on the disk. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count) at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer) at System.IO.FileStream.Dispose(Boolean disposing) at System.IO.Stream.Close() at System.IO.StreamWriter.Dispose(Boolean disposing) at System.IO.TextWriter.Dispose() at Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources) at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, String[] sources) at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource(CompilerParameters options, String[] sources) at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence) at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies) at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence) at System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[] mappings, Type type) at System.Web.Services.Protocols.SoapServerType..ctor(Type type, WebServiceProtocols protocolsSupported) at System.Web.Services.Protocols.SoapServerProtocol.Initialize() at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing) — End of inner exception stack trace — faultcode=soap:Server faultactor=: Class.ganesh1234.wwwWebservicexNet.StockQuoteSoap.GetQuote: line 25, column 1 AnonymousBlock: line 2, column 1 AnonymousBlock: line 2, column 1

    Please rectify my error ………..Thanks in Advance Shiva

  3. HI jithendra,
    can you explain one scenario for REST
    if we write the REST based apex class how can we generate the end-point url for the class

  4. Hi Jitendra,
    I’m given a WSDL wherein required parameters to send across request object are of enum types. And there are not supported in salesforce. In that case is it possible to convert them into complex/simple types ? if yes, how ?

    thanks,
    Raghuprasad

  5. Hi Jitendra,
    i am working with sfdc from couple of months still and newbie to web services.
    i have followed the steps and was able to create stub and use it in developer console. please let me how we can use the response in vf pages

    Thanks for your help
    Regards,
    Raj

    1. Hi Raj,
      You can call webservice in Controller class of Visualforce and save returned value in some Field. SHow that field in Viusalforce..

      1. Thank you Jitendra,

        working on the parsing the received response using dom , is there any sort of good example for restful or soap producer and consumer? This would be great help for me in understanding the both the implementations and will be useful in my another attempt of using websercies being called from a second party to transfer the acounts list and corresponding the cases list vice versa.

        Thank you
        Raj

  6. How do I work if I am unable to generate the WSDL classes and have to handcraft the soap calls? The external webservice has confirmed that is the approach to be taken. Do you have any samples?

    1. You can consume any WSDL in support with some exceptions , you should go through this post which explains which component in WSDL is not supported – https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex.htm

      Apex does not support any other WSDL constructs, types, or services, including:
      RPC/encoded services
      WSDL files with mulitple portTypes, multiple services, or multiple bindings
      WSDL files that import external schemas. For example, the following WSDL fragment imports an external schema, which is not supported:

  7. This is really an amazing blog. Your blog has really helped me understand webservice consumption concept in apex.

    However many company’s quotes are not getting generated due to some issues with WSDL site. I tried with MSFT, CRM etc but still no luck.

    Thanks a lot.

  8. Hi Jitendra,
    Is there a way to trace outgoing SOAP envelope in sandboxes to help debugging the issues. I tried to play with debug level but of not much help. Now I use RequestBib/GetSandbox to trace the message after changing the endpoint. Is there a way to trace the message in debug with the actual endpoint.

    Out of business-
    I am a fan of your posts because of the knowledge and simplicity involved. It also feels good that you work for the same organization that I do :).

    1. Thanks for your words @CommonIntellect:disqus

      I think Requestbin is good option. If its REST API then we can use custom object, however for SOAP API it would be tricky to capture SOAP request.

  9. Hi Jitendra,

    Its a nice tutorial. However what if WSDL file is not compatible with Salesforce? What are the options available? Can you please guide in that?

    Thanks

    1. Hi Shivani,
      I would suggest to make appropriate changes to make it compatible with Salesforce. There is no thumb rule on how to achieve this, it differs as per WSDL and type of error you are getting. Other way is to use proxy webservices which will be compatible with Salesforce and source system as well or use ETL tool. As a last resort, you can use REST API and make SOAP request manually.

  10. Amazing blog..!!
    I want to know about the “Can we consume the Local Web service from apex ” actually i am working on the rest api from apex to external System and I want to Post callout from apex but i am facing the error of 503 “Service Unavailable” and the Url is not live so can we do the post method callout from apex ..?

Leave a Reply