Приглашаем посетить
Добычин (dobychin.lit-info.ru)

How Web Services Work

Previous
Table of Contents
Next

How Web Services Work

Before we begin using Web Services in our PHP applications, we will examine the technologies on which they are built and how they work.

SOAP

The Simple Object Access Protocol (SOAP) is an XML-based text protocol that permits applications to share data over the Internetor indeed, to access a web service. It is a simple protocol based on XML that allows applications to send messages back and forth (requests and responses) over HTTP. As mentioned previously, it is both platform and programming language independent.

Messages in SOAP are ordinary XML documents that have the following parts:

  • An envelope to wrap the entire message.

  • An optional header, with additional information for the request. If present, it must be the first element in the envelope.

  • A message body, containing either the call request and parameter information or the response and data being returned.

  • An optional fault section appearing as a child of the body section, describing an error condition and where it occurred.

The wrapping envelope in a SOAP message must contain appropriate namespace information and encoding information. It looks like this:

<soap:Envelope
   xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
   soap:encoding="http://www.w3.org/2001/12/soap-encoding">
...
</soap:Envelope>

We will not have much opportunity to use the header section of a SOAP message, so we next describe the body section of a message. In short, it contains the request being made of the Web Service or the response to a request (possibly accompanied by fault information). If we had a Web Service to get the weather for a particular Zip or postal code, we might want to invoke a method called getWeatherForCode, passing to it the appropriate Zip code:

<soap:Body>
  <wi:getWeatherForCode
      xmlns:wi='http://somedomain.com/WeatherService'>
    <wi:ZipCode>94121</wi:ZipCode>
  </wi:getWeatherForCode>
</soap:Body>

The reply to such a message might be something like this:

<soap:Body>
  <wi:getWeatherResponse
      xmlns:wi='http://somedomain.com/WeatherService'>
    <wi:Weather>
        April 12: Sunny, 59F (15C), 0% precipitation
    </wi:ZipCode>
  </wi:getWeatherResponse >
</soap:Body>

If a fault element is sent back with the response, it will be an element of the body and will contain subelements describing the exact nature of the fault. We are again fortunate in that the SOAP implementations with which we will be working (see the section, "Using Web Services in PHP") will process these for us and take appropriate action.

A complete SOAP message for the preceding fictional web service might then look as follows. (Note that we have to include the XML declaration in the first line.)

<?xml version="1.0"?>
<soap:Envelope
   xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
   soap:encoding="http://www.w3.org/2001/12/soap-encoding">
  <soap:Body>
    <wi:getWeatherForCode
        xmlns:wi="http://somedomain.com/WeatherService">
      <wi:ZipCode>94121</wi:ZipCode>
    </wi:getWeatherForCode>
  </soap:Body>
</soap:Envelope>

WSDL

Although it is all well and good that we have a scheme to communicate with Web Services, we still have one other problemlearning what methods they expose, what parameters they expect, and what values they return. To solve this problem, another technology was developed, this one called the Web Services Description Language (WSDL; often pronounced "wiz-dul"). It is just an XML language for describing the services that a particular Web Service proffers and the way in which these services are to be accessed.

WSDL files can, unfortunately, be somewhat frightening to look at if you are uncertain as to what exactly they are. Although you will not often need to write your own, you might still have to look at them occasionally to see which methods a particular services offers and what parameters those methods accept.

A WSDL file is organized into five core parts:

  • A list of types.

  • A list of messages that are sent to or are returned from the server (which are used to build up methods).

  • A list of ports, or collections of methods that are grouped together under a common interface name.

  • A list of bindings, which describe how the interfaces (ports) are to be transported and interpreted (as via SOAP, for example).

  • A service description, containing the name, URL, and description for the service.

All of these sections are wrapped in a definitions element in the document:

<?xml version="1.0" encoding="UTF-8"?>

<definitions  name ="SomeService" 
  targetNamespace="http://somedomain.com/svcs/SomeService.wsdl"
  xmlns:tns="http://somedomain.com/svcs/SomeService.wsdl"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.xmlsoap.org/wsdl/"> 

  ...

</definitions>

Types

The types section in WSDL documents allows the service author to define complex types that will be returned or expected by the service. To prevent a whole new type description language from being invented, these are based on the same types and specifications as for XML Schemas. However, we will not be working with Web Services so complicated as to require a custom type declaration.

