Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOAP integration: set root element namespace #41 #50

Merged
merged 1 commit into from
Jan 30, 2017
Merged

Conversation

jumokeoladimeji
Copy link
Contributor

@jumokeoladimeji jumokeoladimeji commented Dec 21, 2016

#41

@jumokeoladimeji jumokeoladimeji self-assigned this Dec 21, 2016
@jumokeoladimeji jumokeoladimeji changed the title Fix/41 SOAP integration: set root element namespace #41 Dec 21, 2016


it 'should require xmlnsAttribute value', ->
assert.equal soap.validate(url: 'http://foo', function: 'whatever', version:'1.1', namespace_prefix: 'tns', xmlnsAttribute_name: 'xmlns:tns'), 'XmlnsAttribute value is required'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want this configuration to be optional.

@@ -189,6 +204,9 @@ requestVariables = ->
{ name: 'url', description: 'WSDL URL', type: 'string', required: true }
{ name: 'function', description: 'Name of the SOAP function to call', type: 'string', required: true }
{ name: 'version', description: 'SOAP version to use: 1.1 or 1.2 (default: 1.1)', type: 'string', required: false }
{ name: 'namespace_prefix', description: 'namespace prefix for the body element', type: 'string', required: true }
{ name: 'xmlnsAttribute_name', description: 'xmlnsAttribute name for the body element', type: 'string', required: true }
{ name: 'xmlnsAttribute_value', description: 'xmlnsAttribute value for the body element', type: 'string', required: true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the variable name all lower case. Maybe root_xmlns_attribute_name and root_xmlns_attribute_value?

@kellym
Copy link
Member

kellym commented Dec 21, 2016

re: tests and validations, it seems as per https://www.w3.org/TR/REC-xml-names/ that xml namespaces are URIs. since this checks vars.url is a valid url, might make sense to do the same for the namespace. i seem to be reading conflicting things on if it's always a URI, but w3c seems to think it should be.

also, for testing the new attributes, you might want to test that the overrideRootElement changes leave the default when those vars are undefined and change it when they're passed in.

@cgrayson
Copy link
Contributor

cgrayson commented Jan 3, 2017

Kelly said:

since this checks vars.url is a valid url, might make sense to do the same for the namespace. i seem to be reading conflicting things on if it's always a URI, but w3c seems to think it should be.

I came across some of those conflicting things you mentioned on Wikipedia: "In general, however, users should assume that the namespace URI is simply a name, not the address of a document on the Web".

For this advanced setting, I think being more lax is better. If someone needs to set up this namespace business, they'll have to enter the value right one way or the other. I'm afraid that as soon as it's validated to be a URI, we'll have a customer that wants to use a non-URI value.

Any thoughts, @alexkwolfe ?

Copy link
Contributor

@cgrayson cgrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to this feedback, there are outstanding questions to discuss about URI validation.

<tns:AddLeadResponse xmlns:tns="http://donkey/ws.asmx/">
<AddLeadXMLResult>
&lt;Response&gt;
&lt;Result&gt;true&lt;/Result&gt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reason for these tags to be in &lt;s and &gt;s, instead of <s and >s?

validateVersion = (vars) ->
version = vars.version?.trim()
return unless version?
return 'Must be valid SOAP version: 1.1 or 1.2' unless version == '1.1' or version == '1.2'

validateXmlnsAttributeValue = (vars) ->
if vars.root_xmlns_attribute_value?
console.log vars.root_xmlns_attribute_value,'validate url result', validate.isValidUrl(vars.root_xmlns_attribute_value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to remove this debugging statement.

@@ -189,6 +198,9 @@ requestVariables = ->
{ name: 'url', description: 'WSDL URL', type: 'string', required: true }
{ name: 'function', description: 'Name of the SOAP function to call', type: 'string', required: true }
{ name: 'version', description: 'SOAP version to use: 1.1 or 1.2 (default: 1.1)', type: 'string', required: false }
{ name: 'root_namespace_prefix', description: 'namespace prefix for the body element', type: 'string', required: false }
{ name: 'root_xmlns_attribute_name', description: 'xmlnsAttribute name for the body element', type: 'string', required: false }
{ name: 'root_xmlns_attribute_value', description: 'xmlnsAttribute value for the body element', type: 'string', required: false }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variables are presented to the user in the UI in the order they're listed here. I think these new settings won't be very commonly used, so they'd be better at the end of this array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think we can give better information about these (admittedly advanced) settings than "xmlnsAttribute name for the body element".

@@ -24,12 +25,14 @@ describe 'Outbound SOAP', ->
vars =
url: 'http://donkey/login/ws/ws.asmx?WSDL'
function: 'someUnsupportedFunction'
root_xmlns_attribute_name: 'xmlns:tns'
root_xmlns_attribute_value: 'http://skylist.com/services/Soap'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these new lines are needed.

@@ -41,6 +44,8 @@ describe 'Outbound SOAP', ->
vars =
url: 'http://donkey/login/ws/ws.asmx?WSDL'
function: 'AddLead'
root_xmlns_attribute_name: 'xmlns:tns'
root_xmlns_attribute_value: 'http://donkey/login/ws/ws.asmx?WSDL'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I don't think these new lines are needed.

done()



Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Kelly mentioned previously, there should also be test coverage for when these new variables are not set, to ensure the requests are still constructed correctly.

@kellym
Copy link
Member

kellym commented Jan 3, 2017

@cgrayson I agree with being more lax on the namespace. My point of reference was https://www.w3.org/TR/REC-xml-names/#concepts -- with the definition being a URI reference. I did a bit more digging just now and found this unclear documentation as well -- not sure if it's referring to a valid URI format or actual endpoint: https://www.w3.org/TR/REC-xml-names/#ProcessorConformance.

So on that note, since namespace validation is pretty unclear, probably best to avoid it after all.

@alexkwolfe
Copy link
Contributor

I vote for omitting URI validation for the namespaces.

@jumokeoladimeji
Copy link
Contributor Author

@cgrayson I have made the changes.

@@ -46,5 +46,3 @@ module.exports =
# ensure that user-specified Content-Type is similar to what's allowed
if headers['content-type']? and !headers['content-type']?.match(new RegExp(contentTypeBase, 'i'))
return "Invalid Content-Type header value"


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These whitespace changes are making this file show as changed when it hasn't, really.

<Result>true</Result>
<Message>some message</Message>
<LeadId>12345</LeadId>
<Empty></Empty>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would normally just be <Empty/>, as here.

.reply 200, wsdl, 'Content-Type': 'text/xml'

@service = nock 'http://donkey'
.post '/login/ws/ws.asmx'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test (and the following one) aren't quite sufficient. They're only verifying that a POST is made by the integration to that URL, but not what is posted. This test should verify that the correct SOAP header stuff is added, and the test below should verify that no SOAP header stuff is changed. I think using a regex, as described in the nock docs, would be the way to go.

namespace: vars.root_namespace_prefix
xmlnsAttributes: [
{ name: vars.root_xmlns_attribute_name, value: vars.root_xmlns_attribute_value }
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'll find, once tests are more thorough, that these options need to be set only when the vars.root_… values are present. For example, I think this code will set an attribute like undefined="undefined".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, as mentioned in discussion on #41, there would ideally be support for multiple name/value pairs here.

Copy link
Contributor

@cgrayson cgrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you have any questions, or when this is ready to review again


# prevent root xlmns attribute key and value from being added to the root element when it is undefined
if !vars.root_xlmns_attributes
delete options.overrideRootElement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic would be a little clearer if the options values were only ever set if needed, rather than always set and then possibly deleted later. E.g., don't declare them at all at first, and then:

 if _.isPlainObject(vars.root_xlmns_attributes)
   options.overrideRootElement = {}
   options.overrideRootElement.namespace = vars.root_namespace_prefix if vars.root_namespace_prefix

   for key, value of vars.root_xlmns_attributes
     options.overrideRootElement.xmlnsAttributes.push { name: key, value: value }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, unfortunately, the way you have this set up won't work. vars.root_xmlns_attributes here is an object, but data isn't addressable like that in LeadConduit. That is, users can't map an object like { 'xmlns:cal': 'http://donkey/ws.asmx/' } in the LC UI. To support multiples, I think there would need to be an array for root_xmlns_names, and another matching one for root_xmlns_values… (unless there's some way I'm not thinking of, @alexkwolfe?).

So, although I think ideally we would allow multiple, for now please step back to one pair, and we'll hope that's enough for the time being.

Copy link
Contributor Author

@jumokeoladimeji jumokeoladimeji Jan 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have edited it. I agree that they should be arrays. The reason why I used wildcard as the type instead of an array is that array is not included as a type in the documentation.

Copy link
Contributor

@cgrayson cgrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting close, I just have that last concern.

# prevent root xlmns attribute key and value from being added to the root element when it is undefined
if vars.root_xmlns_attribute_name and vars.root_xmlns_attribute_value
options.overrideRootElement =
namespace: vars.root_namespace_prefix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I know this is set up as I suggested 😃 but I think there may be a problem here. If only root_namespace_prefix is set (and root_xmlns_attribute_name or …value isn't), then this namespace option will never be set. Maybe tests for each combination of values would make sure these cases are covered.

@alexkwolfe
Copy link
Contributor

Jumoke, based on what you said in our integrations meeting today, it sounds like maybe you were thinking of implementing an array of namespaces. But it sounds like we're OK just skipping that for now. And the only remaining issue is the one that chris brought up here.


# prevent root xlmns attribute key and value from being added to the root element when undefined
if vars.root_xmlns_attribute_name and vars.root_xmlns_attribute_value
options.overrideRootElement['xmlnsAttributes'] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that if vars.root_namespace_prefix isn't defined, then there is no options.overrideRootElement. If you add a test with root_xmlns_attribute_name and root_xmlns_attribute_value, but no vars.root_namespace_prefix, you'll see what I mean.

Copy link
Contributor

@cgrayson cgrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM

options =
valueKey: '#value'
forceSoap12Headers: vars.version?.trim() == '1.2'
disableCache: true
overrideRootElement:
namespace: vars.root_namespace_prefix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it's evidently not currently causing problems, per your tests, when vars.root_namespace_prefix isn't set, this code is setting overrideRootElement.namespace to undefined, which makes me nervous.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the last thing to address before we get this merged?

]

if !vars.root_namespace_prefix
delete options.overrideRootElement['namespace']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deleting this property, I think it makes more sense to not set it at all. I know you're running into an error when root_namespace_prefix isn't defined but the others are, so you could use _.set around L28 to reduce some of the logic to make sure options.overrideRootElement is defined:

_.set options, 'overrideRootElement.xmlnsAttributes', [
  name: vars.root_xmlns_attribute_name
  value: vars.root_xmlns_attribute_value
]

@cgrayson
Copy link
Contributor

Still LGTM

…ce or xmlns attribute name/value pair when specified
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants