Python + Zeep で、WSDLで定義された SOAP API エンドポイントとは別のエンドポイントにアクセスする

SOAP APIのテストなどでは、

  • WSDLの定義とは別のエンドポイント(テスト用エンドポイント)にアクセスしたい
  • ただし、WSDLは修正したくない

という状況があるかもしれません。

 
そこで、Zeepではどのようにやるのかを調べた時のメモを残します。

 

目次

 

環境

 

方法

公式ドキュメントに記載がありました。 ServiceProxy オブジェクトを使えば良いようです。
Creating new ServiceProxy objects | The Client object — Zeep 3.1.0 documentation

 

検証

実際に試してみます。

 

SOAP APIの仕様

以下のようなBindingのWSDLを持つSOAP APIがあるとします。

項目
名前空間 http://example.com/HelloWorld
エンドポイント http://localhost:8088/mockHelloBindingSoap11
メソッド requestMessage()
メソッドの挙動 引数に値を渡してリクエストすると、 Hello, <引数の値> がレスポンスされる

 
実際のWSDL (Hello.wsdl) はこちら。

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns:soap11="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
        xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:ns0="http://example.com/HelloWorld"
        targetNamespace="http://example.com/HelloWorld">

    <wsdl:types>
        <xsd:schema elementFormDefault="qualified" targetNamespace="http://example.com/HelloWorld">
            <xsd:element name="RequestInterface">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element minOccurs="0" name="userName" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element name="ResponseInterface">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element minOccurs="0" name="returnMessage" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
        </xsd:schema>
    </wsdl:types>

    <wsdl:message name="messageIn">
        <wsdl:part name="parameters" element="ns0:RequestInterface" />
    </wsdl:message>
    <wsdl:message name="messageOut">
        <wsdl:part name="parameters" element="ns0:ResponseInterface" />
    </wsdl:message>

    <wsdl:portType name="HelloPort">
        <wsdl:operation name="requestMessage">
            <wsdl:input message="ns0:messageIn"/>
            <wsdl:output message="ns0:messageOut"/>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="HelloBindingSoap11" type="ns0:HelloPort">
        <soap11:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <wsdl:operation name="requestMessage">
            <soap11:operation soapAction="http://example.com/HelloWorld/requestMessage" />
            <wsdl:input>
                <soap11:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap11:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="HelloService">
        <wsdl:port name="HelloServicePort" binding="ns0:HelloBindingSoap11">
            <soap11:address location="http:/example.com/hello"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

 
ただ、本番のエンドポイント http:/example.com/hello が現在稼働していないため、そのままではテストできない状況とします。

 
そこで、 http:/example.com/hello ではなく、ローカルのポートにアクセスさせることにより、テストを実施させるとします。

また、その時のローカルでは、ポート 9100 にてSOAP APIがLISTENしているとします。

$ sudo lsof -i -P | grep "LISTEN"

...
... TCP *:9100 (LISTEN)

 

実装

ZeepでSOAPクライアントを作るところは、今までと同じです。

import pathlib

from zeep import Client

WSDL = pathlib.Path(__file__).parents[0].joinpath('Hello.wsdl')

client = Client(str(WSDL))

 
次に、Clientオブジェクトの create_service() を使い、Service Proxyを生成します。

create_service() の引数は、それぞれ以下となります。

  • 第一引数は、差し替え元の名前空間付きBinding名
  • 第二引数は、差し替え後のエンドポイント
service = client.create_service(
    '{http://example.com/HelloWorld}HelloBindingSoap11',
    'http://localhost:9100/hello'
)

 
あとは Service Proxyオブジェクトを使い、 requestMessage() を呼び出します。

response = service.requestMessage(userName='taro')

print(type(response))
print(response)

 
このスクリプトを実行すると、

<class 'str'>
Hello, taro

と、エンドポイントが差し替えられたことが分かりました。

 

ソースコード

GitHubに上げました。 chanbge_endpoint ディレクトリが今回のものです。
https://github.com/thinkAmi-sandbox/python_zeep-sample