Samisa Abeysinghe who is the director of engineering at WSO2 and one of the key leaders of the WSF/PHP project has published a book titled RESTful PHP Web Services.

RESTful PHP Web Services - Samisa Abeysinghe

RESTful PHP Web Services - Samisa Abeysinghe

In Samisa’s Blog He describes the structure and the content of the book in his own words.

If you are developing RESTful web services in PHP, you will find this book will be a great reference.

WSF/PHP Demo Site contains number of sample web service applications which demonstrate the different features of WSF/PHP. From these demos, Mashup Search Demo demonstrate  the use of  publicly available web services to create a search mashup in your web site.

This demo consists of 3 public web services namely Flickr, Yahoo and Amazon.

Flickr Yahoo Amazon
Service Documentation Page Flickr API Docs
Yahoo API Docs
Amazon API Docs
REST/SOAP REST REST SOAP and REST
Registration for Key Flickr API registration
Yahoo API registration
Amazon API Registration
Source code for sample consumer Flickr Demo Source
Yahoo Demo Source
Amazon Demo Source
PHP class used FlickrClient YahooClient AmazonClient
Available Operations
  • photosTextSearch
  • photosTagSearch
  • webSearch
  • newsSearch
  • imageSearch
  • localSearch
  • itemSearch
  • itemLookup

October 18th, 2008Write RESTful Services in C

You can write REST as well as SOAP web services using Apache Axis2/C web services framework. There you can make existing Axis2/C web services RESTful just by providing the URL patterns and the HTTP methods to each operation in  the services.xml which act as a simple descriptor for an Axis2/C service.

So if we rewrite the RESTful Demo (Written in PHP) using Axis2/C, the services.xml would be something like following.

<service name="RESTfulSchool">
    <!-- mentioning the service library-->
    <parameter name="ServiceClass" locked="xsd:false">RESTfulSchool</parameter>

    <!-- some description -->
    <description>
        The RESTful School demo
    </description>

    <!-- list of operations -->
    <operation name="getSubjects">
            <parameter name="RESTMethod">GET</parameter>
            <parameter name="RESTLocation">subjects</parameter>
    </operation>
    <operation name="getSubjectInfoPerName">
            <parameter name="RESTMethod">GET</parameter>
            <parameter name="RESTLocation">subjects/{name}</parameter>
    </operation>
    <operation name="getStudents">
            <parameter name="RESTMethod">GET</parameter>
            <parameter name="RESTLocation">students</parameter>
    </operation>
    <operation name="getStudentInfoPerName">
            <parameter name="RESTMethod">GET</parameter>
            <parameter name="RESTLocation">students/{name}</parameter>
    </operation>
    <operation name="getMarksPerSubjectPerStudent">
            <parameter name="RESTMethod">GET</parameter>
            <parameter name="RESTLocation">students/{student}/marks/{subject}</parameter>
    </operation>
</service>

We will check how to write the service logic for a operation like “getMarksPerSubjectPerStudent”.

axiom_node_t *
RESTfulSchool_getMarksPerSubjectPerStudent(
    const axutil_env_t * env,
    axiom_node_t * request_payload)
{
    axiom_node_t *student_node = NULL;
    axiom_node_t *subject_node = NULL;

    /* Extracting out the child nodes from the request */
    student_node = axiom_node_get_first_child(request_payload, env);
    subject_node = axiom_node_get_next_sibling(student_node, env);

    /* now we can write the logic to retrieve the marks
       for the given student and subject and build and
       return the response payload */

    return response_payload;
}

As you can see the variables {student} and {subject} given in the services.xml can be easily accessed from your business logic, so we can build the response accordingly.

This way you can build a RESTful web services easily using C language.

Last week I wrote a how to on Writing a SOAP and REST Service with PHP. It shows how to write a single script that enables the SOAP and REST web services interfaces using WSF/PHP. Today I’m going to show you how you can use WSF/PHP to write clients in both SOAP and REST form.

For that I use the Amazon Client Demo hosted in the PHP Web Services Demo Site. With this demo you can do shopping with Amazon using their web services API. It uses a php library (AmazonClient.php) that allows us to connect Amazon using SOAP or REST libraries.

