<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IONCANNON &#187; GAE</title>
	<atom:link href="http://www.ioncannon.net/tag/gae/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ioncannon.net</link>
	<description>Thoughts on Software Development and Engineering</description>
	<lastBuildDate>Tue, 03 Jan 2012 13:59:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
	<atom:link rel='hub' href='http://www.ioncannon.net/?pushpress=hub'/>
		<item>
		<title>SOAP on the Google App Engine platform</title>
		<link>http://www.ioncannon.net/programming/180/soap-on-the-google-app-engine-platform/</link>
		<comments>http://www.ioncannon.net/programming/180/soap-on-the-google-app-engine-platform/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 03:35:25 +0000</pubDate>
		<dc:creator>carson</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[GAE]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[SOAP]]></category>
		<category><![CDATA[web services]]></category>

		<guid isPermaLink="false">http://www.ioncannon.net/?p=180</guid>
		<description><![CDATA[I generally don&#039;t recomend using SOAP instead of REST but I have been required to use SOAP so much now that I think it is inevitably going to be a requirement for a long time for certain projects. So when I noticed a question on stack overflow about using SOAP on the Google App Engine [...]]]></description>
			<content:encoded><![CDATA[<p>I generally don&#039;t recomend using <a href="http://www.ioncannon.net/web-services/117/soap-vs-rest/">SOAP instead of REST</a> but I have been required to use SOAP so much now that I think it is inevitably going to be a requirement for a long time for certain projects. So when I noticed a question on <a href="http://stackoverflow.com/questions/331600/how-to-write-a-web-service-for-google-app-engine">stack overflow</a> about using SOAP on the <a href="http://code.google.com/appengine/">Google App Engine</a> I thought it might be a nice exercise to see how easy it is to get fringe toolsets to work in the GAE.</p>
<p><span id="more-180"></span></p>
<p>I&#039;m going to assume basic knowledge of the GAE system. If you haven&#039;t already tried it out you should read the <a href="http://code.google.com/appengine/docs/gettingstarted/">getting started guide</a>. You shouldn&#039;t need to know any more than what is in that guide to work through this example. I also assume knowledge of creating <a href="http://www.w3.org/TR/wsdl">WSDL</a> files by hand. You will need to be able to do this to generate the SOAP server and client. You can find a <a href="http://www.w3schools.com/WSDL/default.asp">WSDL tutorial here</a> that may help. I also recommend creating an empty directory that will house your project for this example.</p>
<p>The first step involves getting a library from the <a href="http://pywebsvcs.sourceforge.net/">Python Web Services</a> project. You will want to download the <a href="http://sourceforge.net/project/showfiles.php?group_id=26590&#038;package_id=30660&#038;release_id=551193">ZSI 2.1a1</a> package (grab the the tgz file: ZSI-2.1-a1.tar.gz). This is the current alpha release of ZSI but the current stable release won&#039;t work. The stable release has a problem with the expat library but the problem is fixed in 2.1. It is also worth stating that ZSI 2.1 seems to be better put together. Extract the files into a temp directory and then copy only the directory named &#034;ZSI&#034; into your project directory.</p>
<p>Next you will need to get <a href="http://pypi.python.org/pypi/zope.interface">zope.interface</a>. Go to the <a href="http://pypi.python.org/pypi/zope.interface#download">zope.interface download page</a> and find the file named: zope.interface-3.5.0.zip. Unzip this file in a temp directory and then copy the directory named &#034;zope&#034; into your project.</p>
<p>These two external libraries are all you need to create a Python SOAP service. The next step in creating the service involves using the <a href="http://code.google.com/appengine/docs/gettingstarted/usingwebapp.html">GAE webapp framework</a> so it would help to read up on that. This framework works with <a href="http://www.wsgi.org/wsgi/">WSGI</a> and it may also help to <a href="http://www.wsgi.org/wsgi/Learn_WSGI">learn about WSGI</a> as well. I referenced the <a href="http://code.google.com/appengine/articles/django.html">django example</a> and <a href="http://appengine-cookbook.appspot.com/recipe/match-webapp-urls-using-routes/">example of using routes</a> to get an idea of what needed to be done to connect the GAE WSGI up to the ZSI SOAP service. They both use the  <a href="http://code.google.com/appengine/docs/webapp/wsgiapplicationclass.html">WSGIApplication</a> webapp call to tie in their output with the WSGI framework and that is common to all applications that use the webapp framework.</p>
<p>Now that all the libraries are in place and the WSGI and GAE webapp interface make some sense it is time to move on to creating a WSDL file. Here is a simple one that I used for the test:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;definitions</span> </span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns</span>=<span class="st0">&quot;http://schemas.xmlsoap.org/wsdl/&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns:soap</span>=<span class="st0">&quot;http://schemas.xmlsoap.org/wsdl/soap/&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns:soapenc</span>=<span class="st0">&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns:http</span>=<span class="st0">&quot;http://schemas.xmlsoap.org/wsdl/http/&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns:xsd</span>=<span class="st0">&quot;http://www.w3.org/2001/XMLSchema&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xmlns:tns</span>=<span class="st0">&quot;urn:ZSI&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">targetNamespace</span>=<span class="st0">&quot;urn:ZSI&quot;</span> <span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;types<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;xsd:schema</span> <span class="re0">elementFormDefault</span>=<span class="st0">&quot;qualified&quot;</span> <span class="re0">targetNamespace</span>=<span class="st0">&quot;urn:ZSI&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsd:element</span> <span class="re0">name</span>=<span class="st0">&quot;Echo&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsd:complexType<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsd:sequence<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;xsd:element</span> <span class="re0">name</span>=<span class="st0">&quot;value&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;xsd:anyType&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsd:sequence<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsd:complexType<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/xsd:element<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/xsd:schema<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/types<span class="re2">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; <span class="sc3"><span class="re1">&lt;message</span> <span class="re0">name</span>=<span class="st0">&quot;EchoRequest&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;part</span> <span class="re0">name</span>=<span class="st0">&quot;parameters&quot;</span> <span class="re0">element</span>=<span class="st0">&quot;tns:Echo&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/message<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; <span class="sc3"><span class="re1">&lt;message</span> <span class="re0">name</span>=<span class="st0">&quot;EchoResponse&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;part</span> <span class="re0">name</span>=<span class="st0">&quot;parameters&quot;</span> <span class="re0">element</span>=<span class="st0">&quot;tns:Echo&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/message<span class="re2">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; <span class="sc3"><span class="re1">&lt;portType</span> <span class="re0">name</span>=<span class="st0">&quot;EchoServer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;operation</span> <span class="re0">name</span>=<span class="st0">&quot;Echo&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">message</span>=<span class="st0">&quot;tns:EchoRequest&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;output</span> <span class="re0">message</span>=<span class="st0">&quot;tns:EchoResponse&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/operation<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/portType<span class="re2">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; <span class="sc3"><span class="re1">&lt;binding</span> <span class="re0">name</span>=<span class="st0">&quot;EchoServer&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;tns:EchoServer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;soap:binding</span> <span class="re0">style</span>=<span class="st0">&quot;document&quot;</span> </span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">transport</span>=<span class="st0">&quot;http://schemas.xmlsoap.org/soap/http&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;operation</span> <span class="re0">name</span>=<span class="st0">&quot;Echo&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;soap:operation</span> <span class="re0">soapAction</span>=<span class="st0">&quot;Echo&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;input<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;soap:body</span> <span class="re0">use</span>=<span class="st0">&quot;literal&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/input<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;output<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;soap:body</span> <span class="re0">use</span>=<span class="st0">&quot;literal&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/output<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/operation<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/binding<span class="re2">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; <span class="sc3"><span class="re1">&lt;service</span> <span class="re0">name</span>=<span class="st0">&quot;EchoServer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;port</span> <span class="re0">name</span>=<span class="st0">&quot;EchoServer&quot;</span> <span class="re0">binding</span>=<span class="st0">&quot;tns:EchoServer&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;soap:address</span> <span class="re0">location</span>=<span class="st0">&quot;http://gae.ioncannon.net/echo&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/port<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/service<span class="re2">&gt;</span></span></span></p>
<p><span class="sc3"><span class="re1">&lt;/definitions<span class="re2">&gt;</span></span></span></div>
</div>
<p>Notice at the bottom I set the address to the location of my test service along with the application domain name. This is where the application will end up in production. If you want to test first you can stick your localhost information in there instead.</p>
<p>Next you will need to run the wsdl2py application that comes with ZSI on your WSDL file to generate the classes needed for the server. To do this I simply copied the wsdl2py application into the project and ran the following command:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">python wsdl2py SimpleEcho.wsdl</div>
</div>
<p>After you do this you will find a couple new files in your project directory. I then removed the wsdl2py application so it didn&#039;t get uploaded later.</p>
<p>Next create the test endpoint application itself. For this example I named the file echo.py and added the hooks that connect the service to the WSGI interface:</p>
<div class="codesnip-container" >
<div class="python codesnip" style="font-family:monospace;"><span class="kw1">import</span> <span class="kw3">sys</span><br />
<span class="kw1">from</span> google.<span class="me1">appengine</span>.<span class="me1">ext</span> <span class="kw1">import</span> webapp<br />
<span class="kw1">from</span> google.<span class="me1">appengine</span>.<span class="me1">ext</span>.<span class="me1">webapp</span>.<span class="me1">util</span> <span class="kw1">import</span> run_wsgi_app<br />
<span class="kw1">from</span> EchoServer_server <span class="kw1">import</span> <span class="sy0">*</span><br />
<span class="kw1">from</span> ZSI.<span class="me1">twisted</span>.<span class="me1">wsgi</span> <span class="kw1">import</span> SOAPApplication, soapmethod, SOAPHandlerChainFactory, WSGIApplication<br />
&nbsp;<br />
<span class="kw1">class</span> EchoService<span class="br0">&#40;</span>SOAPApplication<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; factory = SOAPHandlerChainFactory<br />
&nbsp; &nbsp; wsdl_content = <span class="kw2">dict</span><span class="br0">&#40;</span>name=<span class="st0">&#039;Echo&#039;</span>, targetNamespace=<span class="st0">&#039;urn:echo&#039;</span>, imports=<span class="br0">&#40;</span><span class="br0">&#41;</span>, portType=<span class="st0">&#034;</span><span class="br0">&#41;</span><br />
&nbsp;<br />
&nbsp; &nbsp; @soapmethod<span class="br0">&#40;</span>EchoRequest.<span class="me1">typecode</span>, EchoResponse.<span class="me1">typecode</span>, operation=<span class="st0">&#039;Echo&#039;</span>, soapaction=<span class="st0">&#039;Echo&#039;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> soap_Echo<span class="br0">&#40;</span><span class="kw2">self</span>, request, response, <span class="sy0">**</span>kw<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; response = request<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> request,response<br />
&nbsp;<br />
application = WSGIApplication<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
application<span class="br0">&#91;</span><span class="st0">&#039;echo&#039;</span><span class="br0">&#93;</span> = EchoService<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp;<br />
<span class="kw1">def</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; run_wsgi_app<span class="br0">&#40;</span>application<span class="br0">&#41;</span><br />
&nbsp;<br />
<span class="kw1">if</span> __name__ == <span class="st0">&quot;__main__&quot;</span>:<br />
&nbsp; main<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</div>
<p>Next create the application description file app.yaml that is needed to upload and install the application in the GAE. For simplicity I just map everything to the main program:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">application: iechotest<br />
version: 1<br />
runtime: python<br />
api_version: 1<br />
&nbsp;<br />
handlers:<br />
- url: /.*<br />
&nbsp; script: echo.py</div>
</div>
<p>At this point my project directory looked like this:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">soaptest/<br />
&nbsp; &nbsp; ZSI/&lt;zsi files&gt;<br />
&nbsp; &nbsp; zope/&lt;zope interface files&gt;<br />
&nbsp; &nbsp; app.yaml &nbsp;<br />
&nbsp; &nbsp; EchoServer_client.py &nbsp;<br />
&nbsp; &nbsp; EchoServer_types.py &nbsp;<br />
&nbsp; &nbsp; EchoServer_server.py<br />
&nbsp; &nbsp; echo.py &nbsp;<br />
&nbsp; &nbsp; SimpleEcho.wsdl</div>
</div>
<p>The application is ready to be uploaded to GAE at this point. After uploading you can stick the endpoint URL into a browser and you should see a message saying &#034;NO RESOURCE FOR GET&#034;.  If you get some type of error use the logs in your application console to look at the application stack trace. If there are no errors you are ready to build a client to test the SOAP service.</p>
<p>To create the client you use the same WSDL file with wsdl2py again. This actually generates the same class files and you need the same libraries in place to run it. The following example client will test the service:</p>
<div class="codesnip-container" >
<div class="python codesnip" style="font-family:monospace;"><span class="kw1">from</span> EchoServer_client <span class="kw1">import</span> <span class="sy0">*</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span>, <span class="kw3">time</span><br />
&nbsp;<br />
TRACE=<span class="kw2">None</span><br />
loc = EchoServerLocator<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
port = loc.<span class="me1">getEchoServer</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>msg = EchoRequest<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
msg._value = 1<br />
rsp = port.<span class="me1">Echo</span><span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;INTEGER: &quot;</span>, rsp._value</p>
<p>
msg._value = <span class="st0">&quot;HI&quot;</span><br />
rsp = port.<span class="me1">Echo</span><span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;STRING: &quot;</span>, rsp._value</p>
<p>msg._value = 1.10000<br />
rsp = port.<span class="me1">Echo</span><span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;FLOAT: &quot;</span>, rsp._value</p>
<p>msg._value = <span class="kw2">dict</span><span class="br0">&#40;</span>milk=<span class="kw2">dict</span><span class="br0">&#40;</span>cost=<span class="nu0">3.15</span>, unit=<span class="st0">&quot;gal&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</div>
<p>As long as the service is in the same place as the WSDL location setting you don&#039;t need to specify an endpoint for the getServer call.</p>
<p>And that is all there is to it. It is fairly involved but if you already understand some of the concepts here it seems fairly strait forward. Along the way I found a <a href="http://www.lokad.com/web-services-time-series-forecasting-tutorial-python.ashx">SOAP tutorial</a> for Python that may be helpful as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioncannon.net/programming/180/soap-on-the-google-app-engine-platform/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

