The introduction

SOAP is a “simple” XML-based protocol that became popular more than a decade ago. SOAP is certainly much more cumbersome than the JSON protocol-based restFul apis that exist today.

If the project is developed in.NET or Java, this is fine, as the IDE has handy built-in capabilities to parse the WSDL file of the SOAP service and automatically generate Client code. But if you use Golang, you’re in trouble.

Here’s where SOAP is different, or where it gets in the way.

SOAP is different

  • Request/Response structure is complex, and the nesting level is multiple and deep

Here is an example of a Request Body that must specify a specific namespace. The API’s authentication key information is also written in the Request Body.

<soapenv:Envelope xmlns:ns="http://www.id3global.com/ID3gWS/2013/04" xmlns:soap="soap" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
      <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
         <wsse:UsernameToken>
            <wsse:Username></wsse:Username>
            <wsse:Password></wsse:Password>
         </wsse:UsernameToken>
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
   </soapenv:Body>
</soapenv:Envelope>
Copy the code

In general, the SOAPenv :Body section is often more complex, cumbersome, and error prone to manual writing without tool support.

  • The setting of the Header
Content-Type: text/xml; charset="utf-8"
SOAPAction: http://www.id3global.com/ID3gWS/2013/04/IGlobalAuthenticate/AuthenticateSP
Copy the code

Header content-type is application/json. Don’t write application/json subconsciously. The SOAPAction header needs to be set to the action to be called. Note that the baseUrl may be different for different actions. RestFul apis don’t have the same pitfalls.

  • Multiple part reponse

Most of the time, SOAP returns data in XML format, but sometimes in multiple part format such as the following, which requires some effort to parse.

--uuid:6d335978-5c93-40b7-b5c4-3acc067e3d8c+id=302 Content-ID: <http://tempuri.org/0> Content-Transfer-Encoding: 8bit Content-Type: application/xop+xml; charset=utf-8; type="text/xml" <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" The XMLNS: u = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" > < s: Header > < o: Security s:mustUnderstand="1" XMLNS: o = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" > < / s: Header > <s:Body></s:Body> </s:Envelope> --uuid:6d335978-5c93-40b7-b5c4-3acc067e3d8c+id=302--Copy the code
  • Time deserialization with Golang’s time.time type

Golang’s time.Time type requires information about the time zone when unmarshal, which simply means at least a Z at the end, for example: 2021-09-23T14:55:43.835z. If there is no time zone information, such as 2024-07-13T00:00:00, then either you use string instead of time. time, or you overwrite the UnmarshalXML method.

The solution

After writing this much, you’ll also find that you have to deal with a lot more detail than you normally would if you didn’t have the tools available.

In the sense that there is no new problem in technology, or that you will never be the first person to encounter this problem, I set out on the road to search, and I have to say search is Still Google!

I found a tool of my choice, Gowsdl, in an article on Medium that you can easily generate template code with:

gowsdl [options] myservice.wsdl
Copy the code

However, I do not recommend that you use the generated code directly, but just use the structure it defines and re-wrap a client yourself, for the following reasons:

  1. There are usually too many actions defined in a WSDL and you only need to use one or two of them
  2. Also, the generated code defaults to using the time fieldtime.Time, it is recommended to manually change it to the one defined in goWSDLXSDDateTime. It’s funny to think why not just use XSDDateTime.

In general, the generated code also has many advantages:

  1. Enums are recognized and specific types and values are generated.
  2. You can identify the corresponding for each actionSOAPActionThe HTTP header

Finally, ONE more point, I don’t know whether the SOAP protocol of the third-party service I integrated is very old or whether there is a bug in the library. In short, when dealing with the response of multiple part, some checking logic failed. I mentioned a PR, although no one has handled it yet, it is quite tricky.

In this case, there is another issue, how to hotfix problems found in reference packages when using go Mod to manage third-party packages?

In fact, it can be divided into 3 steps:

  1. On Github, fork your own repo
  2. Change the code and Push a new tag
  3. But because the reference name of this Module is still the same, if you use your own cloned repO, you will get the following error
Go: github.com/ksloveyuan/[email protected]: parsing go. Mod: module declares its path as: github.com/hooklift/gowsdl but was required as: github.com/ksloveyuan/gowsdlCopy the code

I didn’t dig into the cause, but it feels like go.mod has something to do with it. Again, you won’t be the first person to experience this problem. The solution is to use the replace function in Go. mod. At the end of the go.mod file, add the following line to fix the error

The replace github.com/hooklift/gowsdl v0.5.0 = > github.com/ksloveyuan/gowsdl v0.5.1Copy the code