The former InfoStructureBase (ISB) along with the catalogue of OIO standards has been replaced with digitaliser.dk. Closing up to a formal version 1.0
the current beta 4
has as the first release a public API. The ISB API was SOAP based with Web Services Security UsernameToken for authentication. The the WSDL's can still be seen in the former repository part:
- documentmanager.wsdl
- namespacemanager.wsdl
- reviewrequestmanager.wsdl
- searchmanager.wsdl
- subscriptionmanager.wsdl
- taxonomymanager.wsdl
As annonced in the last release note "Digitaliser.dk - nu med offentligt API og medlemspolitik for grupper og rig tekstredigering" this is based on (OIO)REST with POX responses. The documentation is in the form of endpoints and XML Schemas for the responses, and can be read online: http://api.digitaliser.dk/rest.
I have practically no experience with REST, so I started to google for hints on have to call a REST webservice with Axis2. I did'nt find much and it seem way to complex for likeing. I did found out that REST/POX services can be described with WSDL 2.0 Part: 1 and WSDL Version 2.0 Part 2: Adjuncts. I do not find these as easy reads so I looked for an example and found a post on Keith Chapmans blog "RESTfull Mashup with WSDL 2.0 - WSO2 Mashup Server". The WSDL for this exmaple. Another resource that I haven't really read yet is Lawrence Mandes article on IBM DeveloperWorks called "Describe REST Web services with WSDL 2.0".
Keith's example is quite complex and I wanted something simple to increase the likelihood of succes, so I choose to implement fetching a resource on digitaliser.dk. After cleaning up the example WSDL, removing complex parts, renaming and some trial and error I ended up with this WSDL:
1 <?xml version="1.0"?> 2 <wsdl2:description 3 xmlns:wsdl2="http://www.w3.org/ns/wsdl" 4 xmlns:wrpc="http://www.w3.org/ns/wsdl/rpc" 5 xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 6 xmlns:whttp="http://www.w3.org/ns/wsdl/http" 7 xmlns:wsdlx="http://www.w3.org/ns/wsdl-extensions" 8 xmlns:xs="http://www.w3.org/2001/XMLSchema" 9 xmlns:api1="http://api.digitaliser.dk/rest/1.0" 10 xmlns:xtns="http://rep.oio.dk/sweetxml.org/xml/xsd/20090306/digitaliser.dk/1.0/" 11 xmlns:wtns="http://rep.oio.dk/sweetxml.org/xml/wsdl/20090306/digitaliser.dk/1.0/" 12 targetNamespace="http://rep.oio.dk/sweetxml.org/xml/wsdl/20090306/digitaliser.dk/1.0/"> 13 <wsdl2:types> 14 <xs:import 15 schemaLocation="http://api.digitaliser.dk/schemas/rest/1.0/resource.xsd" 16 namespace="http://api.digitaliser.dk/rest/1.0" /> 17 <xs:schema 18 attributeFormDefault="unqualified" 19 elementFormDefault="qualified" 20 targetNamespace="http://rep.oio.dk/sweetxml.org/xml/xsd/20090306/digitaliser.dk/1.0/"> 21 <xs:element 22 name="identifier" 23 type="xs:string" /> 24 <xs:complexType 25 name="idWrapperType"> 26 <xs:sequence> 27 <xs:element 28 name="id" 29 type="xs:string" /> 30 </xs:sequence> 31 </xs:complexType> 32 <xs:element 33 name="idWrapper" 34 type="xtns:idWrapperType" /> 35 </xs:schema> 36 </wsdl2:types> 37 <wsdl2:interface 38 name="ResourceInterface"> 39 <wsdl2:operation 40 name="getResourceOperation" 41 pattern="http://www.w3.org/ns/wsdl/in-out" 42 wsdlx:safe="true"> 43 <wsdl2:input 44 element="xtns:idWrapper" 45 wsaw:Action="" /> 46 <wsdl2:output 47 element="api1:resource" 48 wsaw:Action="" /> 49 </wsdl2:operation> 50 </wsdl2:interface> 51 <wsdl2:binding 52 name="ResourceBinding" 53 interface="wtns:ResourceInterface" 54 type="http://www.w3.org/ns/wsdl/http"> 55 <wsdl2:operation 56 ref="wtns:getResourceOperation" 57 whttp:method="GET" 58 whttp:location="resources/{id}" /> 59 </wsdl2:binding> 60 <wsdl2:service 61 name="ResourceService" 62 interface="wtns:ResourceInterface"> 63 <wsdl2:endpoint 64 name="RestEndpoint" 65 binding="wtns:ResourceBinding" 66 address="http://api.digitaliser.dk/rest/resources" /> 67 </wsdl2:service> 68 </wsdl2:description>
The three major things for me where:
- Eksternal schemas can/must now be imported directly in the
types
section - no need for a wrapper schema anymore (and it will not work). Look at example 3-4 in the WSDL 2.0 primer or Importing XML Schema in the standard. - Even though it would be the easiest just to have a simpletype element for the request parameter in this example, I have to use a wrapper. The reason I guess is that this model can handle any number of parameters, where the case with just one is the simplest.
- @signature attribute does a reference to child elements in the wrapper defined in the former bullet.
With this WSDL I could generate Axis2 stub code with xmlbenas binding with the ant codegen
utility:
<codegen wsdlfilename="${resource.wsdl}" databindingName="xmlbeans" output="${generated.dir}" wsdlVersion="2.0" />
from here it's easy writing a simple client program. The request param is a little clunky since I'm using XMLBeans, but that's fine with me.
1 package org.sweetxml.rest; 2 3 import java.rmi.RemoteException; 4 import java.util.ArrayList; 5 import java.util.Collection; 6 import java.util.Iterator; 7 8 import org.apache.axis2.Constants; 9 import org.apache.xmlbeans.XmlOptions; 10 import org.apache.xmlbeans.XmlValidationError; 11 12 import dk.digitaliser.api.rest._1_0.ResourceDocument; 13 import dk.oio.rep.sweetxml_org.xml.wsdl._20090306.digitaliser_dk._1_0.ResourceServiceStub; 14 import dk.oio.rep.sweetxml_org.xml.xsd._20090306.digitaliser_dk._1_0.IdWrapperDocument; 15 16 public class ResourceClient { 17 18 public static void main(String[] args) throws RemoteException { 19 String resourceIdentifier = "42079"; 20 ResourceServiceStub stub = new ResourceServiceStub(); 21 stub._getServiceClient().getOptions().setProperty(Constants.Configuration.TRANSPORT_URL, "http://localhost:9999/rest/"); 22 23 IdWrapperDocument requestIdentifierDoc = IdWrapperDocument.Factory.newInstance(); 24 requestIdentifierDoc.addNewIdWrapper().setId(resourceIdentifier); 25 26 ResourceDocument respDoc = stub.getResourceOperation(requestIdentifierDoc); 27 System.out.println("Title on resource " + resourceIdentifier + " is : " + respDoc.getResource().getTitle()); 28 validate(respDoc); 29 } 30 31 private static void validate(ResourceDocument resource) { 32 Collection<XmlValidationError> errors = new ArrayList<XmlValidationError>(); 33 34 XmlOptions validationOptions = new XmlOptions(); 35 validationOptions.setErrorListener(errors); 36 validationOptions.setLoadLineNumbers(); 37 validationOptions.setSaveNamespacesFirst(); 38 validationOptions.setSavePrettyPrint(); 39 validationOptions.setSaveAggressiveNamespaces(); 40 validationOptions.setUseDefaultNamespace(); 41 42 boolean isValid = false; 43 isValid = resource.validate(validationOptions); 44 45 if (!isValid) { 46 Iterator<XmlValidationError> iter = errors.iterator(); 47 System.out.println(errors); 48 while (iter.hasNext()) { 49 XmlValidationError err = iter.next(); 50 System.out.println(err); 51 } 52 } else { 53 System.out.println("Respons is XML Schema Valid"); 54 } 55 } 56 }
I added a very basic validation method that should be enforced if I were to use this for real. Notice that I changed the endpoint to let it run through TCPMon and now finally lets have a look at how it looks like on the wire.
The request
Since this is REST and I'm only fetching a resource htis is just a GET
with only HTTP headers (and no SOAPAction
):
GET /rest/resources/42079 HTTP/1.1 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 SOAPAction: "" User-Agent: Axis2 Host: api.digitaliser.dk:9999
The reponse
The HTTP headers sent back is just plain, except that were informed that it's based on the Noelios Restlet Engine (NRE).
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Date: Fri, 13 Mar 2009 19:11:44 GMT Accept-Ranges: bytes Server: Noelios-Restlet-Engine/1.1..2 Content-Type: text/xml;charset=UTF-8 Transfer-Encoding: chunked
Here's hte body sent back containg the resource
strcuture as defined in the XML Schema.
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <ns1:resource 3 xmlns:ns1="http://api.digitaliser.dk/rest/1.0"> 4 <ns1:title>Demo WSDL for a simple service for OIOUBL Simpel Ordering</ns1:title> 5 <ns1:body>A naive WSDL for a demonstration service based on OIOUBL Simple Ordering to get a 6 realistic complexity.</ns1:body> 7 <ns1:ownerGroup 8 ns1:ref="http://api.digitaliser.dk/rest/groups/42078"> 9 <ns1:title>Sweetxml.org</ns1:title> 10 </ns1:ownerGroup> 11 <ns1:createdDate>2009-01-22T08:38:59.585+01:00</ns1:createdDate> 12 <ns1:published 13 ns1:state="published" 14 ns1:date="2009-01-22T08:42:28.616+01:00" /> 15 <ns1:taggedBy> 16 <ns1:tag 17 ns1:taggedItem="http://api.digitaliser.dk/rest/resources/42079" 18 ns1:owner="http://api.digitaliser.dk/rest/users/19802" 19 ns1:ref="http://api.digitaliser.dk/rest/tags/246143"> 20 <ns1:label>service</ns1:label> 21 </ns1:tag> 22 <ns1:tag 23 ns1:taggedItem="http://api.digitaliser.dk/rest/resources/42079" 24 ns1:owner="http://api.digitaliser.dk/rest/users/19802" 25 ns1:ref="http://api.digitaliser.dk/rest/tags/246139"> 26 <ns1:label>demo</ns1:label> 27 </ns1:tag> 28 <ns1:tag 29 ns1:taggedItem="http://api.digitaliser.dk/rest/resources/42079" 30 ns1:owner="http://api.digitaliser.dk/rest/groups/42078" 31 ns1:ref="http://api.digitaliser.dk/rest/tags/246996"> 32 <ns1:label>WSDL</ns1:label> 33 </ns1:tag> 34 <ns1:tag 35 ns1:taggedItem="http://api.digitaliser.dk/rest/resources/42079" 36 ns1:owner="http://api.digitaliser.dk/rest/users/19802" 37 ns1:ref="http://api.digitaliser.dk/rest/tags/246145"> 38 <ns1:label>webservice</ns1:label> 39 </ns1:tag> 40 <ns1:tag 41 ns1:taggedItem="http://api.digitaliser.dk/rest/resources/42079" 42 ns1:owner="http://api.digitaliser.dk/rest/groups/42078" 43 ns1:ref="http://api.digitaliser.dk/rest/tags/246995"> 44 <ns1:label>OIOUBL</ns1:label> 45 </ns1:tag> 46 </ns1:taggedBy> 47 <ns1:artefacts> 48 <ns1:artefact 49 ns1:ref="http://api.digitaliser.dk/rest/resources/42079/artefacts/SX_OIOUBLorderDemo.wsdl"> 50 <ns1:title>SX_OIOUBLorderDemo.wsdl</ns1:title> 51 </ns1:artefact> 52 </ns1:artefacts> 53 <ns1:uri>http://api.digitaliser.dk/rest/resources/42079</ns1:uri> 54 <ns1:versionGroup 55 ns1:ref="http://api.digitaliser.dk/rest/versiongroups/ff5aba78-c20c-4c70-9190-84527b81d731" /> 56 <ns1:classificationInstance /> 57 <ns1:version></ns1:version> 58 </ns1:resource>
Summary
I was very pleased that I was able to acces the REST API with Axis2, and that I was able to do it in contract-first style. Even more I was gladly surprised that WSDL 2.0 had the functionality to describe it well, since my only prior knowledge was from articles going against WSDL 2.0
3 comments :
Its nice to hear that you found my POST useful. The reason the example is complex is because I was trying to show how WSDL 2.0 could be used to describe this RESTfull scenario.
Here is another example scenario where I've used a hybrid approach.
Hi Keith
Your post was certainly very helpful and a nice read. Please excuse me if it could be read as is your WSDL was unessary, you were realizing a much more complex scenario.
Speaking of complex I've run into a problem trying to create the WSDL2 for the publish part of the API. For any new resource it's a two step process, where the first involves caling "/rest/objectid" which is easy to describe BUT the response is just the new identifier in "text/plain". Do you know if this can be modelled in WSDL 2.0/Axis2, since this response is schema/element-less.
Hii great reading your post
Post a Comment