I have been a lot of work with SOAP recently, consuming 3rd party web services written in JAVA and .NET. And I have come to the conclusion that ColdFusion really does suck when it comes to this particular area.
why do I say this, well basically I feel that Adobe have tried to be too clever with the web services and rather than make it easier for CF to work with SOAP they have in fact made it more of a PITA.
- When you try to consume a web service, the first thing that CF does it download the WSDL and create JAVA stubs for all the methods. This can be the start of your nightmares. Any errors in the WSDL, or anything that JAVA doesn't like, and the stub files will not be created and you will not be able to consume that web service. You also will not get back any kind of remotely useful error message either. So unless the 3rd party is prepared to modify their web service (unlikely) then your screwed. Also the initial request will be very slow while the stubs are generated, and any changes to the WSDL will not be picked up unless you delete the web service definition from the CFADMIN.
Here is an example of the type of error you might get when the stubs cannot be created.coldfusion.jsp.CompilationFailedException: Errors reported by Java compiler: Found 3 semantic errors compiling "/opt/jrun4/servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/stubs/WS888823651/fi/atex/www/namespace/Atex/Web/Advertising/Logo/LogoServiceLocator.java": 53. return _stub; <---> *** Error: The type of this return expression, "fi/atex/www/namespace/Atex/Web/Advertising/Logo/LogoSoapBindingStub", does not match the return type of the method, "fi/atex/www/namespace/Atex/Web/Advertising/Logo/Logo". 74. return _stub; <---> *** Error: The type of this return expression, "fi/atex/www/namespace/Atex/Web/Advertising/Logo/LogoSoapBindingStub", does not match the return type of the method, "java/rmi/Remote". 94. return getLogo(); <-------> *** Error: The type of this return expression, "fi/atex/www/namespace/Atex/Web/Advertising/Logo/Logo", does not match the return type of the method, "java/rmi/Remote". Found 1 semantic error co....
- Creating a SOAP request in CF can also be a total nightmare as you do it with arrays and structures and CF then tries to convert it into SOAP when you invoke the service. Simple variables are no problem, but when you need to create a request comprising of complex nested variable types, the fun and games begins, as CF just wont produce the required SOAP request in the required format.
E.G. Here is part of a required SOAP request, generating this in CF as nested structures does not produce the desired result due to the fact it is a nested set of complex variables.<insertions>
<item xsi:type="ns2:insertion">
<adContent xsi:type="ns2:adContent"><color xsi:type="ns2:color" xsi:nil="true"/>
<id xsi:type="xsd:int">0</id>
<messages xsi:type="soapenc:Array" xsi:nil="true" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"/>
<overmatter xsi:type="xsd:boolean">false</overmatter>
<proofURL xsi:type="xsd:string" xsi:nil="true"/>
<size xsi:type="ns2:size">
<depth xsi:type="xsd:double">30.0</depth><depthUnit xsi:type="xsd:string">mm</depthUnit>
<width xsi:type="xsd:double">31.0</width><widthUnit xsi:type="xsd:string">mm</widthUnit>
</size>
<styleId xsi:type="xsd:int">509</styleId>
<text xsi:type="xsd:string">uploadFile26863.tmp</text>
</adContent>
</item>
<item xsi:type="ns2:insertion">
<adContent xsi:type="ns2:adContent"><color xsi:type="ns2:color" xsi:nil="true"/>
<id xsi:type="xsd:int">1</id>
<messages xsi:type="soapenc:Array" xsi:nil="true" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"/>
<overmatter xsi:type="xsd:boolean">false</overmatter>
<proofURL xsi:type="xsd:string" xsi:nil="true"/>
<size xsi:type="ns2:size">
<depth xsi:type="xsd:double">30.0</depth><depthUnit xsi:type="xsd:string">mm</depthUnit>
<width xsi:type="xsd:double">31.0</width><widthUnit xsi:type="xsd:string">mm</widthUnit>
</size>
<styleId xsi:type="xsd:int">509</styleId>
<text xsi:type="xsd:string">uploadFile26863.tmp</text>
</adContent>
</item>
</insertions> - When providing your own web service for others to consume, the SOAP response created by CF is not very developer friendly at all. CF tends to generate xml attributes instead of tag entities.
In all the above situations you are better of manually creating your own SOAP request/response and sending this off the old fashioned way via a cfhttp post, which is in fact also quicker as you are bypassing the java stub files.
Below is an example of manually consuming a web service with your own hand crafted SOAP request. To generate and test your SOAP requests I recommend a handy tool called SOAP UI which will read your WSDL and create a default request for each method saving you a lot of time. All you need to do is fill in the data and submit the request, wheny ou have it working, just paste the request into your CF code and off you go.
<cfsavecontent variable="localscope.soapRequest">
<cfoutput>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<MyMethod>
<userContext xsi:type="ns1:userContext">
<name xsi:type="xsd:string">USERNAME</name>
<password xsi:type="xsd:string">PASSWORD</password>
</userContext>
<MyItem>
<userGroup xsi:type="xsd:string" xmlns="">1</userGroup>
<transactionType xsi:type="xsd:string" xmlns="">New</transactionType>
<adType xsi:type="xsd:string" xmlns="">L</adType>
<channel xsi:type="xsd:string" xmlns="">WEB</channel>
</MyItem>
</MyMethod>
</soapenv:Body>
</soapenv:Envelope>
</cfoutput>
</cfsavecontent>
<cfhttp url="webServiceURL?wsdl" method="POST" resolveurl="NO" useragent="Axis/1.1">
<cfhttpparam type="header" name="SOAPAction" value="#WSURL#MyMethod">
<cfhttpparam type="xml" name="body" value="#localscope.soapRequest#">
</cfhttp>
<cfset localscope.soapresponse = XMLParse(cfhttp.FileContent) />
May 23, 2007 at 8:49 PM Hi Russ,
I had an issue with SOAP and CF about 2 years ago - you might rememeber as I posted it to the cf dev list... In the end I found the easiest way to get it to work was use the underlying java layer to consume the soap services. CF support of SOAP really does suck, and is one of the reasons I'm making a not so stealthy move to the java arena.
Tom
May 24, 2007 at 9:37 AM Doesn't that still result in the creation and use of the JAVA stubs ?
May 24, 2007 at 11:18 AM well yes and no... I've called in someone elses SOAP service into one of my apps. It took about 30 seconds, and just worked, although to use the service in my local app would mean I need to build it and have axis available to generate the soap stubs. I just don't think CF is foinf the right job with SOAP to be honest, but I'm no expert - I just got it working in a painful way a couple of years back.
But hey it's all new right now, and learning Java, Spring, and another myriad other things right now, means the line between each technology is currently blurred for me a bit.
May 24, 2007 at 11:27 AM Well that is why I went for the above method, do away with the Java stubs altogether and have RAW XML requests and responses. I wouldn't imagine the stubs are created any differently whether your calling the web service via CF or JAVA directly, and any problems with those stubs being created is still going to cause you problems.
May 24, 2007 at 1:39 PM I'll let you know how I get on... my experience with java has so far been nicer with Java than with CF
May 24, 2007 at 1:40 PM I mean my experience with SOAP has been better sofar with Java than with with CF...
Sep 29, 2007 at 4:28 PM THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU!!!!!!!
Nov 13, 2007 at 12:50 PM Hi,
I think you may be too harsh. The problem is not with CF but with badly formed web services. Other code languages would probly have similar probs you describe above. Dreamweaver has its own SOAP UI, components, webservices, give it ?wsdl and it generates cfinvoke code you need to be able to use it, that's really cool. That aspect of Dreamweaver and CF makes working with web services a whole lot better than working with .net imo.
Nov 23, 2007 at 4:32 PM So, you can only use soap web services with coldfusion, if you are using dreamweaver, and happen to find a well formed web service? I am using CFEclipse right now, and I am trying to get hooked up with the paypal webservice which is soap based, and am having all kinds of problems. ColdFusion should make it much easier for me to get in there and get connected quickly. They may have a way to do it, but either their implementation could stand improvement, or their documentation could be improved, or could someone point me to the docs. I have not found good reviews or info yet on CF's soap integration.
Nov 23, 2007 at 5:59 PM Sorry, I didn't mean you couldn't use soap services w/ coldfusion w/o dreamweaver. I was saying that coldfusion should be better able to interface with soap services even if they are not properly formed. Also, I think a part of my problem, is the paypal soap interface not being well formed, and am just about to abandon the soap service, and work with their name-value-pair api instead.
If anyone could give pointers about using their api, please let me know.
Thanks
Feb 29, 2008 at 3:21 PM Thanx a lot, you helped me big time :-)
Feb 29, 2008 at 6:58 PM Checkout Flex3 and web services for a different approach, shallower learning curve. Also Paypal have a sandbox you can test following on:
http://www.scribd.com/doc/377370/How-to-use-the-PayPal-SDK-with-ColdFusion-8?ga_related_doc=1
You could google ColdFusion, Web Services and SOAP, and Paypal API/web services with Flex3 may show up something of use, hope this helps.
Colm
Apr 16, 2008 at 11:21 PM How would one format the Soap request with an attachement? I'm easily consuming webservices without attachments - however i cannot seem to properly format the xml code block to reference an attachment.
Apr 17, 2008 at 7:11 AM Have you read this Bobby.
http://www.w3.org/TR/SOAP-attachments
May 8, 2008 at 2:52 PM Nice post Russ. Got me out of a pickle there.
Jul 12, 2008 at 2:27 PM Awesome. Finally, a working soap example!
SOAP UI was great too.
Jul 21, 2008 at 4:22 PM Russ, I have just spent the last week beating my head against the wall and you solved my problem. Thanks. And thanks for the tip on soapUI. I have over 150 web services each with 10 to 50 methods to create calls to. soapUI will be a huge time saver. Thanks Again.
Oct 25, 2008 at 12:32 PM i want to know where this WSDL function
webServiceURL?wsdl...
I have problem prasing soap xml function.
Oct 25, 2008 at 12:35 PM i mean i would like to read this myitem.usergrop value. how can i read in the function
<MyItem>
<userGroup xsi:type="xsd:string" xmlns="">1</userGroup>
Oct 27, 2008 at 12:38 AM The WebServiceURL is the URL of the web service you are trying to call.
you reference XML value in the form
element.xmlText
or
element.child.xmlText
This will find this covered quite well in the CF docs
Mar 18, 2009 at 9:14 PM Could you describe the following line in more detail? ...
<cfhttpparam type="header" name="SOAPAction" value="#WSURL#MyMethod">
Mar 19, 2009 at 10:33 AM cfhttp param adds additional headers to the http request. Have a look at www.coldfusiondocs.com for more details of this tag.
The name of the header being added is "Soapaction", and the value is #WSURL#MyMethod, #WSURL# being the web service url, followed by your method name.
This header is required for your SOAP request to work.
Mar 19, 2009 at 5:29 PM The header in the Soap requested is <header />, so this line for me then would be...
<cfhttpparam type="header" value="">
Is that correct?
Mar 19, 2009 at 5:32 PM <header /> effectively means there is no header at all, so if this is what the web service wants then you shouldn't need to set anything.
Aug 19, 2009 at 12:30 AM I'm trying to use this method to send a soap request using Campaign Monitor's API but it returns a 415 Unsupported Media Type - Unable to determine MIME type of file error. I can't find any sources that help debug this, would you have an idea? Code below:
<cfsavecontent variable="soapRequest"><?xml version="1.0" encoding="utf-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<Subscriber.AddAndResubscribeWithCustomFields>
<ApiKey>XXXXXX</ApiKey>
<ListID>XXXX</ListID>
<Email>[email protected]</Email>
<Name>Full Name</Name>
<CustomFields>
<SubscriberCustomField>
<Key>State</Key>
<Value>NSW</Value>
</SubscriberCustomField>
</CustomFields>
</Subscriber.AddAndResubscribeWithCustomFields>
</soapenv:Body>
</soapenv:Envelope></cfsavecontent>
<cfset MyXMLDoc = xmlParse(soapRequest) />
<cfoutput>#MyXMLDoc#</cfoutput>
<cfhttp url="http://api.createsend.com/api/api.asmx?wsdl" getasbinary="no" method="POST" useragent="#CGI.http_user_agent#" resolveurl="NO" result="soapresponse" charset="utf-8">
<cfhttpparam type="header" name="Host" value="api.createsend.com" />
<cfhttpparam type="header" name="SOAPAction" value="http://api.createsend.com/api/Subscriber.AddAndResubscribeWithCustomFields" />
<cfhttpparam type="header" name="Content-Type" value="content-type:text/xml;charset='utf-8'" />
<cfhttpparam type="header" name="Content-Length" value="#len(MyXMLDoc)#" />
<cfhttpparam type="header" name="accept-encoding" value="no-compression" />
<cfhttpparam type="header" name="accept-charset" value="utf-8" />
<cfhttpparam type="xml" value="#trim(MyXMLDoc)#" />
</cfhttp>
<cfdump var="#soapresponse#">
Aug 19, 2009 at 2:35 AM Don't worry! Figured this out. My content-type syntax was incorrect- simply should've been value="text/xml;charset=utf-8". My bad.
Aug 19, 2009 at 4:40 AM Hi Russ.....
Excellent post! I have been trying to do this for so long! I have finally been able to connect to a web service that requires SOAP Request Headers! THANK YOU!!
I wonder though could you please tell me how I handle the #localscope.soapresponse# which returns an "AuthenticateUserResult" and 'token' values? I don't know how to make use of the variables returned from <cfset localscope.soapresponse = XMLParse(cfhttp.FileContent) />
Cheers.
Aug 19, 2009 at 12:21 PM Hi Aaron,
glad it was of help to you.
The localscope.soapresponse will contain the response sent back from the web service, in my example I am doing an XMLParse() on the response which turns it into an XML Document Object. If you CFDUMP this then you will see its structure and content, you access it as you would any other XML DOM or CFML structure.
Aug 19, 2009 at 5:57 PM This is a decent article if you need more granular details on how to use the XML data...
http://coldfusion.sys-con.com/node/41761
Hope that helps.
Aug 21, 2012 at 6:50 AM JSON d0bdd0b0 d0bfd0b5d180d0b2d18bd0b9 d0b2d0b7d0b3d0bbd18fd0b4 d0bbd0b5d0b3d187d0b5 d187d0b8d182d0b0d182d18c d0b8 d0bad0bed0b4d0b8d180d0bed0b2d0b0d182d18c, d0bdd0be d0bdd0b0 d0bfd180d0b0d0bad182d0b8d0bad0b5 d0bfd0bed0bbd183d187d0b0d0b5d182d181d18f d187d182d0be d181d0bbd0bed0b6d0bdd0b5d0b5, d187d0b5d0bc XML, d0bcd0bdd0bed0b3d0be d0bed188d0b8d0b1d0bed0ba d0b2 d0b2d0b8d0b4d0b5 d0bed182d181d183d182d181d182d0b2d183d18ed189d0b8d185 d0b8d0bbd0b8 d0bbd0b8d188d0bdd0b8d185 d0b7d0b0d0bfd18fd182d18bd185.d09fd0bed182d0bed0bc, d18f d0b4d0b0d0b6d0b5 d0bdd0b5 d0bfd180d0b5d0b4d181d182d0b0d0b2d0bbd18fd18e, d187d0b5d0bc d0bcd0bed0b6d0bdd0be d181d0b5d0b9d187d0b0d181 d0b7d0b0d0bcd0b5d0bdd0b8d182d18c XSLT, d0bdd0b5d181d0bcd0bed182d180d18f d0bdd0b0 d182d0be, d187d182d0be d182d0b5d185d0bdd0bed0bbd0bed0b3d0b8d18f d0bdd0b5 d0bfd180d0bed181d182d0b0d18f d0b4d0bbd18f d0b8d0b7d183d187d0b5d0bdd0b8d18f (d0bed181d0bed0b1d0b5d0bdd0bdd0be d0bfd180d0bed0b3d180d0b0d0bcd0bcd0b8d181d182d0b0d0bc d181 d0b8d185 d0b8d0bcd0bfd0b5d180d0b0d182d0b8d0b2d0bdd18bd0bc d0bcd18bd188d0bbd0b5d0bdd0b8d0b5d0bc), d18dd182d0be d181d0b0d0bcd18bd0b9 d0b3d0b8d0b1d0bad0b8d0b9 d0b8 d0bcd0bed189d0bdd18bd0b9 d188d0b0d0b1d0bbd0bed0bdd0b8d0b7d0b0d182d0bed180 d0b8d0b7 d0b2d181d0b5d185 d181d183d189d0b5d181d182d0b2d183d18ed189d0b8d185, d0b4d0b0 d0b5d189d0b5 d0b8 d181d0b0d0bcd18bd0b9 d180d0b0d181d0bfd180d0bed181d182d180d0b0d0bdd0b5d0bdd0bdd18bd0b9, d0b5d181d182d18c d0b2d0b5d0b7d0b4d0b5.d0a5d0bed182d18f d181d0b0d0bc XML d0b8 d0b8d0bcd0b5d0b5d182 d0bdd0b5d0b4d0bed181d182d0b0d182d0bad0b8, d0bdd0be d181 d0bdd0b8d0bc d0bcd0bed0b6d0bdd0be d180d0b0d0b1d0bed182d0b0d182d18c d0b8 d0b1d0bed0bbd0b5d0b5 d183d0b4d0bed0b1d0bdd18bd0bcd0b8 d0bcd0b5d182d0bed0b4d0b0d0bcd0b8, d0bdd0b0d0bfd180d0b8d0bcd0b5d180 d181 d0bfd0bed0bcd0bed189d18cd18e SimpleXml (d0b2 PHP), d18dd182d0be d183d0b6d0b5 d187d182d0be-d182d0be d0b1d0bbd0b8d0b7d0bad0bed0b5 d0ba prbouotf.d0a1d0b5d0b9d187d0b0d181 prbouotf d0b7d0b0d18fd0b2d0bbd0b5d0bd d182d0bed0bbd18cd0bad0be d0b2 C++, Java, Python, d18dd182d0bed0b3d0be d0bcd0b0d0bbd0be, d0bdd183d0b6d0bdd0be d187d182d0bed0b1d18b d0b0d0b1d181d0bed0bbd18ed182d0bdd0be d0b2d0b5d0b7d0b4d0b5 d0bcd0bed0b6d0bdd0be d0b1d18bd0bbd0be d180d0b0d0b1d0bed182d0b0d182d18c d181 d18dd182d0b8d0bcd0b8 d0b4d0b0d0bdd0bdd18bd0bcd0b8, d182d0bed0b3d0b4d0b0 d0b8 d0bcd0bed0b6d0bdd0be d0b1d183d0b4d0b5d182 d0b3d0bed0b2d0bed180d0b8d182d18c d0be d0b7d0b0d0bcd0b5d0bdd0b5 d18dd182d0b8d0bc d184d0bed180d0bcd0b0d182d0bed0bc XML.