You can see in the library code It is using different values for “useSOAP” argument depending on what form of messaging we like to use. Amazon SOAP service uses the SOAP 1.1 and the REST service uses the “GET” HTTP method for messaging. We can configure these details as mentioned in the following table.

REST SOAP
array(
      "to"=>self::AMAZON_REST_ENDPOINT,
      "HTTPMethod"=>"GET",
      "useSOAP" => FALSE)
array(
      "to"=>self::AMAZON_SOAP_ENDPOINT,
      "useSOAP" => "1.1",
      "action" => "http://soap.amazon.com")

Since Amazon requires different request messages for SOAP and REST services, we have to create them separately depending on the request type. But the response returns by the service is same in both cases so we can handle it using the same code.

Here is how ItemLookup operation of the Amazon service is written within the above mentioned constrains.

    /**
     * ItemLookup
     * @param $ASIN Amaxon Item Id
     * @return associate array consist of the response parameters
     */
    public function ItemLookup($ASIN)
    {

        if($this->is_soap)
        {
             $req_payload = <<<XML
                <ItemLookup xmlns="http://webservices.amazon.com/AWSECommerceService/2007-10-29">
                    <SubscriptionId>{$this->amazon_key}</SubscriptionId>
                    <ResponseGroup>Medium</ResponseGroup>
                    <Request>
                        <ItemId>{$ASIN}</ItemId>
                        <ReviewPage>1</ReviewPage>
                    </Request>
                </ItemLookup>
XML;
        }
        else
        {
             $req_payload = <<<XML
                <ItemLookup xmlns="http://webservices.amazon.com/AWSECommerceService/2007-10-29">
                    <SubscriptionId>{$this->amazon_key}</SubscriptionId>
                    <Service>AWSECommerceService</Service>
                    <ResponseGroup>Large</ResponseGroup>
                    <Operation>ItemLookup</Operation>
                    <ItemId>{$ASIN}</ItemId>
                    <ReviewPage>1</ReviewPage>
                </ItemLookup>
XML;
        }

        $ret_message = $this->request($req_payload);

        $simplexml = new SimpleXMLElement($ret_message->str);

        $res = $simplexml;

        return $res;
    }

WSF/PHP enables you to write both REST and SOAP services in PHP from a single script. I have written about how you can expose your Database as a REST and SOAP services in few of my previous posts using the Data Service capability of WSF/PHP. But there can be situations where your service is not based on a Database. For an example it can use results of some calculations, or a mashup calling other services. In that case you will prefer to write the service logic yourself. Here is how you can do it.

Lets think we have weather forecast data (may be from another service) and I want to make a web service using it and make it accessible via both REST and SOAP protocols.

In our demo service we give forecasts of temperature, humidity and some other parameters for a given date. So I expect

SOAP request payload as following.

<weatherReport>
  <date>{date}</date>
  <parameter>{parameter}</parameter>
</weatherReport>

And REST Request will be like

weatherReport/{date}/forecast/{parameter}

Note that here parameter can hold values like temperature, humidity or sunset-time.

First we declare our operation and the REST Request Mapping like this,

$operations = array("weatherReport" => "weather_report");
$restmap = array("weatherReport" =>
				array("HTTPMethod" =>"GET",
				      "RESTLocation" => "weatherReport/{date}/forecast/{parameter}"));

When you declare your rest mapping like above , in the service operation you will have the same request XML for both SOAP and REST form like this,

<weatherReport>
  <date>{date}</date>
  <parameter>{parameter}</parameter>
</weatherReport>

So in your service logic you just handling the request in only above format. You can easily extract out the request parameters using SimpleXML functions and return the corresponding result. So you service operation would be something like this,

function weather_report($in_message) {

	// create the simple xml element for the request xml
	$request_xml = new SimpleXMLElement($in_message->str);

	// extract out the parameter and the date
	$date = $request_xml->date;
	$parameter = $request_xml->parameter;

	// It is up to you to retrun the weather data ($result) for the requested date and parameter

	return "<response>$result</response>";
}

