As it happens, the SOAP specification is useful straight "out of the box." The fact that it provides both a message format and marshalling naturally supports RPC, and indeed millions of developers worldwide will by now have seen how easy it is to run SOAP RPC-based Web services on a myriad of platforms. It's probably not the case that SOAP RPC will be the dominant paradigm for SOAP in the long term, but it is easy to achieve results with SOAP RPC quickly because all the major toolkits support it and RPC is a pattern many developers are familiar with.
SOAP RPC provides toolkits with a convention for packaging SOAP-encoded messages so they can be easily mapped onto procedure calls in programming languages. To illustrate, let's return to our banking scenario and see how SOAP RPC might be used to expose account management facilities to users. Bear in mind throughout this simple example that it is an utterly insecure instance whose purpose is to demonstrate SOAP RPC only.
Figure 3-16 shows a simple interaction between a Web service that offers the facility to open bank accounts and a client that consumes this functionality on behalf of a user. The Web service supports an operation called openAccount(…) which it exposes through a SOAP server and advertises as being accessible via SOAP RPC (SOAP does not itself provide a means of describing interfaces, but as we shall see later in the chapter, WSDL does). The client interacts with this service through a stub or proxy class called Bank which is toolkit-generated (though masochists are free to generate their own stubs) and deals with the marshalling and un-marshalling of local variables into SOAP RPC messages.
Figure 3-16. Interacting with a banking service via SOAP RPC.
In this simple use case, the SOAP on the wire between the client and Web service is similarly straightforward. Figure 3-17 shows the SOAP RPC request sent from the client to the Web service:
Figure 3-17. A SOAP RPC request.
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Body> <bank:openAccount env:encodingStyle= "http://www.w3.org/2002/06/soap-encoding" xmlns:bank="http://bank.example.org/account" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <bank:title xsi:type="xs:string"> Mr </bank:title> <bank:surname xsi:type="xs:string"> Bond </bank:surname> <bank:firstname xsi:type="xs:string"> James </bank:firstname> <bank:postcode xsi:type="xs:string"> S1 3AZ </bank:postcode> <bank:telephone xsi:type="xs:string"> 09876 123456 </bank:telephone> </bank:openAccount> </env:Body> </env:Envelope>
There is nothing particularly surprising about the RPC request presented in Figure 3-17. As per the RPC specification, the content is held entirely within the SOAP body (SOAP RPC does not preclude the use of header blocks, but they are unnecessary for this example), and the name of the element (openAccount) matches the name of the method to be called on the Web service. The contents of the bank:openAccount correspond to the parameters of the openAccount method shown in Figure 3-16, with the addition of the xsi:type attribute to help recipients of the message to convert the contents of each parameter element to the correct kind of variable in specific programming languages. The response to the original request follows a slightly more intricate set of rules and conventions as shown in Figure 3-18.
Figure 3-18. A SOAP RPC response.
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope"> <env:Body> <bank:openAccountResponse env:encodingStyle= "http://www.w3.org/2002/06/soap-encoding" xmlns:rpc= "http://www.w3.org/2002/06/soap-rpc" xmlns:bank= "http://bank.example.org/account" xmlns:xs= "http://www.w3.org/2001/XMLSchema" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"> <rpc:result>bank:accountNo</rpc:result> <bank:accountNo xsi:type="xsd:int"> 10000014 </bank:accountNo> </bank:openAccountResponse> </env:Body> </env:Envelope>
The SOAP RPC response is slightly more complex and interesting than the request, and there are two noteworthy aspects of the SOAP RPC response. The first is that by convention the name of the response element is the same as the request element with Response appended (and toolkits make use of this convention so it's practically standard now).
The second interesting aspect is that the response is capable of matching the procedure call semantics of many languages since it supports in, out, and in/out parameters as well as return values where an "in" parameter sources a variable to the procedure call; an "out" parameter sources nothing to the procedure but is populated with data at the end of the procedure call. An "in/out" parameter does both, while a return value is similar to an out parameter with the exception that its data may be ignored by the caller.
In this example, we have five "in" parameters (title, surname, first name, post code, and telephone number) which we saw in the SOAP request and expect a single return value (account number) which we see in the SOAP response. The return value is also interesting because, due to its importance in most programming languages, it is separated from out and in/out parameters by the addition of the rpc:result element that contains a QName that references the element which holds the return value. Other elements which are not referenced are simply treated as out or in/out parameters. This behavior is different from previous versions of SOAP where the return value was distinguished by being first among the child elements of the response. This was rectified for SOAP 1.2 because of the inevitable ambiguity that such a contrivance incurs what happens when there is no return value?
Of course in a textbook example like this, everything has worked correctly and no problems were encountered. Indeed, you would be hard pressed to find a reader who would enjoy a book where the examples were a set of abject failures. However, like paying taxes and dying, computing systems failures seem inevitable. To cover those cases where things go wrong, SOAP RPC takes advantage of the SOAP fault mechanism with a set of additional fault codes (whose namespace is http://www.w3.org/2002/06/soap-rpc), which are used in preference to the standard SOAP fault codes in RPC-based messages shown in Figure 3-19, in decreasing order of precedence.
Finally, in Figure 3-20 we see a SOAP RPC fault in action where a poorly constructed client application has tried to invoke an operation on the bank Web service, but has populated its request message with nonsense. In this figure, the bank Web service responds with a SOAP RPC fault that identifies the faulting actor (the sender) as part of the Code element. It also describes what the faulting actor did wrong (sent bad arguments) by specified the QName rpc:BadArguments as part of the subcode element. It also contains some human-readable information to aid debugging (missing surname parameter), in the Reason element.
Figure 3-20. A SOAP RPC fault.
<?xml version="1.0"?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope" xmlns:rpc="http://www.w3.org/2002/06/soap-rpc"> <env:Body> <env:Fault> <env:Code> <env:Value>env:Sender</env:Value> <env:Subcode> <env:Value>rpc:BadArguments</env:Value> </env:Subcode> </env:Code> <env:Reason> Missing surname parameter </env:Reason> </env:Fault> </env:Body> </env:Envelope>