web-dev-qa-db-fra.com

Appeler SOAP avec Golang

Je suis nouveau sur golang et j'essaye de faire un appel savon avec gowsdl .

J'ai généré le code wsdl et l'ai installé sous forme de package. J'ai cependant du mal à comprendre la syntaxe pour appeler la méthode à partir d'elle.

Lorsque j'examine le paquet, voici ce que je veux dans le corps du savon:

type AccountUser struct {
    XMLName xml.Name `xml:"http://exacttarget.com/wsdl/partnerAPI AccountUser"`

    *APIObject

    AccountUserID             int32         `xml:"AccountUserID,omitempty"`
    UserID                    string        `xml:"UserID,omitempty"`
    Password                  string        `xml:"Password,omitempty"`
    Name                      string        `xml:"Name,omitempty"`
    Email                     string        `xml:"Email,omitempty"`
    MustChangePassword        bool          `xml:"MustChangePassword,omitempty"`
    ActiveFlag                bool          `xml:"ActiveFlag,omitempty"`
    ChallengePhrase           string        `xml:"ChallengePhrase,omitempty"`
    ChallengeAnswer           string        `xml:"ChallengeAnswer,omitempty"`
    UserPermissions           []*UserAccess `xml:"UserPermissions,omitempty"`
    Delete                    int32         `xml:"Delete,omitempty"`
    LastSuccessfulLogin       time.Time     `xml:"LastSuccessfulLogin,omitempty"`
    IsAPIUser                 bool          `xml:"IsAPIUser,omitempty"`
    NotificationEmailAddress  string        `xml:"NotificationEmailAddress,omitempty"`
    IsLocked                  bool          `xml:"IsLocked,omitempty"`
    Unlock                    bool          `xml:"Unlock,omitempty"`
    BusinessUnit              int32         `xml:"BusinessUnit,omitempty"`
    DefaultBusinessUnit       int32         `xml:"DefaultBusinessUnit,omitempty"`
    DefaultApplication        string        `xml:"DefaultApplication,omitempty"`
    Locale                    *Locale       `xml:"Locale,omitempty"`
    TimeZone                  *TimeZone     `xml:"TimeZone,omitempty"`
    DefaultBusinessUnitObject *BusinessUnit `xml:"DefaultBusinessUnitObject,omitempty"`

    AssociatedBusinessUnits struct {
        BusinessUnit []*BusinessUnit `xml:"BusinessUnit,omitempty"`
    } `xml:"AssociatedBusinessUnits,omitempty"`

    Roles struct {
        Role []*Role `xml:"Role,omitempty"`
    } `xml:"Roles,omitempty"`

    LanguageLocale *Locale `xml:"LanguageLocale,omitempty"`

    SsoIdentities struct {
        SsoIdentity []*SsoIdentity `xml:"SsoIdentity,omitempty"`
    } `xml:"SsoIdentities,omitempty"`
}

Et la méthode pour appeler le SOAP est:

func (s *SOAPClient) Call(soapAction string, request, response interface{}) error {
    envelope := SOAPEnvelope{
    //Header:        SoapHeader{},
    }

    envelope.Body.Content = request
    buffer := new(bytes.Buffer)

    encoder := xml.NewEncoder(buffer)
    //encoder.Indent("  ", "    ")

    if err := encoder.Encode(envelope); err != nil {
        return err
    }

    if err := encoder.Flush(); err != nil {
        return err
    }

    log.Println(buffer.String())

    req, err := http.NewRequest("POST", s.url, buffer)
    if err != nil {
        return err
    }
    if s.auth != nil {
        req.SetBasicAuth(s.auth.Login, s.auth.Password)
    }

    req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"")
    if soapAction != "" {
        req.Header.Add("SOAPAction", soapAction)
    }

    req.Header.Set("User-Agent", "gowsdl/0.1")
    req.Close = true

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: s.tls,
        },
        Dial: dialTimeout,
    }

    client := &http.Client{Transport: tr}
    res, err := client.Do(req)
    if err != nil {
        return err
    }
    defer res.Body.Close()

    rawbody, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return err
    }
    if len(rawbody) == 0 {
        log.Println("empty response")
        return nil
    }

    log.Println(string(rawbody))
    respEnvelope := new(SOAPEnvelope)
    respEnvelope.Body = SOAPBody{Content: response}
    err = xml.Unmarshal(rawbody, respEnvelope)
    if err != nil {
        return err
    }

    fault := respEnvelope.Body.Fault
    if fault != nil {
        return fault
    }

    return nil
}

J'ai importé le package dans mon fichier go et j'aimerais avoir des conseils sur la façon d'appeler cela.

8
Samuel Dare

Pour utiliser le code généré, vous devrez évidemment initialiser d'abord le client soap avec l'une des fonctions "constructeur" générées NewSOAPClient ou NewSOAPClientWithTLSConfig.

Après cela, vous devrez préparer des valeurs two que vous pouvez utiliser comme arguments de demande et de réponse à la méthode Call, elles représentent le contenu du corps des charges utiles de demande/réponse de savon.

Les types de ces deux valeurs dépendent du type d'appel que vous souhaitez effectuer, par exemple les appels hypothétiques create_account, update_account et delete_account nécessitent généralement des types différents. Fondamentalement, le type de la valeur request doit être marshalable dans un xml qui correspond au xml attendu par le service soap pour l'action spécifiée , et le type de response doit être non commercialisable à partir d'un xml qui correspond à la réponse documentée du service soap pour l'action spécifiée.


Considérez cet exemple artificiel:

Il existe un service SOAP qui vous permet de créer des utilisateurs. Pour que vous puissiez créer un utilisateur avec le service, vous devez envoyer un e-mail et un mot de passe, et si tout est ok, il le fera renvoie un identifiant. Dans un tel cas, vos deux types de demande/réponse devraient ressembler à ceci:

type CreateUserRequest struct {
    Email    string `xml:"Email,omitempty"`
    Password string `xml:"Password,omitempty"`
}

type CreateUserResponse struct {
    ID string `xml:"ID"`
}

Ensuite, le code client ressemblerait à ceci:

client := NewSOAPClient("https://soap.example.com/call", true, nil)

req := &CreateUserRequest{
    Email:    "[email protected]",
    Password: "1234567890",
}
res := &CreateUserResponse{}
if err := client.Call("create_user", req, res); err != nil {
    panic(err)
}

// if everything went well res.ID should have its
// value set with the one returned by the service.
fmt.Println(res.ID)
6
mkopriva