Showing posts with label RESTful. Show all posts
Showing posts with label RESTful. Show all posts

Sunday, April 12, 2015

generate a self signed certification for dropwizard


1. use JDK keytool to generate keystore:

yiyujia@hadoopDev: keytool -genkeypair -keyalg RSA -dname "CN=localhost" -keystore linkedBAC.keystore -keypass 123456 -storepass 12345


2. modify Dropwizard configuration file as bellow.

server:
 #  softNofileLimit: 1000 #  hardNofileLimit: 1000   applicationConnectors:
     - type: http
       port: 8088
     - type: https
       port: 8443
       keyStorePath: linkedBAC.keystore
       keyStorePassword: 123456
       validateCerts: false       validatePeers: false   adminConnectors:
     - type: http
       port: 8081
     - type: https
       port: 8444
       keyStorePath: linkedBAC.keystore
       keyStorePassword: 123456
       validateCerts: false       validatePeers: false

3. Using curl to test your Dropwizard applicaiton.

curl -k --data "user_name=yiyu&password=123456&device_id=1&grant_type=password" https://localhost:8443/oauth2/token/accessToken


4. Or, if want to use web browser to test, we need to add self signged certification as exception by following steps as below.














Tuesday, September 23, 2014

OAuth2.0 refresh token and access token


