Sample Application described in WSDL using HTTP binding and showing messages

This is potential primer material that explores how to use the WSDL http binding to describe interactions with an HTTP service.  This is an example of music information and purchasing Web service.  It is styled after the CDDB database http://www.gracenote.com/gn_products/cddb.html and allmusic.com sites.  It has generated a number of questions where I don't think the WSDL as exists can express certain things.  I'm grateful for any reviews or comments on this.  It could be put into the primer as well.

An Artist has:
 - ID
 - Name
 - Biography
 - Genre
 - Image
 - Web site

Clients have 3 types of interactions: retrieve all/specific information, change/add/delete information, and search based upon a subset of the Artist fields. 

 - Get Artist complete information for a given Artist
 - Get Artist field contents (Name, Biography, etc.) for a given Artist
 - Add Artist
 - Update Artist
 - Get Artist list by Artist name, genre

Schema
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.w3.org/2002/ws/music/2004/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.w3.org/2002/ws/music/2004/" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="Music">
    <xs:complexType name="Music">
      <xs:sequence>
        <xs:element ref="tns:Artist" maxOccurs="unbounded"/>
        <xs:element ref="tns:ArtistRef" maxOccurs="unbounded"/>
        <xs:any namespace="##other" processContents="lax"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
  <!-- To do a /Music/Artist/5, need to have a type with only 1 child -->
  <xs:complexType name="ArtistIDBase">
    <xs:sequence>
      <xs:element name="id" type="xs:ID"/>
    </xs:sequence>
  </xs:complexType>
  
   <!-- When Adding an artist, the ID isn't known -->
  <xs:element name="ArtistWithoutID">
    <xs:complexType name="ArtistWithoutId">
      <xs:sequence>
        <xs:element name="Name" type="xs:string"/>
        <xs:element name="Biography" type="xs:string"/>
        <xs:element name="Genre" type="xs:string"/>
        <xs:element name="Image" type="xs:anyURI"/>
        <xs:element name="Site" type="xs:anyURI"/>
        <xs:any namespace="##other" processContents="lax"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
  <!-- Need to have ID + all of the fields for <artist> returns -->
  <!-- probably better modelling in schema to combine the id with the non-id fields -->
  <xs:element name="Artist">
    <xs:complexType name="Artist">
      <xs:complexContent>
        <xs:extension base="tns:ArtistIDBase">
          <xs:sequence>
            <xs:element name="Name" type="xs:string"/>
            <xs:element name="Biography" type="xs:string"/>
            <xs:element name="Genre" type="xs:string"/>
            <xs:element name="Image" type="xs:anyURI"/>
            <xs:element name="Site" type="xs:anyURI"/>
            <xs:any namespace="##other" processContents="lax"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  
  <!-- Need a query structure to do queries, ie &name=thieverycorp -->
   <xs:element name="ArtistQuery">
    <xs:complexType name="ArtistQuery">
      <xs:complexContent>
        <xs:extension base="tns:ArtistIDBase">
          <xs:sequence>
            <xs:element name="Name" type="xs:string" minOccurs="0"/>
            <xs:element name="Genre" type="xs:string" minOccurs="0"/>
            <xs:element name="Rating" type="xs:decimal" minOccurs="0"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  
  <!-- ID + REF structure for getting back list of IDs that can be used to create URI -->
  <xs:element name="ArtistIDRef">
    <xs:complexType name="ArtistIDRef">
      <xs:complexContent>
        <xs:extension base="tns:ArtistIDBase">
          <xs:sequence>
            <xs:element name="Name" type="xs:string"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  
  <!-- Artist Field names for doing field queries -->
  <xs:element name="ArtistIDFieldName" type="tns:ArtistField"/>
  <xs:complexType name="ArtistField">
    <xs:complexContent>
      <xs:extension base="tns:ArtistIDBase">
        <xs:sequence>
          <xs:element name="Field" type="tns:ArtistFieldNames"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  
  <!-- Artist Field Name + Value for setting field -->
  <xs:element name="ArtistFieldNameAndValue">
    <xs:complexType name="ArtistFieldNameAndValue">
      <xs:complexContent>
        <xs:extension base="tns:ArtistField">
          <xs:sequence>
            <xs:element name="Value"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  
  <!-- List of field names -->
  <xs:simpleType name="ArtistFieldNames">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Name"/>
      <xs:enumeration value="Biography"/>
      <xs:enumeration value="Genre"/>
      <xs:enumeration value="Image"/>
      <xs:enumeration value="Site"/>
    </xs:restriction>
  </xs:simpleType>
  
  <!-- URI for getting back opaque URIs -->
  <xs:complexType name="uri">
    <xs:sequence>
      <xs:element name="uri" type="xs:anyURI"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>



