Miré a mi alrededor y todo lo que pude encontrar es la compatibilidad con xml.Soporte WSDL/SOAP en Go?
¿Hay paquetes para admitir SOAP/WSDL en Go?
Miré a mi alrededor y todo lo que pude encontrar es la compatibilidad con xml.Soporte WSDL/SOAP en Go?
¿Hay paquetes para admitir SOAP/WSDL en Go?
Nope.
SOAP es una mierda, pero tuve que implementar un servidor de un protocolo ya definido que usa SOAP, así que escuché con net/http
y sobres descodificados/codificados con encoding/xml
. En pocos minutos, ya entregué mi primer sobre con Go.
Claro que sí, pero hay una infinidad de sistemas empresariales que solo admiten SOAP. Para esos casos, todavía necesitamos algo útil. – fiorix
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 a partir del WSDL, o se hace sobre la marcha con tablas hash.
Sin embargo, puede codificar y decodificar solicitudes SOAP manualmente. Descubrí que el paquete estándar encoding/xml
es insuficiente para SOAP. Hay tantos caprichos en servidores diferentes, y las limitaciones en encoding/xml
hacen que sea difícil generar una solicitud con la que estos servidores estén satisfechos. Por ejemplo, algunos servidores necesitan xsi:type="xsd:string"
en cada etiqueta de cadena. Con el fin de hacer esto correctamente su estructura debe tener este aspecto para encoding/xml
:
type MethodCall struct {
One XSI
Two XSI
}
type XSI struct {
Type string `xml:"xsi:type,attr"`
Vaue string `xml:",chardata"`
}
Y se construye de esta manera:
MethodCall{
XSI{"xsd:string", "One"},
XSI{"xsd:string", "Two"},
}
que le ofrece:
<MethodCall>
<One xsi:type="xsd:string">One</One>
<Two xsi:type="xsd:string">Two</Two>
</MethodCall>
Ahora bien, este podría estar bien. Sin duda hace el trabajo. Pero, ¿y si necesitaras algo más que un string
? encoding/xml
actualmente no es compatible con interface{}
.
Como puede ver, esto se complica. Si tuviera una API SOAP para integrar, probablemente no sería tan malo. ¿Qué pasaría si tuviera varios, cada uno con sus propios caprichos?
¿No sería lindo si pudieras hacer esto?
type MethodCall struct {
One string
Two string
}
Entonces dicen 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 codificador/decodificador encoding/xml
, pero tiene lo que se necesita para SOAP.
Aquí está 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 respuesta, o un fallo. Esto no es estrictamente necesario. También puede hacerlo de esta manera:
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)
Encontrará el método Find
útil cuando los datos se ve 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 usar el método Find
para obtener Table1
. El método Decode
y DecodeElement
también funciona en sectores. De modo que puede pasar un []MethodCallResponse
si NewDataSet
contiene más de un resultado.
Estoy de acuerdo con Zippower que SOAP apesta. Desafortunadamente, muchas empresas usan SOAP, y algunas veces se ve obligado a utilizar estas API. Con el paquete xmlutil espero que sea un poco menos doloroso trabajar con él.
Go tip ahora es compatible con [Marsalers] (http://tip.golang.org/pkg/encoding/xml/#Marshaler) y [Unmarshalers] (http://tip.golang.org/pkg/encoding/xml/# Unmarshaler) en codificación/xml como encoding/json ya lo hizo, y se espera que esta característica esté en Go 1.2. Esto podría ayudar con el manejo de SOAP. – Matt
Funciona muy bien @luke, su pequeña utilidad xml lib ... js necesita una documentación de inicio, aunque con unos minutos de escaneo a través del script anterior pude entender cómo hacer las cosas – Knights
Escribí un analizador WSDL que puede generar código Go para llamar a SOAP. Hay muchas limitaciones en la codificación/xml con respecto a las etiquetas, y puse un enlace a eso en el archivo README. Échale un vistazo: https://github.com/fiorix/wsdl2go – fiorix
Si bien todavía no hay nada en sí mismo Go, hay gowsdl. Hasta ahora, parece funcionar lo suficientemente bien como para 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 ordenar las solicitudes y las respuestas unmarshal, una gran ganancia.
También hay wsdl-go.
Pero no lo he usado, entonces realmente no puedo decirlo.
This parece que ya no existe. –
Gracias por el pequeño paquete XML/SOAP, hizo bien el trabajo. Los chicos pueden encontrar la lib aquí - https://github.com/webconnex/xmlutil – Knights
A menudo tengo que usar SOAP en sistemas heredados, y lo he estado haciendo mediante estructuras de codificación en Go hasta el fin de semana pasado. Hackeado un generador de código analizador + Go para WSDL que puede producir código Go utilizable para llamar a SOAP. Algunas de las API que uso son bastante extensas, generando archivos con más de 2k LOC. Échale un vistazo: https://github.com/fiorix/wsdl2go – fiorix