8 min read

Designing Clients

While designing the library service, the ultimate outcome was the mapping of business operations to URIs and HTTP verbs. The client design is governed by this mapping. Prior to service design, the problem statement was analyzed. For consuming the service and invoking the business operations of the service using clients, there needs to be some understanding of how the service intends to solve the problem. In other words, the service, by design, has already solved the problem. However, the semantics of the solution provided by the service needs to be understood by the developers implementing the clients. The semantics of the service is usually documented in terms of business operations and the relationships between those operations. And sometimes, the semantics are obvious. As an example, in the library system, a member returning a book must have already borrowed that book. Theborrow book operation precedes the return book operation. Client design must take these semantics into account.

Resource Design

Following is the URI and HTTP verb mapping for business operations of the library system:

URI

HTTP Method

Collection

Operation

Business Operation

/book

GET

books

retrieve

Get books

/book

POST

books

create

Add book(s)

/book/{book_id}

GET

books

retrieve

Get book data

/member

GET

members

retrieve

Get members

/member

POST

members

create

Add member(s)

/member/{member_id}

GET

members

retrieve

Get member data

/member/{member_id}/books

GET

members

retrieve

Get member borrowings

/member/{member_id}/books/{book_id}

POST

members

create

Borrow book

/member/{member_id}/books/{book_id}

DELETE

members

delete

Return book

 

When it comes to client design, the resource design is given, and is an input to the client design. When it comes to implementing clients, we have to adhere to the design given to us by the service designer. In this example, we designed the API given in the above table, so we are already familiar with the API. Sometimes, you may have to use an API designed by someone else, hence you would have to ensure that you have access to information such as:

  1. Resource URI formats
  2. HTTP methods involved with each resource URI
  3. The resource collection that is associated with the URI
  4. The nature of the operation to be executed combining the URI and the HTTP verb
  5. The business operation that maps the resource operation to the real world context

Looking into the above resource design table, we can identify two resources, book and member. And we could understand some of the semantics associated with the business operations of the resources.

  1. Create, retrieve books
  2. Create, retrieve members
  3. Borrow book, list borrowed books and return book
  4. Book ID and member ID could be used to invoke operations specific to a particular book or member instance

System Implementation

In this section, we will use the techniques on client programming to consume the library service.

These techniques include:

  1. Building requests using XML
  2. Sending requests with correct HTTP verbs using an HTTP client library like CURL
  3. Receiving XML responses and processing the received responses to extract information that we require from the response

Retrieving Resource Information

Here is the PHP source code to retrieve book information.

<?php
$url = 'http://localhost/rest/04/library/book.php';

$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);

$xml = simplexml_load_string($response);

foreach ($xml->book as $book) {
echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";
}
?>

The output generated is shown below

Resource-Oriented Clients with REST PrinciplesResource-Oriented Clients with REST Principles

As per the service design, all that is required is to send a GET request to the URL of the book resource. And as per the service semantics, we are expecting the response to be something similar to:

<books>
<book>
<id>1</id>
<name>Book1</name>
<author>Auth1</author>
<isbn>ISBN0001</isbn>
</book>
<book>
<id>2</id>
<name>Book2</name>
<author>Auth2</author>
<isbn>ISBN0002</isbn>
</book>
</books>

So in the client, we convert the response to an XML tree.

$xml = simplexml_load_string($response);

And generate the output that we desire from the client. In this case we print all the books.

foreach ($xml->book as $book) {
echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";
}

The output is:

    1, Book1, Auth1, ISBN0001
    2, Book2, Auth2, ISBN0002

Similarly, we could retrieve all the members with the following PHP script.

<?php
$url = 'http://localhost/rest/04/library/member.php';

$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);

$xml = simplexml_load_string($response);

foreach ($xml->member as $member) {
echo "$member->id, $member->first_name, $member->last_name <br/>n";
}
?>

Next, retrieving books borrowed by a member.

<?php
$url = 'http://localhost/rest/04/library/member.php/1/books';

$client = curl_init($url);
curl_setopt($client, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($client);
curl_close($client);

$xml = simplexml_load_string($response);

foreach ($xml->book as $book) {
echo "$book->id, $book->name, $book->author, $book->isbn <br/>n";
}
?>

Here we are retrieving the books borrowed by member with ID 1. Only the URL differs, the rest of the logic is the same.

Creating Resources

Books, members, and borrowings could be created using POST operations, as per the service design. The following PHP script creates new book.

<?php

$url = 'http://localhost/rest/04/library/book.php';

$data = <<<XML
<books>
<book><name>Book3</name><author>Auth3</author><isbn>ISBN0003</isbn></book>
<book><name>Book4</name><author>Auth4</author><isbn>ISBN0004</isbn></book>
</books>
XML;

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$response = curl_exec($ch);

curl_close($ch);

echo $response;
?>

When data is sent with POST verb to the URI of the book resource, the posted data would be used to create resource instances. Note that, in order to figure out the format of the XML message to be used, you have to look into the service operation documentation. This is where the knowledge on service semantics comes into play.

Next is the PHP script to create members.

<?php

$url = 'http://localhost/rest/04/library/member.php';

$data = <<<XML
<members><member><first_name>Sam</first_name><last_name>Noel</last_name></member></members>
XML;

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$response = curl_exec($ch);

curl_close($ch);

echo $response;
?>

This script is very similar to the script that creates books. Only differences are the endpoint address and the XML payload used. The endpoint address refers to the location where the service is located. In the above script the endpoint address of the service is:

$url = 'http://localhost/rest/04/library/member.php';

Next, borrowing a book can be done by posting to the member URI with the ID of the member borrowing the book, and the ID of the book being borrowed.

<?php

$url = 'http://localhost/rest/04/library/member.php/1/books/2';


$data = <<<XML
XML;

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$response = curl_exec($ch);

curl_close($ch);

echo $response;
?>

Note that, in the above sample, we are not posting any data to the URI. Hence the XML payload is empty:

$data = <<<XML
XML;

As per the REST architectural principles, we just send a POST request with all resource information on the URI itself. In this example, member with ID 1 is borrowing the book with ID 2.

$url = 'http://localhost/rest/04/library/member.php/1/books/2';

One of the things to be noted in the client scripts is that we have used hard coded URLs and parameter values. When you are using these scripts with an application that uses a Web-based user interface, those hard coded values need to be parameterized.

And we send a POST request to this URL:

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

Note that, even though the XML payload that we are sending to the service is empty, we still have to set the CURLOPT_POSTFIELDS option for CURL. This is because we have set CURLOPT_POST to true and the CRUL library mandates setting POST field option even when it is empty.

This script would cause a book borrowing to be created on the server side. When the member.php script receives a request with the from /{member_id}/books/{book_id} with HTTP verb POST, it maps the request to borrow book business operation. So, the URL

$url = 'http://localhost/rest/04/library/member.php/1/books/2';

means that member with ID 1 is borrowing the book with ID 2.

LEAVE A REPLY

Please enter your comment!
Please enter your name here