Interacting using the x-www-form-uriencoded style
WSDL

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:musicw="http://example.com/Artist" xmlns:wsdl="">
	<xs:import href="Music-Artist.xsd"/>
	<wsdl:interface name="Artist">
		<wsdl:operation name="ArtistSearch" method="GET">
			<wsdl:input ref="music:ArtistQuery"/>
			<wsdl:output ref="music:Music"/>
		</wsdl:operation>
		<wsdl:operation name="ArtistRefSearch" method="GET">
			<wsdl:input ref="music:ArtistQuery"/>
			<wsdl:output ref="music:Music"/>
		</wsdl:operation>
		<wsdl:operation name="GetArtist" method="GET">
			<wsdl:input ref="music:ArtistID"/>
			<wsdl:output ref="music:Artist"/>
		</wsdl:operation>

		<!-- Given a uri in a field for an artist, simply dereference the URI -->
		<wsdl:operation name="GetArtistOpaqueURI" method="GET">
			<wsdl:input ref="music:uri"/>
			<wsdl:output ref="music:ArtistWithoutURI"/>
		</wsdl:operation>
		
		<wsdl:operation name="GetFieldByFieldName" method="GET">
			<wsdl:input ref="music:ArtistFieldName"/>
			<wsdl:output ref="xsd:any"/>
		</wsdl:operation>
		<wsdl:operation name="AddArtistServerID" method="POST">
		   <wsdl:input ref="music:ArtistWithoutID"/>
		   <wsdl:output ref="music:ArtistRef"/>
		 </wsdl:operation>	 
		 <wsdl:operation name="AddArtistClientID" method="POST">
		   <wsdl:input ref="music:Artist"/>
		   <wsdl:output ref="music:ArtistRef"/>
		 </wsdl:operation>
		<wsdl:operation name="DeleteArtist" method="DELETE">
			<wsdl:input ref="music:ArtistID"/>
		</wsdl:operation>
		<wsdl:operation name="UpdateArtist" method="PUT">
			<wsdl:input ref="music:Artist"/>
			<wsdl:output ref="music:Artist"/>
		</wsdl:operation>
		<wsdl:operation name="UpdateField" method="PUT">
			<wsdl:input ref="music:ArtistFieldNameAndValue"/>
		</wsdl:operation>

	</wsdl:interface>
	<wsdl:binding name="Artist" interface="Artist" http:defaultMethod="GET">
	<wsdl:operation ref="ArtistSearch" location="Artist/{Name}"/>
	<wsdl:operation ref="ArtistRefSearch" location="ArtistRef/{Name}"/>
  	<wsdl:operation ref="GetArtist" location="Artist/{ID}"/>
  	<wsdl:operation ref="GetArtistOpaqueURI" location="{uri}"/>
  	<wsdl:operation ref="GetFieldByFieldname" location="Artist/{ID}/"/>
  	<wsdl:operation ref="AddArtistServerID" location="Artist" method="POST"/>
 	<wsdl:operation ref="AddArtistClientID" location="Artist" method="POST"/>
  	<wsdl:operation ref="DeleteArtist" location="Artist/{ID}" method="DELETE"/>
  	<wsdl:operation ref="UpdateArtist" location="Artist/{ID}" method="PUT"/>
  	<wsdl:operation ref="UpdateArtistField" location="Artist/{ID}" method="PUT"/>
	</wsdl:binding>
</wsdl:definitions>

Message Examples

Example: ArtistSearch 
GET /Music/Artist?genre="electronica"

Return:
<Music>
  <Artist>
    <ID>5</ID>
    <Name>Thievery Corp</Name> 
    <Genre>Electronica</Genre>
    <site>http://thievery.com</site>
  </Artist>
</Music>

Example: GetAllArtists
GET /Music/Artist

Returns:
<Music>
  <Artist>
    <ID>5</ID>
    <Name>Thievery Corp</Name>
    <Genre>Electronica</Genre>
    <site>http://thievery.com</site>
  </Artist>
</Music>

Example: GetArtistReferences
GET /Music/ArtistRef?genre="electronica"

Return:
<Music>
  <ArtistRef>
    <ID>5</ID>
    <Name>Thievery Corp</Name> 
  </ArtistRef>
</Music>

Example: GetArtist 
GET /Music/Artist/5

Return:
<Artist>
  <ID>5</ID>
  <Name>Thievery Corp</Name>
  <Genre>Electronica</Genre>
  <site>http://thievery.com</site>
</Artist>

Example: GetArtistOpaqueURI
* This assumes the URI="id/xyz"
GET /Music/Artist/id/zyz

Return:
<Artist>
  <Name>Thievery Corp</Name>
  <Genre>Electronica</Genre>
  <site>http://thievery.com</site>
</Artist>


Example: GetFieldByFieldName
GET /Music/Artist/5?field="site"

Return:
<site>http://thievery.com</site>

Example: AddArtistServerId
POST /Music/Artist
<Artist>
    <Name>Thievery Corp version 2</Name>
    <Genre>Electronica</Genre>
    <site>http://newbetterthievery.com</site>
</Artist>

Returns:
Content-Location: /Music/Artist/6
* How is the HTTP Content-location mapped to xml in this case?  Is it dropped?  Should there be XML returned?

Example: AddArtistClientID
* I don't think this works in the current WSDL http binding
POST /Music/Artist/7
<Artist>
    <ID>7</ID>
    <Name>Thievery Corp version 3</Name>
    <Genre>Electronica</Genre>
    <site>http://newwaybetterthievery.com</site>
</Artist>

Returns:
Content-Location: /Music/Artist/7

Example: DeleteArtist
DELETE /Music/Artist/5

Example: UpdateArtist
* I don't think this works in the current WSDL http binding
PUT /Music/Artist/5
<Artist>
    <ID>5</ID>
    <Name>Thievery Corp</Name>
    <Genre>Electronica</Genre>
    <site>http://newbetterthievery.com</site>
  </Artist>

Example: UpdateArtistField
* I don't think this works in the wsdl as is
PUT /Music/Artist/5/site
<site>http://newbetterthievery.com</site>

Received on Wednesday, 9 June 2004 20:11:45 UTC