I keep getting bogged down in
what I’d call a “technology” gap between web services implemented on top of HTTP
and web services implemented (potentially) on top of other protocols. I’ve been
having a lot of discussions around this lately and I thought I’d blog what I’ve
been thinking about as a means of getting my thoughts in order and, thereby,
preserving my sanity J
The problem arises for me
because HTTP is implicitly a request-response protocol and the technologies that
we have for building web services today take “advantage” of that fact to
implement their services in a particular way.
Imagine a scenario where I have
a distributor of products who orders their products from a number of suppliers.
The suppliers implement a web-service interface that allows the distributor to
order from them.
So, for discussion, imagine that
the supplier will need to send a request message something like;
<?xml
version="1.0"
encoding="utf-8"
?>
<Order
xmlns="urn:supplies-com">
<WidgetOrder
Quantity="500"
WidgetName="Buttons"/>
</Order>
And that seems fine and then I’d
imagine that the supplier might send back a message that looks something like;
<?xml
version="1.0"
encoding="utf-8"
?>
<Supply
xmlns="urn:supplies- com">
<Goods
HoldDays="2"
Quantity="50"
WidgetName="Buttons"/>
</Supply>
So, that all seems fine. If
we’re modelling this kind of interaction with web services then we’d probably go
ahead and build a WSDL operation that described this interchange;
<portType
name="OrderWidgetsPort">
<operation
name="OrderWidgets">
<input
message="WidgetOrderMessage"
/>
<output
message="WidgetOrderResponseMessage"
/>
</operation>
</portType>
And this is where I start to hit
problems. It’s not immediately obvious so let me explain why.
The WSDL document says that we
have an operation that consumes one message and produces another message. What
is does not say is whether, as a consumer of the service, you should assume
that the response is produced synchronously with respect to the receipt of the
request.
If we go and implement this kind
of WSDL operation on top of HTTP/ASMX then we’d end up with a service
implementation (and, proxy clients for it) which assumed that the
response to the request message is available within the timeout period of the
HTTP protocol. That is, we’d submit a request message and the client would then
sit and wait for the WidgetOrderResponseMessage to be returned down the
HTTP response stream. If no response was available then the client will fail.
ASMX does have asynchronous support both in server-side implementation and
client-side proxies but, still, if the HTTP request is left to time out then we
will still fail and so this asynchronous support will only allow us to delay for
a short period of time.
If we go and implement this kind
of WSDL operation on top of TCP/WSE2.0 then we can make a choice and have a
service implementation which does not assume that the response to
the request message is available within a particular period. The supplier
service can receive an order message, store its ReplyTo address and, at
some later point, send a response back to that end point reference using a
RelatesTo header field so that the sender can tie together request and
response.
From a business (or, arguably to
my way of thinking, Service Oriented) perspective it seems unreasonable to
assume that the Supplier would be able to produce an order response message here
in a particular timeframe. If the supplier has to wait for an overnight batch
job to return before determining their stock levels then we’re not going to be
able to leave an HTTP request hanging for 24 hours.
So, what would be reasonable
from a business point of view? It seems to me that what we could legitimately
expect would be a receipt from the supplier service. This ties up with
the business scenario where I order something over the telephone and I get back
an order number (a receipt). During the process of waiting for delivery of the
goods I’ve ordered I can phone the supplier again, give them the order number
and they’ll give me some more information as to what my order status is. When
the order is finally delivered I usually get some kind of documentation that
describes who supplied it, who delivered it, who packed it, who checked it and
so on but, at any earlier point in the ordering process, I only get limited
visibility of this set of information.
We can change our messages in
order to reflect this. Our request still looks the same;
<?xml
version="1.0"
encoding="utf-8"
?>
<Order
xmlns="urn:supplies-com">
<WidgetOrder
Quantity="500"
WidgetName="Buttons"/>
</Order>
But our response needs to be
changed. We could either have a response that was purely a receipt or we could
have a response which would contain one of two things (via xs:choice) –
one would be a receipt and the other would (in the case where the supplier could
perform a synchronous operation for us) be the actual reply message. So,
following that second scheme, a valid response message would be;
<?xml
version="1.0"
encoding="utf-8"
?>
<Supply
xmlns="urn:supplies-com">
<Goods
HoldDays="2"
Quantity="50"
WidgetName="Buttons"/>
</Supply>
And another valid response
message would be;
<?xml
version="1.0"
encoding="utf-8"
?>
<Supply
xmlns="urn:supplies-com">
<Receipt
id="unique id"/>
</Supply>
So I end up with a schema that
looks something like;
<?xml
version="1.0"
encoding="utf-8"
?>
<xs:schema
id="Supply"
targetNamespace="urn:supplies-com"
elementFormDefault="qualified"
xmlns="urn:supplies-mt.com"
xmlns:mstns="urn:supplies-com"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType
name="SupplyType">
<xs:attribute
name="WidgetName"
type="xs:string"/>
<xs:attribute
name="Quantity"
type="xs:integer"/>
<xs:attribute
name="HoldDays"
type="xs:integer"/>
</xs:complexType>
<xs:complexType
name="ReceiptType">
<xs:attribute
name="id"
type="xs:uuid"/>
</xs:complexType>
<xs:complexType
name="SupplyDocumentType">
<xs:choice>
<xs:element
name="Goods"
type="mstns:SupplyType"/>
<xs:element
name="Receipt"
type="mstns:ReceiptType"/>
</xs:choice>
</xs:complexType>
<xs:element
name="Supply"
type="mstns:SupplyDocumentType"/>
</xs:schema>
We now need an additional
operation on our web service to support this kind of pattern.
<portType
name="OrderWidgetsPort">
<operation
name="OrderWidgets">
<input
message="WidgetOrderMessage"
/>
<output
message="WidgetOrderReceiptOrFulfillmentMessage"
/>
</operation>
<operation
name="CheckWidgetOrderStatus">
<input
message="WidgetOrderStatusMessage"
/>
<output
message="WidgetOrderReceiptOrFulfillmentMessage"
/>
</operation>
</portType>
Note that in the second
operation here, CheckWidgetOrderStatus I’ve lazily used the same message
type as was present in the original OrderWidgets operation as the
response message type. So, when we check order status we will (once again)
either get back the real order status or we will get back a receipt telling us
to come back later on.
So, I’m happy now with what I
have here but there’s one thing that’s leaving me puzzled at this point and
that’s this – doesn’t every web service need to be implemented in this fashion?
Is it ever reasonable to design an interface that will allow for an HTTP
implementation that will assume a synchronous response message and,
thereby, couple the “client” and “service” provider in terms of expectation
around response time?
Would it make sense for every
Response message in a web service operation to include a “receipt” portion or
have I just lost the plot again?
Posted
Fri, Jul 30 2004 6:07 AM
by
mtaulty