Messages

message elements in the WSDL describe the messages that the Web Service supports. These are often combined to create methods, with one message for sending the method and the other for the response:

<message name='getWeatherRequest'>
  <part name='zipcode' type='xsd:string'/>
</message>

<message name='getWeatherResponse'>
  <part name='value' type='xsd:string'/>
</message>

The preceding describes two messages that together could be used to create a getWeather method for a weather Web Service. The first message, getWeatherRequest, indicates that it takes one parameter, called zipcode, which should be of type string. The second message, getWeatherResponse, returns one value (called value), which is also of type string.

You can include multiple part elements if you want to have more than one parameter. We could add a message to this Web Service that also lets people specify a city and state for the location for which they want the weather:

<message name='getWeatherByCityRequest'>
  <part name='city' type='xsd:string'/>
  <part name='state' type='xsd:string'/>
</message>

Ports

A port is a collection of messages that, together, form the methods that this Web Service exposes. A port is declared in the portType element. Within portType, you declare operations, which are made up of messages, and may optionally contain fault information:

<portType name="GetWeatherPortType">
  <operation name="getWeather">
    <input message="getWeatherRequest"/>
    <output message="getWeatherResponse"/>
  </operation>
  <operation name="getWeatherByCity">
    <input message="getWeatherByCityRequest"/>
    <output message="getWeatherResponse"/>
  </operation>
</portType>

The portType shows that we have declared two operations (methods), each of which is composed of two messages that our system understandsone to receive the request and one to send a response. The port type is the most important element in a WSDL, and the one you should seek out first when you come across one of these documents.

Binding

The least intuitive portion of the WSDL is the binding element, which describes how exactly people are to interact with the server. To tell people to interact with our Web Service using SOAP, we might use something similar to the following:

<binding name="GetWeatherBinding" type="GetWeather">
  <soap:binding style="rpc"
      transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="getWeather">
    <soap:operation soapAction="getWeather"/>
    <input>
      <soap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace=" http://somedomain.com/svcs/WeatherService"
        use="encoded"/>
    </input>
    <output>
      <soap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace=" "
        use="encoded"/>
    </output>
  </operation>
  <operation name="getWeatherByCity">
    <soap:operation soapAction="getWeatherByCity"/>
    <input>
      <soap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="http://somedomain.com/svcs/WeatherService"
        use="encoded"/>
    </input>
    <output>
      <soap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="http://somedomain.com/svcs/WeatherService"
        use="encoded"/>
    </output>
  </operation>

</binding>

Now, before our heads explode, we can look through this binding element (which we have called GetWeatherBinding) and realize that there are only three subelements:

  • The soap:binding element, which tells us that we will be using SOAP over HTTP as our protocol, and that we will be using it as a means to call functions (hence the value rpc, for remote procedure calling).

  • Two operation elements, which describe the two operations, getWeather and getWeatherByCity, which we will expose with our service. Their subelements describe how messages are sent to the Web Service to invoke them. For the two examples here, SOAP messages are to be used for both input and output. (See the earlier section titled "SOAP").

Service

The final section in a WSDL document provides a way to describe the service and the exact location for communications with this service:

<service name="GetWeatherService">
  <documentation>
    Use this service to get weather for cities in the United
    States, Canada, or Mexico.
  </documentation>
  <port name="GetWeather" binding="GetWeatherBinding">
    <soap:address
    location="http://somedomain.com:80/svcs/WeatherService"/>
  </port>
</service>

