droyo / go-xml

utility and code-generation libraries for XML
MIT License
302 stars 114 forks source link

WSDL Response decoding does not seem to work #74

Open leth opened 5 years ago

leth commented 5 years ago

I cannot, despite my best efforts, find a way to decode the response body. The envelope is processed fine, just the contents of the Body is not decoded.

I think we need a test case for the generated code, as #25 calls for

droyo commented 5 years ago

I admit I haven't even manually tested this part of the generated code very thoroughly. Would you happen to have a WSDL endpoint in mind that we can use as an example?

leth commented 5 years ago

I'm new to the world of WSDL, so don't have any examples to test against. It's fairly striaghtforward to catch: if you marshal and serialise a request struct to bytes, then try to deserialise and marshal it back to structs then it will just be empty.

IIUC it's because the Envelope Body is an interface{}; go can marshal it since it has a instance to reflect on, but it can't unmarshal it because it's not sure what type they should be.

droyo commented 5 years ago

Ah, it looks like the tests I have in wsdlgen/examples/* only test marshalling.

I think the gentests/_testgen can be easily extended to generate tests for wsdlgen if there is a .wsdl file, and mock responses if there is a .sample file in the relevant directory, with some inspiration from the links you gave me in #25.

droyo commented 5 years ago

Ok, I 've got some rudimentary tests pushed in the issue-25 branch and I think I might see the problem. It looks like I may have added an unnecessary layer of encapsulation in the temporary types used to marshal/unmarshal requests and responses. Example:

WSDL:

<message name="GetLastTradePriceOutput">
    <part name="body" element="xsd1:TradePrice"/>
</message>

<portType name="StockQuotePortType">
    <operation name="GetLastTradePrice">
       <input message="tns:GetLastTradePriceInput"/>
       <output message="tns:GetLastTradePriceOutput"/>
    </operation>
</portType>

Go:

var output struct {
    XMLName struct{} `xml:"http://example.com/stockquote.wsdl GetLastTradePrice"`
    Args    struct {
        Body TradePrice `xml:"http://example.com/stockquote.wsdl body"`
    } `xml:"http://example.com/stockquote.wsdl GetLastTradePriceOutput"`
}

I'll need to check the soap spec again to see what the correct behavior is here.

droyo commented 5 years ago

Ok, the relevant portion of the WSDL spec is https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_porttypes and it does seem like I have a few too many layers here.

droyo commented 5 years ago

OK, reading the specs a bit more I'm beginning to understand.

https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap:operation

The value of this attribute also affects the way in which the Body of the SOAP message is constructed [...] If the attribute is not specified, it defaults to the value specified in the soap:binding element. If the soap:binding element does not specify a style, it is assumed to be "document".

https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap:body

If the operation style is rpc each part is a parameter or a return value and appears inside a wrapper element within the body (following Section 7.1 of the SOAP specification). [...] If the operation style is document there are no additional wrappers, and the message parts appear directly under the SOAP Body element.

Relevant portions of the SOAP spec:

rpc style: https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383533 doc style: https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383503

So next steps would be:

I opened #76 for the related goal of generating error types for soap faults.

leth commented 5 years ago

Thanks for looking into this in such detail! In the interim I've switched to xsdgen, and manually built the soap envelope handling for my service.

I'm working with an operation which binds input and output to the SOAP body:

      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>