Finally you create the WSService object with the “operations” and “RESTMapping” and call its reply method which actually response to the requests.

$service = new WSService(array("operations" => $operations, "RESTMapping" => $restmap));
$service->reply();

You just created a web service which will handle both SOAP and REST requests.

PHP in most percentage is used with MySQL Server in LAMP or WAMP stacks. But there may be situations where PHP uses MSSQL databases in back-end. And PHP scripts can be used to make Web services exposing MSSQL Databases. That is enabled by the  Data Services capability in WSF/PHP 2.0.0.

Here are the steps to get the PHP Data Services working with MSSQL in windows. You can safelty skip the starting point if you have already have the necessory software installed.

  • Download Apache Web Server, PHP and MSSQL server. (You can download the MSSQL server 2005 expess edition from here.
  • Enable the php_mssql, php_pdo and php_pdo_mssql extension from the php.ini.
  • If you have MSSQL server 2005, the default client DLL (ntwdblib.dll) use to connect to MSSQL server will not work. So you need to download a newer version of this dll. You can easily find this googling the name of the dll. (The dll version worked for me is 2000.80.194.0). Copy this dll to following directories.
    • <your_windows_drive>/windows/system32
    • <your_apache_installation>/apache2/bin
  • To Demo purpose I have created a MSSQL database called “RESTFulSchool” and and table called ‘Subjects” with the following schema. If you already have a MSSQL database you can just continue with that.
    Column Name Data Type
    subjectID int
    subjectName text
    subjectTeacher text

    And make sure you fill some data into the table. You can get this done easily with MSSQL Server Management Studio downloadable from http://www.microsoft.com/sql/editions/express/default.mspx

  • So here is my code to the Data Service. Note in the config variable I have given the information about my MSSQL connection.
    <?php
    
    //Including the Data Services library
    require_once("wso2/DataServices/DataService.php");
    
    //Including the connection information for my MSSQL Connection
    require_once("constants.php");
    
    // database configurations
    $config = array(
    		"db" => "mssql",
    		"username" => MSSQL_USERNAME
    		"password" => MSSQL_PASSWORD
    		"dbname" => "RESTfulSchool",
    		"dbhost" => MSSSQL_SERVER_NAME
    		);
    
    $output_format = array(
                        "resultElement" => "subjects",
                        "rowElement" => "subject",
                        "elements" => array(
                                "name" => "subjectName",
                                "teacher" => "subjectTeacher"));
    
    $sql = "SELECT subjectName, subjectTeacher FROM Subjects";
    
    $get_subjects_op = array("outputFormat" => $output_format, "sql" => $sql);
    
    $get_subjects_url = array("HTTPMethod" => "GET", "RESTLocation" => "subjects");
    
    // list of operations
    $operations = array(
                    "getSubjects" => $get_subjects_op,
                    );
    
    // list of rest url mappping (operation => url)
    $restmap = array(
                    "getSubjects" => $get_subjects_url,
                    );
    
    // creating DSService and reply
    $service = new DataService(array("config" => $config, "operations" => $operations, "RESTMapping"=>$restmap));
    $service->reply();
    
    ?>
  • You just wrote a SOAP+REST Data Service to expose your MSSQL Data as a Web Service. Now Put this script (say school_service.php) in to the Apache web directory and access it using a browser with the following url.
    http://localhost//school_service.php/subjects

    If you have done every thing right, you should see a nice xml showing your data. Note that here we used REST interface to test our service. You don’t need to do any thing special to expose it as SOAP. Its SOAP endpoint would be simply

    http://localhost//school_service.php

Get the WSDL Generation working with MSSQL
If you try to retrieve the WSDL for the above service using this URL

http://localhost//school_service.php?wsdl

You will get an error message saying that the meta data retrieval is not supported for this particular driver (MSSQL Driver). For the time being, in order to get rid of this warning you have to disable showing warnings in your PHP programs. You can get it done by editing the php.ini with this entry

error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING

But even with this fix, the schema types of the name and teacher entries will be shown as “xsd:anyType”. If you want to have a more specific type associated with them, Just change the $output_format variable to the following.

$output_format = array(
                    "resultElement" => "subjects",
                    "rowElement" => "subject",
		    "elements" => array(
			"name" => array("column" => "subjectName", "xsdType" => "xsd:string"),
			"teacher" => array("column" => "subjectTeacher", "xsdType" => "xsd:string")));

Here instead of giving a string to ‘teacher’ and ‘name’ entries, we give an array containing both column name and the the custom xsd type we want to appear in the WSDL.  Note that this fix is needed only for databases that doesn’t provide the meta data interface through the PHP PDO layer. For database like mysql wsdl generation works straight away.

The REST API for Twitter is very simple to learn and implement. And it has a comprehensive documentation.

Here is some selected operations to just to show its design. Note that here userid should be replaced with a valid twitter user id or user name and the format should be changed to the required output format (.xml, json, rss, atom are possible output formats)

Operation HTTP Verb URL Example HTTP Request (Setting username as ‘dimuthu’ and the output format as .xml)
Get public (all users) statuses GET http://twitter.com/statuses/public_timeline GET http://twitter.com/statuses/public_timeline
Get a user statuses GET http://twitter.com/statuses/user_timeline/userid.format GET http://twitter.com/statuses/user_timeline/dimuthu.xml
Get a particular status GET http://twitter.com/statuses/show/statusid.format GET http://twitter.com/statuses/show/938135815.xml
Create a new status POST http://twitter.com/statuses/update.format POST http://twitter.com/statuses/update.xml
Authorization: Basic xxxx
………..
<status>my status message</status>
Delete a particular status DELETE/ POST http://twitter.com/statuses/destroy/statusid.xml DELETE http://twitter.com/statuses/destroy/939390294.xml
Authorization: Basic xxxx
………..

After having look at this API, the first question I had was whether this API is actually RESTful. In RESTful design we expect to map a resource to a URL and do CRUD (Create, Read, Update and Delete) operations using request with different Http Verbs (POST, GET, PUT, DELETE) with that same URL. Look at my blog on RESTful CRUD Data Services Demo for more clarification.

So if ever the API is designed following the above theory it would have been like this.

Operation HTTP Request
Get all statuses GET http://twitter.com/statuses.xml
Get a particular user statuses GET http://twitter.com/users/{user_id}/statuses.xml
Get a particular statuses of a user GET http://twitter.com/users/{user_id}/statuses/{status_id}.xml
Crete a particular statuses of a user POST http://twitter.com/users/{user_id}/statuses.xml
Update a particular statuses of a user PUT http://twitter.com/users/{user_id}/statuses/{status_id}.xml
Delete a particular statuses of a user DELETE http://twitter.com/users/{user_id}/statuses/{status_id}.xml

So I think although Twitter API is really nice and easy, it is not really a RESTful API. If it was really RESTful, URLs might have been more organized so more easier to remember or predict. But still this API allows thousands of third party application to talk to the twitter, demonstrating the value of  providing web services over just providing some web pages in a website.

September 27th, 2008RESTful CRUD Data Services Demo

When you are developing Web Service for CRUD (Create, Read, Update, Delete) operations you may find it is easy to implement it as RESTful service. In this Demo on RESTful CRUD Service You can have an idea how you develop such a service with WSO2 WSF/PHP.

Here we take a scenario of submitting applications (say for a school).

In RESTful world we map a resource to a unique URL. In this demo, application is a resource. We use the URL “application/{id}” to represent a particular application with the id {id}.

You can  use  HTTP verb + Resource URL touples to manipulate the resource with CRUD operations.  Here is how it is done in this particular demonstration.

Request format (HTTP Verb + URL) Operation Semantic
POST applications/{id} Create an application
GET applications/{id} Get an application
PUT applications/{id} Change an application
DELETE applications/{id} Delete an application

Go for the wsf/php demo sitefor the live demo of this service. Visit the demo service source code to see how easy to implement it with WSF/PHP Data Services library.

I wrote a similar blog on Data Services last week to demonstrate how you design the mapping of url to different resources in a RESTful Service.


© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress