web-dev-qa-db-ja.com

GolangでSOAPを呼び出す

私はgolangを初めて使用し、 gowsdl を使用してsoap呼び出しを試みます。

Wsdlコードを生成し、パッケージとしてインストールしました。しかし、メソッドを呼び出すための構文を理解するのに苦労しています。

私がパッケージを調べるとき、これは私が石鹸本体に欲しいものです:

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"`
}

そしてSOAPを呼び出すメソッドは次のとおりです:

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
}

私は自分のgoファイルにパッケージをインポートしましたが、これをどのように呼び出すかについてのポインタが大好きです。

8
Samuel Dare

生成されたコードを使用するには、最初に、生成された「コンストラクター」関数NewSOAPClientまたはNewSOAPClientWithTLSConfigの1つでSOAPクライアントを初期化する必要があります。

その後、Callメソッドへの要求および応答引数として使用できるtwo値を準備する必要があります。これらの値は、SOAP要求/応答ペイロードの本体コンテンツを表します。

これら2つの値のタイプは、どのような種類の呼び出しを行うかによって異なります。たとえば、架空の呼び出しcreate_account、update_account、およびdelete_accountは通常、異なるタイプを必要とします。基本的に、request値のタイプは、marshalableで、指定されたアクションのSOAPサービスで予期されるXMLと一致するXMLにする必要があります、およびresponseのタイプは、指定されたアクションに対するSOAPサービスの文書化された応答と一致するxmlからのunmarshalableである必要があります。


この不自然な例を考えてみましょう:

ユーザーを作成できるSOAPサービスがあります。このサービスを使用してユーザーを作成できるようにするには、メールとパスワードを送信する必要があります。問題がなければ、 IDを返します。このような場合、2つの要求/応答タイプは次のようになります。

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

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

次に、クライアントコードは次のようになります。

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