wsaa ejemplos afip soap go soap-client

soap - ejemplos - afip web service documentation



¿Soporte WSDL/SOAP en Go? (5)

No

SOAP apesta, pero tuve que implementar un servidor de un protocolo ya definido que utiliza SOAP, así que escuché con net/http y descodifiqué / codifiqué los sobres con encoding/xml . En pocos minutos, ya serví mi primer sobre con Go.

¿Hay algún paquete para soportar SOAP / WSDL en Go?


No hay soporte para WSDL en Go. El soporte en otros idiomas es estático o dinámico: cualquiera de las estructuras se genera previamente desde el WSDL, o se realiza sobre la marcha con tablas hash.

Sin embargo, puede codificar y decodificar las solicitudes SOAP manualmente. Encontré que el paquete de encoding/xml estándar no es suficiente para SOAP. Hay tantas peculiaridades en diferentes servidores, y las limitaciones en la encoding/xml dificultan la generación de una solicitud con la que estos servidores están satisfechos.

Por ejemplo, algunos servidores necesitan xsi:type="xsd:string" en cada etiqueta de cadena. Para hacer esto correctamente, su estructura debe tener este aspecto para la encoding/xml :

type MethodCall struct { One XSI Two XSI } type XSI struct { Type string `xml:"xsi:type,attr"` Vaue string `xml:",chardata"` }

Y lo construyes así:

MethodCall{ XSI{"xsd:string", "One"}, XSI{"xsd:string", "Two"}, }

Lo que te da:

<MethodCall> <One xsi:type="xsd:string">One</One> <Two xsi:type="xsd:string">Two</Two> </MethodCall>

Ahora esto podría estar bien. Ciertamente hace el trabajo. Pero, ¿qué pasa si necesitas algo más que una string ? encoding/xml actualmente no soporta la interface{} .

Como puedes ver esto se complica. Si tuvieras que integrar una API SOAP, probablemente no sería tan malo. ¿Y si tuvieras varias, cada una con sus propias peculiaridades?

¿No sería bueno si pudieras hacer esto?

type MethodCall struct { One string Two string }

Luego diga a encoding/xml : "Este servidor quiere tipos xsi".

Para resolver este problema, creé github.com/webconnex/xmlutil . Es un trabajo en progreso. No tiene todas las características del encoding/xml / decodificador de encoding/xml , pero tiene lo que se necesita para SOAP.

Aquí hay un ejemplo de trabajo:

package main import ( "bytes" "encoding/xml" "fmt" "github.com/webconnex/xmlutil" "log" //"net/http" ) type Envelope struct { Body `xml:"soap:"` } type Body struct { Msg interface{} } type MethodCall struct { One string Two string } type MethodCallResponse struct { Three string } func main() { x := xmlutil.NewXmlUtil() x.RegisterNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi") x.RegisterNamespace("http://www.w3.org/2001/XMLSchema", "xsd") x.RegisterNamespace("http://www.w3.org/2003/05/soap-envelope", "soap") x.RegisterTypeMore(Envelope{}, xml.Name{"http://www.w3.org/2003/05/soap-envelope", ""}, []xml.Attr{ xml.Attr{xml.Name{"xmlns", "xsi"}, "http://www.w3.org/2001/XMLSchema-instance"}, xml.Attr{xml.Name{"xmlns", "xsd"}, "http://www.w3.org/2001/XMLSchema"}, xml.Attr{xml.Name{"xmlns", "soap"}, "http://www.w3.org/2003/05/soap-envelope"}, }) x.RegisterTypeMore("", xml.Name{}, []xml.Attr{ xml.Attr{xml.Name{"http://www.w3.org/2001/XMLSchema-instance", "type"}, "xsd:string"}, }) buf := new(bytes.Buffer) buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`) buf.WriteByte(''/n'') enc := x.NewEncoder(buf) env := &Envelope{Body{MethodCall{ One: "one", Two: "two", }}} if err := enc.Encode(env); err != nil { log.Fatal(err) } // Print request bs := buf.Bytes() bs = bytes.Replace(bs, []byte{''>'', ''<''}, []byte{''>'', ''/n'', ''<''}, -1) fmt.Printf("%s/n/n", bs) /* // Send response, SOAP 1.2, fill in url, namespace, and action var r *http.Response if r, err = http.Post(url, "application/soap+xml; charset=utf-8; action="+namespace+"/"+action, buf); err != nil { return } dec := x.NewDecoder(r.Body) */ // Decode response dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?> <soap:Envelope> <soap:Body> <MethodCallResponse> <Three>three</Three> </MethodCallResponse> </soap:Body> </soap:Envelope>`)) find := []xml.Name{ xml.Name{"", "MethodCallResponse"}, xml.Name{"http://www.w3.org/2003/05/soap-envelope", "Fault"}, } var start *xml.StartElement var err error if start, err = dec.Find(find); err != nil { log.Fatal(err) } if start.Name.Local == "Fault" { log.Fatal("Fault!") // Here you can decode a Soap Fault } var resp MethodCallResponse if err := dec.DecodeElement(&resp, start); err != nil { log.Fatal(err) } fmt.Printf("%#v/n/n", resp) }

Con el ejemplo anterior, utilizo el método Find para obtener el objeto de respuesta, o un fallo. Esto no es estrictamente necesario. También puedes hacerlo así:

x.RegisterType(MethodCallResponse{}) ... // Decode response dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?> <soap:Envelope> <soap:Body> <MethodCallResponse> <Three>three</Three> </MethodCallResponse> </soap:Body> </soap:Envelope>`)) var start *xml.StartElement var resp Envelope if err := dec.DecodeElement(&resp, start); err != nil { log.Fatal(err) } fmt.Printf("%#v/n/n", resp)

Find útil el método Find cuando sus datos se vean así:

<soap:Envelope> <soap:Body> <MethodResponse> <MethodResult> <diffgr:diffgram> <NewDataSet> <Table1 diffgr:id="Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted"> <Three>three</Three> </Table1> </NewDataSet> </diffgr:diffgram> </MethodResult> </MethodResponse> </soap:Body> </soap:Envelope>

Este es un DiffGram, parte de Microsoft .NET. Puede utilizar el método Find para llegar a Table1 . El método Decode y DecodeElement también funciona en DecodeElement . Por lo tanto, puede pasar un []MethodCallResponse si NewDataSet contiene más de un resultado.

Estoy de acuerdo con Zippower en que SOAP sí apesta. Pero, desafortunadamente, muchas empresas utilizan SOAP y, a veces, se ven obligados a usar estas API. Con el paquete xmlutil, espero que sea un poco menos doloroso trabajar con él.


Si bien todavía no hay nada en Go, hay gowsdl . Hasta ahora, parece funcionar lo suficientemente bien como para que pueda interactuar con varios servicios SOAP.

No utilizo el proxy SOAP que proporciona, que creo que no es compatible con auth, pero gowsdl genera las estructuras y el código que necesito del WSDL para reunir solicitudes y respuestas unmarshal, una gran victoria.


También hay wsdl-go .
Pero no lo he usado, así que realmente no puedo decirlo.


una opción es usar gsoap que produce un cliente C WSDL y luego usar ese cliente a través de GO con cgo