- Doing Business with SkatesTown
- Inventory Check Web Service
- A Closer Look at SOAP
- The SOAP Messaging Framework
- SOAP Intermediaries
- The SOAP Body
- The SOAP Processing Model
- Versioning in SOAP
- Processing Headers and Bodies
- Faults: Error Handling in SOAP
- Objects in XML: The SOAP Data Model
- The SOAP RPC Conventions
- XML, Straight Up: Document-Style SOAP
- When to Use Which Style
- The Transport Binding Framework
- Using SOAP to Send Binary Data
- Small-Scale SOAP, Big-Time SOAP
The Transport Binding Framework
The SOAP processing model talks about what a node should do when it processes a SOAP message. As we've discussed, messages are described abstractly in terms of the XML infoset. Now it's time to look more closely at how those infosets are moved from place to place.
A SOAP protocol binding is a set of rules that describes a method of getting a SOAP infoset from one node to another. For instance, you already know that HTTP is a common way to transport SOAP messages. The purpose of the SOAP HTTP binding (which you'll find in part 2 of the spec) is to describe how to take a SOAP infoset at one node and serialize it across an HTTP connection to another node.
Many bindings, including the standard HTTP one, specify that the XML 1.0 serialization for the infoset should be usedthat means if you look at the messages on the wire, you'll see angle brackets as in any regular XML document. But the binding's job is really to move the infoset from node to node, and the way the infoset is represented on the wire is up to the binding author. This means bindings have the freedom to specify custom serializations; they might do this to increase efficiency with compression or a binary protocol, or to add security via encryption, among other reasons.
Since bindings determine the concrete structure of the bits on the wire and how they're processed into SOAP messages, it's critical that communicating parties agree on what binding to usethat agreement is just as important as the agreement of what data to send. This is why bindings, like SOAP modules, are named with URIs. The standard SOAP 1.2 HTTP binding, for instance, is identified by the URI http://www.w3.org/2003/05/soap/bindings/HTTP/. Note that there can be many different SOAP bindings for a given underlying protocolagreeing on a binding means not only agreeing to use HTTP to send SOAP messages, but also to follow all the rules of the given binding specification when doing so.
Bindings can be simple or complex, and they can provide a variety of different levels of functionality. A raw UDP binding, for instance, might not provide any guarantee that the messages sent arrive at the other side. On the other hand, a binding to a reliable message queuing system such as the Java Message Service (JMS) might provide guaranteed (eventual) arrival, even in the face of crashes or network failures. We can also imagine bindings to underlying protocols that provide security, such as HTTPS, or with the ability to broadcast messages to a variety of recipients at once, like multicast IP.
Even when the underlying protocol doesn't provide desired functionality directly, it's still possible to write a binding that does fancy things. For instance, you could design a custom HTTP binding specifying that, for security reasons, the XML forming each message should be encrypted before being sent (and decrypted on the receiving side). Such custom bindings are possible, but it's often a better idea to use the extensibility built into the envelope to implement this kind of functionality. Also, bindings only serve to pass messages between adjacent nodes along a SOAP message path. If you need end-to-end functionality in a situation where intermediaries are involved, it's usually better to use in-message extensibility with SOAP headers.
Features and Properties
Bindings can do a huge variety of different things for uscompare this variety to what the SOAP header mechanism can do, and you might notice that the set of possible semantics you can achieve is similar (almost anything, in fact). The designers of SOAP 1.2 noticed the similarity as well, and wanted to write a framework that might help future extension authors describe their semantics in ways that were easy to reason about, compare with each other, and refer to in machine-readable ways.
What was needed was a way to specify that a given semantic could be implemented either by a binding or by using SOAP headers. Nodes might use this information to decide whether to send particular headersif you're running on top a secure binding, for instance, you might not need to add security headers to your messages, which can save your application effort and time. Also, since a variety of modules might be available to an engine at any given time, it would also be nice to be able to unambiguously indicate that a particular module performed a certain set of desired semantics. To achieve these goals, the first job was to have a standard way to name the semantics in question.
The SOAP authors came up with an extensibility framework that is described in section 3 of part 1 of the SOAP 1.2 spec. The framework revolves around the notion of an abstract feature g, which is essentially a semantic that has a name (a URI) and a specification explaining what it means. Features can be things like reliability, security, transactions, or anything you might imagine. A feature is typically specified by describing the behavior of each node involved in the interaction, any data that needs to be known before the feature does its thing, and any data that is transferred from node to node as a result. It's generally convenient if the specification of the feature's behavior can be found at the URI naming the featureso if a user sees a reference to it somewhere, they can easily locate a description of what it does.
The state relevant to a feature is generally described in terms of named properties g. Properties, in the SOAP 1.2 sense, are pieces of state, named with URIs, which affect the operation of features. For instance, you might describe a "favorite color" feature that involves transferring a hexadecimal color value from one node to another. You would pick a URI for the feature, describe the rules of operation, and name the color property with another URI. Because a feature definition is abstract, you don't say anything about how this color would move across the wire.
Features are expressed (turned into reality via some mechanism) by bindings and modules. We've already described both of theserecall that a binding is a means for performing functions below the SOAP processing model, and a module is a means for performing functions using the SOAP processing model, via headers.
Here's a simple example of how a feature might be expressed by a binding in one case and a module in another. Imagine a "secure channel" feature. The specification for this feature indicates that it has the URI http://skatestown.com/secureChannel, and the abstract feature describes a message traveling from node to node in an unsnoopable fashion (to some reasonable level of security). We might then imagine a SOAP binding to the HTTPS protocol, which would specify that it implements the http://skatestown.com/secureChannel feature. Since HTTPS meets the security requirements of the abstract feature, the feature would be satisfied by the binding with no extra work, and the binding specification would indicate that it natively supports this feature. We could also imagine a SOAP module (something like WS-Security, which we discuss in Chapter 9, "Securing Web Services") that provides encryption and signing of a SOAP message across any binding. The module specification would also state that it implements the secureChannel feature. With this information in hand, it would be possible, in a situation that required a secure channel, to decide to engage our SOAP module in some situations (when using the HTTP binding, for instance) and to not bother in other situations where the HTTPS binding is in use.
Another example of making features concrete could be the color feature discussed earlier. The feature spec describes moving a color value from the sender to the receiver in the abstract. A custom binding over email might define a special SMTP header to carry this color information outside the SOAP envelope. Writing a SOAP module to satisfy the feature would involve defining a SOAP header that carried the value in the envelope.
Message Exchange Patterns
One common type of feature is a Message Exchange Pattern (MEP) g. An MEP specifies how many messages move around in a given interaction, where they originate, and where they end up. Each binding can (and must) support one or more message exchange patterns. The SOAP 1.2 spec defines two standard MEPs: Request-Response and SOAP Response. Without going into too much detail (you can find the full specifications for these MEPs in the SOAP 1.2 spec, part 2), we'll give you a flavor of what these MEPs are about.
The Request-Response MEP involves a requesting node and a responding node. As you might expect, it has the following semantics: First, the requesting node sends a SOAP message to the responding node. Then the responding node replies with a SOAP message that returns to the requesting node. See Figure 3.9.
Figure 3.9 The Request-Response MEP
You should note a couple of important things here. First, the response message is correlated to the request messagein other words, the requesting node must be able to figure out which response goes with which request. Since the MEP is abstract, though, it doesn't specify how this correlation is achieved but leaves that up to implementations. Second, if a fault is generated at the responding node, the fault is delivered in the response message.
The SOAP Response MEP is similar to the Request-Response MEP, except for the fact that the request message is explicitly not a SOAP message. In other words, the request doesn't trigger the execution of the SOAP processing model on the receiving node. The receiving node responds to the request with a SOAP message, as in the Request-Response MEP (see Figure 3.10).
Figure 3.10 The SOAP Response MEP
The primary reason for introducing this strange-seeming MEP is to support REST-style interactions with SOAP (see the sidebar "REST-Style versus Tunneled Web Services"). The SOAP Response MEP allows a request to be something as simple as an HTTP GET; and since the responding node doesn't have to implement the SOAP processing model, it can return a SOAP message in any way it deems appropriate. It might, for instance, be an HTTP server with a variety of SOAP messages in its filesystem.
As you'll see in a moment, the HTTP binding natively supports both of these MEPs. Of course, MEPs, like other abstract features, can also be implemented via SOAP modules. Here's an example of how the Request-Response MEP might be implemented using SOAP headers across a transport that only allows one-way messages:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap/envelope"> <soapenv:Header> <!--This header specifies the return address--> <reqresp:ReplyTo soapenv:mustUnderstand="true" xmlns:reqresp="http://skatestown.com/requestResponse"> <destination>udp://me.com:6666</destination> </reqresp:ReplyTo> <!--This header specifies a correlation ID--> <reqresp:correlationID soapenv:mustUnderstand="true" xmlns:reqresp="http://skatestown.com/requestResponse"> 1234 </reqresp:correlationID> </soapenv:Header> <soapenv:Body> <doSomethingCool/> </soapenv:Body> </soapenv:Envelope>
This message might have been sent in a UDP datagram, which is a one-way interaction. The receiver would have to understand these headers (since they're marked mustUnderstand) in order to process the message; when it generated a reply, it would follow the rules of the ReplyTo header and send the reply via UDP to port 6666 of host me.com. The reply would contain the same correlationID sent in the request, so that the receiver on me.com would be able to match the response to the pending request. The WS-Addressing spec includes a mechanism a lot like this, which we'll cover in Chapter 8, "Web Services and Stateful Resources."
If your interaction requires the request-response MEP, you might choose to use the HTTP binding (or any binding that implements that MEP natively), or you might use a SOAP module that specifies how to implement the MEP across other bindings. The important goal of the framework is to enable abstractly defining what functionality you needthen you're free to select appropriate implementations without tying yourself to a particular way of doing things.
REST-Style versus Tunneled Web Services
REpresentational State Transfer (REST) g refers to an architectural style of building software that mirrors what HTTP is built to do: transfer representations of the state of named resources from place to place with a small set of methods (GET, POST, PUT, DELETE). The methods have various semantics associated with themfor instance, a GET is a request for a resource's representation, and by definition GETs should be safe operations. "Safe" in this context means they should have no side effects. So, you do a GET on my bank account URL in order to obtain your current balance, you can repeat that operation many times with no ill effects. However if the GET withdrew funds from your account, , that would clearly be a serious side effect (and therefore illegal in REST).
Another interesting thing to note about GET is that the results are often cacheable: If you do a GET on a weather report URL, the results probably won't change much if you do it again in 10 minutes. As a result, the infrastructure can cache the result, and if someone asks for the same GET again before the cache entryexpires, you can return the cached data instead of going out over the Net to fetch the same weather again. The HTTP infrastructure uses this caching style to great effect; most large ISPs or companies have shared caching proxies at the edge of the network that vastly reduce the network bandwidth outside the organizationeach time anyone asks for http://cnn.com, the cache checks if a local, fresh copy exists before going out across the network.
We bring up REST because it shines light on an interesting controversy. REST advocates (sometimes known as RESTifarians) noticed that SOAP 1.1's HTTP binding mandated using the POST method. Since POSTs are not safe or cacheable in the same way GETs are, even simple SOAP requests to obtain data like stock quotes or weather reports had to use a mechanism that prevented the HTTP infrastructure from doing its job. Even though these operations might have been safe, SOAP was ignoring the HTTP semantic for safe operations and losing out on valuable caching behavior as a consequence.
This issue has since been fixed in the SOAP 1.2 HTTP binding, which supports the WebMethod feature. In other words, SOAP 1.2 is a lot more REST-friendly than SOAP 1.1 was, since it includes a specific technique for utilizing HTTP GET, including all that goes along with it in terms of caching support and operation safety. HTTP semantics are respected, and HTTP isn't always used as a tunnel for SOAP messages.
We believe that SOAP's flexible messaging and extensibility model (which supports both semantics provided by the underlying protocol and also those provided by higher-level extensions in the SOAP envelope) offer the right framework for supporting a large variety of architectural approaches. We hope this framework will allow the protocol both good uptake and longevity in the development community.
Features and Properties Redux
The features and properties mechanism in SOAP 1.2 is a powerful and flexible extensibility framework. By naming semantics, as well as the variables used to implement those semantics, we enable referencing those concepts in an unambiguous way. Doing so is useful for a number of reasonsas you'll see in Chapter 4, "Describing Web Services," naming semantics lets you express capabilities and requirements of your services in machine-readable form. This allows software to reason about whether a given service is compatible with particular requirements. In addition to the machine-readability aspect, naming features and properties allows multiple specifications to refer to the same concepts when describing functionality. This encourages good composition between extensions, and also allows future extensions to be written that implement identical (but perhaps faster, or more flexible) semantics.
Now that you understand the framework and its components, we'll go into more detail about the SOAP HTTP binding.
The HTTP Binding
You already know the HTTP binding is identified with the URI http://www.w3.org/2003/05/soap/bindings/HTTP/ and that it supports both the Request-Response and the SOAP Response MEPs. Before we examine the other interesting facets of this binding, let's discuss how those MEPs are realized.
Since HTTP is natively a request/response protocol, when using the Request-Response MEP with the HTTP binding, the request/response semantics map directly to the equivalent HTTP messages. In other words, the SOAP request message travels in the HTTP request, and the SOAP response message is in the HTTP response. This is a great example of utilizing the native capabilities of an underlying protocol to implement an abstract feature.
The SOAP Response MEP is also implemented natively by the HTTP binding and is typically used with the GET Web method to retrieve representations of Web resources expressed as SOAP messages, or to make idempotent (safe) queries. When using this MEP this way, the non-SOAP request is the HTTP GET request, and the SOAP response message (or fault) comes back, as in the Request/Response case, in the HTTP response.
The HTTP binding also specifies how faults during the processing of a message map to particular HTTP status codes and how the semantics of HTTP status codes map to Web service invocations.
SOAP 1.1 Differences: Status Codes
In SOAP 1.1, the HTTP binding specified that if a fault was returned in an HTTP response, the status code had to be 500 (server error). This worked, but it didn't allow systems to use the inherent meaning in the HTTP status codes400 means a problem with the sender, 500 means a problem with the receiver, and so on. SOAP 1.2 resolves this issue by specifying a richer set of fault codes; for example, if a soapenv:Sender fault is generated, indicating a problem with the request message, the engine should use the 400 HTTP status code when returning the fault. Other faults generate a 500, as in SOAP 1.1.
The HTTP binding also implements two abstract features, which are described next.
The SOAP Action Feature
In the SOAP 1.1 HTTP binding, you were required to send a custom HTTP header called SOAPAction along with SOAP messages. The purpose of this header was twofold: to let any system receiving the message know that the contents were SOAP and to convey the intent of the message via a URI. In SOAP 1.1, the first purpose was necessary because the media type was text/xml; since that media type could carry any XML document, processors needed to look inside the XML (which might involve an expensive parse) to check if it was a SOAP envelope. The SOAPAction header allowed them to realize this was a SOAP message and perhaps make decisions about routing or logging based on that knowledge. The presence of the header was enough to indicate that it was SOAP, but the URI could also convey more specific meaning, abstractly describing the intent of the message. Many implementations use this URI for dispatching to a particular piece of code on the backend, especially when using document-style SOAP. For example, you might send a purchase order as the body contents to two different methodsone called submitPO() and the other called validatePO(). Since the XML is the same in both cases, you could use the value of the SOAPAction URI to differentiate.
SOAP 1.2 uses the application/soap+xml media type, and the SOAPAction header is no longer needed to differentiate SOAP traffic from other XML documents moving across HTTP connections. But a lot of people still want a standard way to indicate a message's purpose outside of the SOAP envelope. The features and properties mechanism described earlier seemed like a perfect fit for an abstract feature.
The SOAPAction feature can be made available for any binding that uses the application/soap+xml media type to send its messages. The definition of that media type (which you can find in the glossary) specifies an optional action parameter, which is used in SOAP 1.2 instead of an HTTP-specific header to carry the SOAPAction URI. The feature has a single property, http://www.w3.org/2003/05/soap/features/ action/Action. When this property is given a URI value, the spec indicates that the binding that implements the feature must place the value into the action parameter. So, if the property had the value http://example.com/myAction at the sender, the message would start like this (assuming the HTTP binding):
POST /axis/SomeService.jws Content-Type: application/soap+xml; charset=utf-8; _action="http://example.com/myAction" ...rest of message...
On the receiving side, a node receiving a message with an action parameter over a binding that supports the SOAP Action feature is required to make the value of the action parameter available in the http://www.w3.org/2003/05/soap/features/action/Action property.
The Web Method Feature
Normal SOAP exchanges across HTTP use the POST HTTP verb. However, sometimes other HTTP methods are more appropriate for a given situation. For instance, when you use the SOAP Response MEP, you're often making a state query, which in HTTP is modeled with the GET verb. If you only allowed POST, you would be forcing HTTP into a particular limited set of uses (purely as a transport). Therefore, in an effort to allow developers to better integrate the semantics of SOAP with the semantics of HTTP, the Web Method Feature (defined in part 2 of the spec) was born.
This feature defines a single property, http://www.w3.org/2003/05/soap/features/web-method/Method, which contains one of the words GET, POST, PUT, or DELETE (although other values may be supported later). When sending a message, the HTTP binding will use the verb specified in this property instead of the default POST. This is most often used in concert with the SOAP Response MEP to implement REST semantics.
Right now this feature is only relevant to HTTP; but if other bindings are developed to underlying protocols with REST-like semantics, it would be available for them as well.