Earlier this week I worked with John Bliss on an interesting problem he had. Let me describe his issue, and the solution he came up, and what I learned from it.
John was trying to consume a web service. The web service demanded that a particular SOAP header be sent:
<soap:Header>
<ApiUserAuthHeader xmlns="namespace">
<UserName>xxxxx</UserName>
<Password>xxxxx</Password>
<UserAccessKey>xxxx</UserAccessKey>
</ApiUserAuthHeader>
</soap:Header>
He created the header like so:
<cfset ApiUserAuthHeader = StructNew()>
<cfset
ApiUserAuthHeader.UserAccessKey = "xxxxx">
<cfset ApiUserAuthHeader.Password =
"xxxxx">
<cfset ApiUserAuthHeader.UserName = "xxxxx">
<cfset
AddSOAPRequestHeader(MyWebservice, "namespace", "ApiUserAuthHeader",
ApiUserAuthHeader)>
So far so good, right? I've never actually used addSOAPRequestHeader, but just looking at his code it made sense to me. The result however was off:
<soapenv:Header>
<ns1:ApiUserAuthHeader xmlns:ns1="namespace">
<item
xmlns:ns2="http://xml.apache.org/xml-soap">
<key
xsi:type="xsd:string">PASSWORD</key>
<value
xsi:type="xsd:string">xxxxx</value>
</item>
<item>
<key
xsi:type="xsd:string">USERNAME</key>
<value
xsi:type="xsd:string">xxxxx</value>
</item>
<item>
<key
xsi:type="xsd:string">USERACCESSKEY</key>
<value
xsi:type="xsd:string">xxxxx</value>
</item>
</ns1:ApiUserAuthHeader>
</soapenv:Header>
If you compare this to what the API requires, you can see they don't match. The first suggestion I had was to change how he worked with the structures. When you do:
<cfset s = {}>
<cfset s.name = "Ray">
to create a structure, ColdFusion will uppercase the struct key (name), to give you: s.NAME = "Ray". I recommended he try bracket notation, essentially:
<cfset s = {}>
<cfset s["name"] = "Ray">
This didn't help either (although the resultant header did have the right case for the keys). I hashed this a bit more in my head and then I had an idea. He created the XML data pretty much the way I always did - with structure functions. Of course, ColdFusion also has native XML functions to create XML nodes/data. I never use them because the structure functions are simpler (to me!) and just plain work. In this case though switching to 'proper' XML manipulation functions worked perfectly for him:
<cfset doc = XmlNew()>
<cfset doc.ApiUserAuthHeader = XmlElemNew(ApiUserAuthHeader, "namespace", "ApiUserAuthHeader")>
<cfset doc.ApiUserAuthHeader.UserName = XmlElemNew(ApiUserAuthHeader, "UserName")>
<cfset doc.ApiUserAuthHeader.UserName.XmlText = "xxxxx">
<cfset doc.ApiUserAuthHeader.UserAccessKey = XmlElemNew(ApiUserAuthHeader, "UserAccessKey")>
<cfset doc.ApiUserAuthHeader.UserAccessKey.XmlText = "xxxxx">
<cfset doc.ApiUserAuthHeader.Password = XmlElemNew(ApiUserAuthHeader, "Password")>
<cfset doc.ApiUserAuthHeader.Password.XmlText = "xxxxx">
<cfset AddSOAPRequestHeader(MyWebservice, "namespace", "ApiUserAuthHeader", doc)>
So I guess I don't have much to add here, but I'd be curious if this type of problem has tripped up others?