When we implement OAuth2, we have access token and refresh token. Why do we need both refresh token and access token? Using plain English, below are reasons in simplified version.


  • For security reason, OAuth2 has both refresh token and access token. access token is something close to one-time password, which is ideally secure. access token may be expired shortly. Refresh token may last for long time and even will not expire until it will be revoked. 


  • For performance and scalability reason, it better to verify HTTP request on the resource server instead of on central authorization server for every HTTP request.


  • Basically, access_token is kind of temporary password and refresh_token is pass to get temporary password from central authentication server. "temporary" password, access_token, is verified on resource server.

    Wednesday, October 26, 2011

    A simple tutorial about Exception handling in Jersey 1.1.5

    There are at least three ways for us to deal with Exception in Jersey RESTful framework.

    1. Create a WebApplicationException instance and throw it in code.
    2. Extending your own Exception from WebApplicationException and throw your own exception in code
    3. creating an ExceptionMapper to have chance to further customize response upon exception.

    This simple tutorial shows how to map our own defined exception in Jersey. Code has been created and tested in netbeans 6.9.1 with Jersey version 1.1.5 and Tomcat 6.

    creating our dummy runtime exception class

    package jia.blog;
    
    public class JiaAppException extends RuntimeException{
    
        public JiaAppException( String message ) {
            super( message );
        }
    
    }
    

    Create our testing Web service

    package jia.blog;
    
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.UriInfo;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.GET;
    import javax.ws.rs.Produces;
    
    /**
     * REST Web Service
     *
     * @author Yiyu Jia
     */
    
    @Path("generic")
    public class WSTester {
        @Context
        private UriInfo context;
    
        /** Creates a new instance of WSTester */
        public WSTester() {
        }
    
        /**
         * Retrieves representation of an instance of jia.blog.WSTester
         * @return an instance of java.lang.String
         */
        @GET
        @Produces("application/xml")
        public String getXml() {        
             throw new JiaAppException("Sorry. You are not allowed to access this resource.");
        }
    
    }
    

    Creating Exception Mapper class

    package jia.blog;
    
    import javax.ws.rs.core.GenericEntity;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.ext.ExceptionMapper;
    import javax.ws.rs.ext.Provider;
    
    /**
     *
     * @author Yiyu Jia
     */
    
    @Provider
    public class JiaExceptionMapper implements ExceptionMapper< jiaappexception > {
    
        @Override
        public Response toResponse(JiaAppException jiaException) {
            
            GenericEntity ge = new GenericEntity < string > ( jiaException.getMessage ( ) ) { };
    
            return Response.status(Response.Status.FORBIDDEN).
                    entity(ge).build();
        }
    }
    
    

    The web.xml file

    Note: no servlet init param 'com.sun.jersey.config.property.packages'
    
        
            ServletAdaptor
            com.sun.jersey.spi.container.servlet.ServletContainer       
            1
        
        
            ServletAdaptor
            /resources/*
        
        
            
                30
            
        
        
            index.jsp
        
    
    

    Test it

    If you deploy web app on tomcat running on localhost and listen on port 8080, you test by pointing web browser to access URL http://localhost:8080/JerseyTest/resources/generic .

    Wednesday, September 28, 2011

    How to model RESTful Web Service

    I see somebody lost way when he/she tries to model RESTful Web service. The issues I noticed are,
    • Not always keep in mind that RESTful Web Service is CRUD on "resources".
    • Put verbs in URI. Therefore, the concept about resources is messy up. 
    • Not think that URI is a hierarchy structure to help on organizing "resources"
     So, I made below picture to help on modeling RESTful Web Service.



    Simplicity should be one of major reasons for us to adopt RESTful Web service. So, I think it is unnecessary to make RESTful model to be complicate. Another major reason to use RESTful Web Service is that the motivation of project is to "share resources" over the Internet/Intranet (or should say in Cloud? :) ). With these concepts in mind, we can divide the modeling process into four steps as below,
    1. Tell myself that I am going to make software to share "resource" as sharing HTML pages.
    2. Making a sheet to list/add resources into it.
    3. Check each resource and see if it need to be further categorized, Or, we will think if we need to have a reserved category for future. These categories will be mapped into URL. 
    4. For each classified resource, we can do CRUD operations, which maps to HTTP verbs POST, GET, PUT, or DELETE.
    Using the Customer in above picture as an example, it is a kind of Resource. Customers are under different categories, silver and gold. For each customer, we can do CRUD operation. Then, the URI for getting a customer may like this: /resources/customer/silver/customerID/

    It is better to avoid putting verbs in URI because we are going to share resource and verbs (operation) will be indicated by HTML verbs. Of course, it will still work if we put verbs in URI. It is just string. There is no standard spec for RESTful Web Service. We can define our own languge/protocl in URI. But, what I introduce here should be helpful for organizing analysts' thoughts and make models to be neat and SIMPLE.

    Friday, September 9, 2011

    A simple tutorial about creating Jersey RESTful web service in Netbean 7.0

    I believe that new technologies should make things simpler instead of more complex. RESTful Web service is one of them. But, it seems there is no very simple tutorial about how to create RESTful Web service in Netbean. So, here is a extremely simple tutorial about how to create a Servlet based only RESTful web service in Netbeans 7.0.

    There are several different RESTful web service frameworks on the market. Jersey is one of them. Jersey is reference implementation of JSR 311: JAX-RS: The JavaTM API for RESTful Web Services . The follows steps will show how easy it is to create a RESTful Web Service in Netbeans 7.0.

    1)Create a Web application






    2) Create our first RESTful Web service in Netbeans 7.0 with Jersey.








    3) Test it.

    Once we successfully did above steps, we see a new Restful Web Service folder in project as shown below.

    We modify and add hello world string into GenericResource.java as shown below,
    /**
    * Retrieves representation of an instance of jia.blog.rest.GenericResource
    * @return an instance of java.lang.String
    */
    @GET
    @Produces("text/html")
    public String getHtml() {
       //TODO return proper representation object
       return "

    Hello World!

    "; }

    Then we compile and deploy the project. Once we successful deployed it. We can test our hello world example by using the following URL:

    http://localhost:8080/jerseyRest/firstREST/generic

    I purposely use different string "jerseyRest", "fristREST", "generic" in URL as this way can help you to map string in URL into the place where we input in netbeans 7.0.

    Also, this simple hello world example has been successfully tested on JDK 1.5 and Tomcat 6.0 environment. So, it works on i5/OS V5R4 platform too.

    Here is the link to source code jiaRest.zip

    Friday, July 1, 2011

    ExtJS 4 REST proxy and Zend framework Zend_Rest_Route are incompatible.

    I noticed a very strange thing when I worked on Ext JS 4 v4.0.2 and Zend Framework. I find that every time when Ext JS grid sends new created Record to the server through its REST proxy, the POST method was teated as PUT method in Zend_Rest_Route. This cause troublesome because my code have to know if the incoming record a new one for insert or exsiting one for update. Otherwise, I have to use some UPSERT SQL statement to UPDATE or INSERT record into Database table. Unfortunately, I use DB2 for i5/OS V5R4, which does not have built-in UPSERT command and it even does nor support MERGE statement.

    I do not want to walkaround this by doing SELECT first and judging if the code need to run INSERT or UPDATE statement. So, I traced the Ext JS 4 code and Zend Framework 1.11 code. I found that these two are not compatiable. I am not sure if we can say it is BUG as this wont happen if either side change their code. Or, both side can change the code to avoid the confilicaton if we say bugs are from both sides.

    The key for this issue is that Ext JS 4 append record's id at the end of base URL, which points to RESTful service. Below is a psuedo POST URL create by Ext JS 4 REST proxy. I highlight the unexpected friend in red color.

    http://hostname/yourRestServiceURI/yourRecordId/?dc=randomNum


    We understand that adding record id as part of URI can allow server side script easily find it. But, why this design is implemented in a general SDK like Ext JS? Especially, I do not see good reason for a POST request to have it as record in POST are suppoe not to have been existing on server side. Therefore, the ID of the new record might not have been generated if it will be generated on the server side only.

    In Ext JS 4 source code \src\data\proxyRest.js, we can see what happens,
    /**
         * Specialized version of buildUrl that incorporates the {@link #appendId} and {@link #format} options into the
         * generated url. Override this to provide further customizations, but remember to call the superclass buildUrl
         * so that additional parameters like the cache buster string are appended
         */
        buildUrl: function(request) {
            var me        = this,
                operation = request.operation,
                records   = operation.records || [],
                record    = records[0],
                format    = me.format,
                url       = me.getUrl(request),
                id        = record ? record.getId() : operation.id;
            
            if (me.appendId && id) {
                if (!url.match(/\/$/)) {
                    url += '/';
                }
                
                url += id; //Why add ID here even for POST? Yiyu Jia
            }
            
            if (format) {
                if (!url.match(/\.$/)) {
                    url += '.';
                }
                
                url += format;
            }
            
            request.url = url;
            
            return me.callParent(arguments);
        }
    }
    

    Now, people will ask why adding id in URL cause the problem in Zend Framework? Well, let's trace Zend Framework code now.

    On Zend Framework API document about Zend_Rest_Route, we can see Zend clearly described their design how RESTful URI should looks like,
    Zend_Rest_Route Behavior
    MethodURIModule_Controller::action
    GET/product/ratings/Product_RatingsController::indexAction()
    GET/product/ratings/:idProduct_RatingsController::getAction()
    POST/product/ratingsProduct_RatingsController::postAction()
    PUT/product/ratings/:idProduct_RatingsController::putAction()
    DELETE/product/ratings/:idProduct_RatingsController::deleteAction()
    POST/product/ratings/:id?_method=PUTProduct_RatingsController::putAction()
    POST/product/ratings/:id?_method=DELETEProduct_RatingsController::deleteAction()

    As we can see, Zend Framework does not expect any thing attached to method URI when PHP programmer intend to use POST method. In Zend_Rest_Route source code, we can see a case switch statement as below. You will see when the POST method will be "magically" routed to PUT method if pathElementCount is larger than zero.

    switch( $values[$this->_actionKey] ){
                        case 'post':
                            if ($pathElementCount > 0) {
                                $values[$this->_actionKey] = 'put';
                            } else {
                                $values[$this->_actionKey] = 'post';
                            }
                            break;
                        case 'put':
                            $values[$this->_actionKey] = 'put';
                            break;
                    }
    
    

    But, where is the $pathElementCount set? In the same source code file, we can see below statement,

    //Store path count for method mapping
    $pathElementCount = count($path);
    

    So, where is value of $path populated? Still, in the same source code, there is a function call match. Part of it is cited as below.

    /**
         * Matches a user submitted request. Assigns and returns an array of variables
         * on a successful match.
         *
         * If a request object is registered, it uses its setModuleName(),
         * setControllerName(), and setActionName() accessors to set those values.
         * Always returns the values as an array.
         *
         * @param Zend_Controller_Request_Http $request Request used to match against this routing ruleset
         * @return array An array of assigned values or a false on a mismatch
         */
        public function match($request, $partial = false)
        {
            if (!$request instanceof Zend_Controller_Request_Http) {
                $request = $this->_front->getRequest();
            }
            $this->_request = $request;
            $this->_setRequestKeys();
    
            $path   = $request->getPathInfo();
            $params = $request->getParams();
            $values = array();
            $path   = trim($path, self::URI_DELIMITER);
    

    Ok, now, it is not the end of code tracing yet. Where is the getPathInfo() function? It is in Zend_Controller_Request_Http. The following code citation will show us that getPathInfo() eeturns everything between the BaseUrl and QueryString and deos something special.

    /**
         * Returns everything between the BaseUrl and QueryString.
         * This value is calculated instead of reading PATH_INFO
         * directly from $_SERVER due to cross-platform differences.
         *
         * @return string
         */
        public function getPathInfo()
        {
            if (empty($this->_pathInfo)) {
                $this->setPathInfo();
            }
    
            return $this->_pathInfo;
        }
    

    /**
         * Set the PATH_INFO string
         *
         * @param string|null $pathInfo
         * @return Zend_Controller_Request_Http
         */
        public function setPathInfo($pathInfo = null)
        {
            if ($pathInfo === null) {
                $baseUrl = $this->getBaseUrl(); // this actually calls setBaseUrl() & setRequestUri()
                $baseUrlRaw = $this->getBaseUrl(false);
                $baseUrlEncoded = urlencode($baseUrlRaw);
            
                if (null === ($requestUri = $this->getRequestUri())) {
                    return $this;
                }
            
                // Remove the query string from REQUEST_URI
                if ($pos = strpos($requestUri, '?')) {
                    $requestUri = substr($requestUri, 0, $pos);
                }
                
                if (!empty($baseUrl) || !empty($baseUrlRaw)) {
                    if (strpos($requestUri, $baseUrl) === 0) {
                        $pathInfo = substr($requestUri, strlen($baseUrl));
                    } elseif (strpos($requestUri, $baseUrlRaw) === 0) {
                        $pathInfo = substr($requestUri, strlen($baseUrlRaw));
                    } elseif (strpos($requestUri, $baseUrlEncoded) === 0) {
                        $pathInfo = substr($requestUri, strlen($baseUrlEncoded));
                    } else {
                        $pathInfo = $requestUri;
                    }
                } else {
                    $pathInfo = $requestUri;
                }
            
            }
    
            $this->_pathInfo = (string) $pathInfo;
            return $this;
        }
    

    So, what is the conclusion? The conclusion is that both Ext JS and Zend framework has their own design of RESTful URI pattern. Unfortunately, they are not compatible with each other. They are too nice to do more than developer expected. As libraries vendor, they maybe should do less sometimes in order to make their library as general as possible. Ext JS, as a pure client side JavaScript library, should not guide server side script designer how to implement RESTful Web service. Zend Framework, as a pure server side script library, should not make design for client side application either. In fact, RESTful Web service is a set of guide lines for developer to make scalable application over HTTP methods. But, it does not define how the URI pattern must be.

    Thursday, June 23, 2011

    Managing Grid CRUD In ExtJS 4

    I read a discussion on Sencha forum (here). Obviously, ExtJS 4 make user to be frustrating because of the lack of well organized document and lack of well commented sample code. Probably, it is just because ExtJS 4 is too new that developers have not catch up. However, since ExtJS is partially commercial product instead of a pure open source project, its quality should be well controlled before it announce final release. Here is a little bit experiece on how to make a CRUD grid with ExtJS 4.

    To successfully use Grid, auto sync store, and rowediting plugin in ExtJS 4, there are several points need to be highlighted. I listed them as below,


    1. In your Model class, you have to either define a hardcoded 'id' property or use 'idProperty' to specify one column as 'id'.
    2. You server side code need to return processed records back to browser. I tried only send back "id" in "data" part. But, it is not successful.
    3. Be aware that the format of record in the "data" has JSON format.
    4. Be sure to implemented at least one Validator in your Model class because, in ExtJS source code AbstractStore.js, you can find the following code, which may always return true for a new created record in RowEditing plugin when the store is set as autoSync = true

    /**
         * @private
         * Filter function for new records.
         */
        filterNew: function(item) {
            // only want phantom records that are valid
            return item.phantom === true && item.isValid();
        },
    

    Most likely, we wont use auto sync store in real product. But, this example could be a good start.

    Tuesday, November 9, 2010

    creating RESTful service with Zend_Rest_Route and Zend_Rest_Controller

    After trying different ways to make RESTful WS in Zend Framework, I am aware that I can simply use Zend_Rest_Route and ZendRest_Controller to make "standard" RESTful WS in PHP. Especially, Zend_Rest_Route supports RESTful URI pattern like /parameterName/parameterValue/.... This is different from what I read from forums. I am using Zend Framework 1.10 in Zend Server 5.0.1 running on IBM i. Zend_Rest_Server is really not good choice to make RESTful service. Zend_Rest_Server needs to be further improved to meet the requirement of "standard" RESTful.

    I tried Zend_Controller_Router_Route to implemented RESTful URI pattern. But, it is easier to use Zend_Rest_Route and Zend_Rest_Controller. Actually, Zend_Rest_Controller does nothing but defines several abstract methods, which map to relevant HTTP methods. But, our RESTful controller must extend from it. Below is the sample codes. In my environment, I can access it with this URL: http://localhost/jiaRESTfulWS/public/index/product/fish/number/100/

    BootStrap class
    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {
     //adding this function in Bootstrap class to initilize Zend_Rest_Route.
     protected function _initRestRoute() {
      //getting an instance of zend front controller.
      $frontController = Zend_Controller_Front::getInstance ();
      //initializing a Zend_Rest_Route
      $restRoute = new Zend_Rest_Route ( $frontController );
      //let all actions to use Zend_Rest_Route.
      $frontController->getRouter ()->addRoute ( 'default', $restRoute );
     }
     
    }
    

    IndexController.php
    class IndexController extends Zend_Rest_Controller
    {
     
     public function init() {
      $this->getHelper ( 'viewRenderer' )->setNoRender ( true ); 
     }
     
     /**
      * The index action handles index/list requests; it should respond with a
      * list of the requested resources.
      */
     public function indexAction() {
      //HTTP code 500 might not good choice here.
      $this->getResponse ()->setHttpResponseCode ( 500 );
      $this->getResponse ()->appendBody ( "no list/index allowed" );
      
     } 
     
     /**
      * The get action handles GET requests and receives an 'id' parameter; it
      * should respond with the server resource state of the resource identified
      * by the 'id' value.
      */
     public function getAction() {  
      
      //I will return result in XML format.
      $this->getResponse ()->setHeader ( 'Content-Type', 'text/xml' );
      
      //Note: the Request object here is not HttpRequest. It is Zend controller request. This is the key!
      if ($this->getRequest ()->getParam ( "product" ) != NULL and $this->getRequest ()->getParam ( "number") != NULL ) {   
       //Initializing a dummy object for return. 
       $return = new Jia_Return ();
       $return->setProducts ( $this->getRequest ()->getParam ( "product" ) );
       $return->setQuantity ( $this->getRequest ()->getParam ( "number" ) );
       //We prevent the product has been found.
       //So, we set HTTP code 200 here.  
       $this->getResponse ()->setHttpResponseCode ( 200 );
      }    
       else {
        $return= new Jia_ErrorCode('no parameters!');
        //prevent the product is not found.
        $this->getResponse ()->setHttpResponseCode ( 200 );
       }
      
      print $this->_handleStruct( $return );
     
     }
     
     /**
      * The post action handles POST requests; it should accept and digest a
      * POSTed resource representation and persist the resource state.
      */
     public function postAction() {
      
     }
     
     /**
      * The put action handles PUT requests and receives an 'id' parameter; it
      * should update the server resource state of the resource identified by
      * the 'id' value.
      */
     public function putAction() {
     
     }
     
     /**
      * The delete action handles DELETE requests and receives an 'id'
      * parameter; it should update the server resource state of the resource
      * identified by the 'id' value.
      */
     public function deleteAction() {
     
     }
     
      
     /**
      * Handle an array or object result
      *
      * @param array|object $struct Result Value
      * @return string XML Response
      */
     protected function _handleStruct($struct) {
    
      $dom = new DOMDocument ( '1.0', 'UTF-8' );
      
      $root = $dom->createElement ( "Jia" );
      $method = $root;
      
      $root->setAttribute ( 'generator', 'Yiyu Blog' );
      $root->setAttribute ( 'version', '1.0' );
      $dom->appendChild ( $root );
      
      $this->_structValue ( $struct, $dom, $method );
      
      $struct = ( array ) $struct;
      if (! isset ( $struct ['status'] )) {
       $status = $dom->createElement ( 'status', 'success' );
       $method->appendChild ( $status );
      }
      return $dom->saveXML ();
     }
     
     /**
      * Recursively iterate through a struct
      *
      * Recursively iterates through an associative array or object's properties
      * to build XML response.
      *
      * @param mixed $struct
      * @param DOMDocument $dom
      * @param DOMElement $parent
      * @return void
      */
     protected function _structValue($struct, DOMDocument $dom, DOMElement $parent) {
      $struct = ( array ) $struct;
      
      foreach ( $struct as $key => $value ) {
       if ($value === false) {
        $value = 0;
       } elseif ($value === true) {
        $value = 1;
       }
       
       if (ctype_digit ( ( string ) $key )) {
        $key = 'key_' . $key;
       }
       
       if (is_array ( $value ) || is_object ( $value )) {
        $element = $dom->createElement ( $key );
        $this->_structValue ( $value, $dom, $element );
       } else {
        $element = $dom->createElement ( $key );
        $element->appendChild ( $dom->createTextNode ( $value ) );
       }
       
       $parent->appendChild ( $element );
      }
     }
     
    }
    
    Return.php
    /**
     * A dummy class as return objec.
     * 
     * @author Yiyu Jia
     *
     */
    class Jia_Return {
     
     /**
      * 
      * @var unknown_type
      */
     public $products;
     public $quantity;
     /**
      * @return the $products
      */
     public function getProducts() {
      return $this->products;
     }
    
     /**
      * @param $products the $products to set
      */
     public function setProducts($products) {
      $this->products = $products;
     }
     /**
      * @return the $quantity
      */
     public function getQuantity() {
      return $this->quantity;
     }
    
     /**
      * @param $quantity the $quantity to set
      */
     public function setQuantity($quantity) {
      $this->quantity = $quantity;
     }
     
    }
    

    ErrorCode.php
    /**
     * An dummy error code class.
     * 
     * @author Yiyu Jia
     *
     */
    class Jia_ErrorCode { 
     
     public $errorCode;
     
     function __construct($errMsg){
      $this->errorCode = $errMsg;
     }  
    
    }
    

    ZendStudio 7.2 project file can be downloaded from here.

    Friday, November 5, 2010

    A simple tutorial about creating Zend_Rest_Server based RESTful service.

    It seems that RESTful WS is attracting more people to consider as RPC solution. Compared with SOAP based Web Service, RESTful has its advantage and disadvantage. RESTful WS is declared to be more scalability as it exactly maps HTTP methods  POST, GET, PUT, DELETE as a CRUD (Create, Request, Update, Delete) operations. So, if we design our RESTful WS as stateless, it could be more scalable in a cluster farm. It can get benefit from Cache mechanism of HTTP (limited to HTTP GET method configuration on proxy server in most time). However, it could be problem or ask for cost if we do not want the result to be cached. Furthermore, we can not always assume client Web browser has cache enabled. So, RESTful is not always right choice. Especially, it is not good choice when we develop an enterprise application which ask for complex data structure delivered between sub systems and it does not have extremely large volume of the concurrent accessing.

    I will compose another post to describe my comparison about SOAP WS and RESTful WS and JSON-RPC. Here, I will show a simple demo about how to create Zend_Rest_Server based RESTful WS in Zend Studio. Zend_Rest_Server is not perfect. For instances, it can not work together with Zend_Action_Router_Route. It also asked for calling function by put "method=functionName" in requesting URL after the "?". This make some guys think it is not RESTful WS as some person said it is not good design. But, I think it is not wrong design at least.  Below is source for simple ZF based RESTful WS.
    1. Create a new ZF project in Zend Studio and name it as jiaRESTfulWS.
    2. Add autoloaderNamespaces[] = "Jia_" in application.ini to allow Zend Autoloader load Jia_* classes.
    3. Creating a action class DummyController under directory /application/controllers. 
    4. creating a function restAction() in DummyController .
    5. Creating a Jia_Hello class with sayHello($name) function under /library/Jia directory.
    It is done. You need to pay attention on how to specify web service URI in the code if you use different project name and function names. Or, you might want to add alias in your apache httpd configuration file to simplify the URL. On my machine, this demo RESTful WS can be accessed with following URL: http://localhost/jiaRESTfulWS/public/index.php/Dummy/rest?method=sayHello&name=jia . See key source code as below,

    Jia_Hello class
    /**
     * This class contains function which will be used by Web service caller.
     * All business logics will be implented or called in these functions.
     * 
     * @author Yiyu Jia
     *
     */
    class Jia_Hello {
    
     /**
      * 
      * @param string $name
      * @return string
      * 
      */
     public function sayHello($name){
      return "hello ".$name;
     }
    }
    
    

    DummyController class
    /**
     * This class includes one function restAction(), wich has Zend_Rest_Server initialized.
     * However, you can only use URI with "?" like this "/rest?method=sayHello&name=jia". You 
     * can not have URI like "/rest/name/jia"
     * 
     * @author yiyu
     *
     */
    class DummyController extends Zend_Controller_Action
    {
     /**
      *  action named as rest.
      */
     public function restAction() {
      
      // disable layouts and renderers
      $this->getHelper ( 'viewRenderer' )->setNoRender ( true );
      
      // initialize REST server
      $server = new Zend_Rest_Server();
      // set REST service class
      $server->setClass ( 'Jia_Hello' ); 
        
      // handle request
      $server->handle ();
     
     }
     
    }
    

    Zend Studio 7.2 project file can be downloaded here. Also, I do not recommend to use Zend_Rest_Server for developing RESTful WS as I think it is old and uncompleted class. Zend_Rest_Route should be a better choice to make RESTful Web Service in PHP. Here is a simple tutorial about how to use Zend_Rest_Route and Zend_Rest_Controller to create RESTful Web Service. Creating RESTful service with Zend_Rest_Route and Zend_Rest_Controller