In this section, we provide two things: a handy description for the service in the documentation element, and information on exactly to which network address and port you connect to use the GetWeather service (http://somedomain.com:80/svcs/WeatherService) through the port element.

Putting It All Together

Our WSDL file for a fictional weather Web Service might now look like this:

<?xml version="1.0"?>

<definitions  name ="SomeService" 
  targetNamespace="http://somedomain.com/svcs/SomeService.wsdl"
  xmlns:tns="http://somedomain.com/svcs/SomeService.wsdl"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.xmlsoap.org/wsdl/"> 

  <!-- 
       Messages.  Two request types, one response type
   -->
  <message name='getWeatherRequest'>
    <part name='zipcode' type='xsd:string'/>
  </message>

  <message name='getWeatherByCityRequest'>
    <part name='city' type='xsd:string'/>
    <part name='state' type='xsd:string'/>
  </message>
  <message name='getWeatherResponse'>
    <part name='value' type='xsd:string'/>
  </message>

  <!-- 
       We have one port on which we will define two methods:
       getWeather and getWeatherByCity 
   -->
  <portType name="GetWeatherPortType">
    <operation name="getWeather">
      <input message="getWeatherRequest"/>
      <output message="getWeatherResponse"/>
    </operation>
    <operation name="getWeatherByCity">
      <input message="getWeatherByCityRequest"/>
      <output message="getWeatherResponse"/>
    </operation>
  </portType>

  <!-- 
       Set up the binding so that our portType is accessible
       through SOAP over HTTP, and indicate that it is an
       RPC interface.
   -->
  <binding name="GetWeatherBinding" type="GetWeather">

    <soap:binding style="rpc"
      transport="http://schemas.xmlsoap.org/soap/http"/>

    <operation name="getWeather">
      <soap:operation soapAction="getWeather"/>
      <input>
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace=" http://somedomain.com/svcs/WeatherService"
          use="encoded"/>
      </input>
      <output>
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace=" "
          use="encoded"/>
      </output>
    </operation>

    <operation name="getWeatherByCity">
      <soap:operation soapAction="getWeatherByCity"/>
      <input>
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="http://somedomain.com/svcs/WeatherService"
          use="encoded"/>
      </input>
      <output>
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="http://somedomain.com/svcs/WeatherService"
          use="encoded"/>
      </output>
    </operation>

  </binding>

  <!-- 
       Finally, advertise the service and indicate that it is
       a SOAP-based one.
   -->
  <service name="GetWeatherService">
    <documentation>
      Use this service to get weather for cities in the United
      States, Canada, or Mexico.
    </documentation>
    <port name="GetWeather" binding="GetWeatherBinding">
      <soap:address
      location="http://somedomain.com:80/svcs/WeatherService"/>
    </port>
  </service>

</definitions>

That can seem quite the mouthful (eyeful?) for a service that exposes only two methods. Yet the format is reasonably predictable, and you will become more comfortable with it over time as you are exposed to more and more XML Web Services.

If you are still not comfortable with the contents of the WSDL file, fear not! As you will see in the later section "Using Web Services in PHP," the language will take care of interpreting the details for us. We only have to truly worry about WSDL documents if we want to write our own XML Web Services, because PHP does not have tools to generate them.

HTTP

The last piece to the XML Web Services puzzle is the actual means via which requests and responses are transmitted between the client and server. Because they use SOAP operating over HTTP, a method invocation just becomes an HTTP request. (See Chapter 13, "Web Applications and the Internet.")

The only new item in the request is a new MIME type, application/soap+xml, which indicates that the request body contains SOAP content. To invoke the getWeather method, we use a request similar to the following:

POST /svcs/WeatherService HTTP/1.1
Host: somedomain.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: ...

<?xml version="1.0"?>
<soap:Envelope
   xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
   soap:encoding="http://www.w3.org/2001/12/soap-encoding">
  <soap:Body>
    <wi:getWeather
        xmlns:wi="http://somedomain.com/WeatherService">
      <wi:zipcode >94121</wi:zipcode >
    </wi:getWeather>
  </soap:Body>
</soap:Envelope>

The response sent back might look like this:

HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: ...

<?xml version="1.0"?>
<soap:Body>
  <wi:getWeatherResponse
      xmlns:wi='http://somedomain.com/WeatherService'>
    <wi:value>
        April 12: Sunny, 59F/15C, 0% precipitation
    </wi:value>
  </wi:getWeatherResponse>
</soap:Body>

XML-RPC

SOAP is not the only way to invoke methods or functions on remote servers using HTTP and XML. In the early days of Web Services, a number of different proposals were floated about; one, called XML-RPC, gained some traction in the Web Services community. PHP contains support for this, and you can use it to access those services written using that protocol.

This book does not cover XML-RPC; if you are familiar with XML Web Services (and SOAP in particular), however, the former will not be so foreign.


Previous
Table of Contents
Next