Using REST web services with ZendRest 1
At the start of this chapter, we mentioned that the various Zend Framework components we'd be working with would include XML but that we wouldn't be needing to deal with it directly. The Zend_Rest section of the manual opens by stating that "REST Web Services use service-specific XML formats," which is true, but it needs a little clarification because REST web services don't care whether or not they use XML. Zend_ Rest does use XML as its format of choice, but it's possible to circumvent this if you dig around a bit, which we'll do after looking at REST in a bit more detail.
12.4.1 What is REST?
REST stands for Representational State Transfer and was originally outlined in "Architectural Styles and the Design of Network-based Software Architectures" by Roy Fielding, whose role as "primary architect of the current Hypertext Transfer Protocol" explains some of the background to REST. As Fielding states in the document, "REST ignores the details of component implementation and protocol syntax in order to focus on the roles of components, the constraints upon their interaction with other components, and their interpretation of significant data elements." He also states that "the motivation for developing REST was to create an architectural model for how the Web should work, such that it could serve as the guiding framework for the Web protocol standards." In other words, every time we make an HTTP request, we're using a transfer protocol based on the REST concept.
While the key element of RPC is the command, usually accessed via a single point of entry, the key element in REST is the resource, an example of which could be the Places login page, whose resource identifier is the URL http://places/auth/login/.
Resources can change over time (for example, our login page could have interface updates), but the resource identifiers should remain valid.
Of course, having a lot of resources doesn't hold a great deal of value unless we can do something with them, and in the case of web services we have the HTTP methods. To illustrate the value that such apparently simple operations have, Table 12.2 compares the HTTP methods POST, GET, PUT, and DELETE with the common generic database operations: create, read, update, and delete (CRUD). All readers of this book will likely be familiar with the POST and GET HTTP request methods, whereas PUT and DELETE are less well known, partly because they're not often implemented by all HTTP servers. This limitation is reflected in Zend Rest, because Zend Rest Client is able to send all of these request methods but Zend_Rest_Server will only respond to GET and POST.
Presuming that readers will already know enough HTTP to be able to join the dots on the fundamentals, we've kept this introduction to REST intentionally brief. Hopefully, as we start to explore some of the REST components of Zend Framework, things will become clearer. We'll start with Zend_Rest_Client.
12.4.2 Using Zend_Rest_Client
As we mentioned at the start of this section, Zend Rest uses XML to serialize the data it processes in the body of the HTTP request or response, but not all RESTful web services use XML. One example is the Akismet spam-filtering service, which we'll use to demonstrate the various ways of accessing REST-based web services. Figure 12.7 shows where we could use the service to check the reviews submitted by users of our Places application to make sure spam replies are kept out.
Another reason we've chosen Akismet is that Zend Framework has a Zend_Service_Akismet component, which means you won't be left with a partially implemented solution and will hopefully be able to understand how that component works.
The Akismet API provides a small choice of resources, shown in table 12.3, from which we'll choose the resource to verify that the API key, which is required to use Akismet and is obtained from Wordpress.com, is valid.
The first thing we'll do is attempt to use Zend_Rest to access this resource in the method demonstrated in the manual. You can see this in listing 12.10.
|
HTTP methods |
Database operations |
|
POST |
Create |
|
GET |
Read |
|
PUT |
Update |
|
DELETE |
Delete |
- Figure 12.7 The reviews in our Places application, which we could filter using the Akismet spam-filtering service
|
Resource identifier |
Description |
|
rest.akismet.com/1.1/verify-key api-key.rest.akismet.com/1.1/comment-check api-key.rest.akismet.com/1.1/submit-spam api-key.rest.akismet.com/1.1/submit-ham |
Verifies the required API key. Identifies whether or not the submitted comment is spam. Submits missed spam. Submits content incorrectly marked as spam. |
Listing 12.10 Sending a REST request to Akismet using Zend_Rest_Client
$client = new Zend_Rest_Client(
'http://rest.akismet.com/1.1/verify-key'
Instantiates client with URL of the resource echo $client->key('f6k3apik3y') ->blog('http ://places/ ->post(); ———
Sends request as HTTP POST
Sets blog to URL of blog
Sets key to value of API key
In this example, we construct our client with the URL of the verify key resource, then, using the fluent interface that is common in many Zend Framework components, we set the two required variables key and blog using the built-in magic methods. Finally, we send them via an HTTP POST request. Unfortunately, despite the pleasing simplicity of this code, the resulting request will fail because Akismet doesn't return the XML response that is expected by Zend_Rest_Client when used this way.
Since all Akismet needs is a simple HTTP request, and Zend_Rest itself uses Zend_Http_Client, why can't we just use Zend_Http_Client in the first place? The answer, as demonstrated in listing 12.11, is that we can.
Listing 12.11 Sending a REST request to Akismet using Zend_Http_Client
$client = new Zend_Http_Client(
'http://rest.akismet.com/1.1/verify-key'
'key' => 'f6k3apik3y', 'blog' => 'http://places/'
Instantiates client with resource URL
Builds array with required data for verify request
Zend_Http_Client::POST
} catch (Zend_Http_Client_Exception $e) {
echo $e->getCode() . ' : ' . $e->getMessage()
Formats data into an HTTP POST
Makes request
Zend_Http_Client won't attempt to parse the returned response from Akismet as if it were XML, and we'll receive the plain text response valid or invalid depending on whether or not our data is verified successfully.
If Zend_Http_Client can successfully make the request, surely there is a way that Zend_Rest can do the same? Of course there is, and in listing 12.12, which should be looking familiar by now, we bypass having Akismet's plain text response parsed as XML by calling the restPost() method directly. Unlike our first attempt, this method returns the body of the HTTP response rather than sending it through Zend Rest Client Result.
Listing 12.12 Sending a REST request to Akismet using Zend_Rest
$client = new Zend_Rest_Client( <-'http://rest.akismet.com'
'key' => 'f6k3apik3y', 'blog' => ' http://places/'
Instantiates client with request URL
Builds array with required data for verify request
$response = $client->restPost( ' /1.1/verify-key',
$data var_dump($response); } catch (Zend_Rest_Client_Exception $e) {
echo $e->getCode() . ' : ' . $e->getMessage()
Makes HTTP POST request
Having solved our problem with Akismet's service, we now know we can use Zend_Rest_Client with plain-text-based and XML-based RESTful web services. If we wanted to work with the rest of Akismet's resources, it would obviously make more sense to use Zend_Service_Akismet, but if there weren't a prebuilt Zend Framework component we'd have several options. One of those is to use Zend_Rest_Server to interact with REST-based web services provided by our own application server.
12.4.3 Using Zend_Rest_Server
Let's imagine that we've convinced one of the advertisers on Places, Edinburgh Zoo, to take part in a joint promotion that will be hosted separately from both of our sites. The idea is to make a short lifespan mashup site based on content from Places, Edinburgh Zoo, and other interested sites.
As we did with our XML-RPC server earlier, we'll start by making a simple interface called Places_Service_Place_Interface to make sure our server has a consistent API. Listing 12.13 shows our interface with two methods: one to get a place and one to get the reviews for a place.
Listing 12.13 Our Places service application interface interface Places Service Place Interface public function getPlace($id); public function getReviews($id) ;
In listing 12.14, we make a concrete implementation of our interface using queries similar to those from chapter 6. Note that the database results are returned as an array rather than as the default objects, which would have failed when processed by Zend_ Rest_Server. Another thing you may notice is that unlike Zend_XmlRpc_Server, Zend_Rest_Server does not require parameters and return values specified in DocBlocks even though it will use them if provided.
Listing 12.14 Our Places service concrete class class ServicePlaces implements Places_Service_Place_Interface
public function getPlace($id)
$placesFinder = new Places(); $place = $placesFinder->find($id); return $place->current()->toArray ( );
public function getReviews($id)
$reviewsFinder = new Reviews();
$rowset = $reviewsFinder->fetchByPlaceld($id); return $rowset->toArray(); <-
Returns query results as array
Now that we have the concrete class, we can attach it to Zend_Rest_Server with the same approach that we covered with Zend_XmlRpc_Server. Listing 12.15 shows our REST server set up within an action controller and accessible via an HTTP GET or POST that must supply the name of the service method you wish to invoke.
Listing 12.15 Our REST server class RestController extends Zend_Controller_Action {
protected $_server;
public function init() {
$this->_server = new Zend_Rest_Server(); $this->_helper->viewRenderer->setNoRender();
public function indexAction()
require_once 'ServicePlaces.php';
$this->_server->setClass('ServicePlaces');
Figure 12.8 shows the XML-formatted results of some example GET requests to the resources http://places/rest/?method=getPlace&id=6 (on the left) and http:// places/rest/?method=getReviews&id=6 (on the right) using Firefox.
All our mashup site needs to do is use Zend_Rest_Client to make requests like the following:
$client = new Zend_Rest_Client('http://places/rest/?method=getPlace'); $response = $client->id('6')->get();
This will return a Zend_Rest_Client_Result object that allows us to access the elements of the response as properties that can be used in our site like so:
Figure 12.8 The results of our REST server query: getPlace on the left and getReviews on the right
Figure 12.8 The results of our REST server query: getPlace on the left and getReviews on the right echo $response->name; // Outputs "Edinburgh Zoo"
Having worked through the implementation of Zend_XmlRpc_Server, itself relatively simple when compared to, say, SOAP, you'll have found Zend_Rest_Server very easy to follow. As with any brief introduction, there is a lot that has not been covered, such as PUT and DELETE HTTP requests, which are not handled by Zend_Rest_Server, and authentication. However, what we've set up is a REST server whose strength lies in the relationship between Zend_Rest_Server and Zend_Rest_Client and the simplicity of implementation.
Post a comment