Introduction to writing a REST server in PHP

This article is the second in my SOAP and REST API series, following on from my SOAP vs. REST API Implementation article and will fill in some more of the details around implementing a REST server in PHP.

This article is intended to give a basic introduction and a guide to push you in the right direction with your REST server implementation. As such, the examples used in this article are somewhat abstracted from real world uses. If there is demand for it I will write a much more in-depth “ultimate” REST server implementation article at a later date.

If you’re not familiar with the concept of REST, before we move on I’d suggest that you get up to speed with a bit of background reading. Some possible sources are:

Getting started
This should really go without saying but I’ll say it anyway. Before hitting the code to implement a REST server you should work out a few things about what you’re implementing:

  1. Make a list of ALL of your API methods.
  2. Work out which request methods (GET, POST, PUT and DELETE) the methods are used with – It is possible that they will be used with more than one request method.
  3. Work out your URL scheme for the API. What URL maps to what API method?

To keep things simple in this article we will be working with 4 methods. One for each request method listed above. Let’s call them:

  1. my_get
  2. my_post
  3. my_put
  4. my_delete

It is quite obvious which API method ties in with each request method so I won’t go into that. Each of the methods will be mapped to a URL of the same name. For example my_get will be mapped to http://www.mydomain.com/rest/my-get, my_post will be mapped to http://www.mydomain.com/rest/my-post and so forth.

Setting up the “server”
In a real world implementation I would suggest setting up a REST server class that handles all of the method/url mapping, request/response headers, data manipulation, errors etc. In fact, I’ve actually got such a class that is just about ready for release.

For this article I’m staying right away from any such class in order to keep the examples simple. So our REST server will look something like this:

<?php

function RESTServer() {
    // find the function/method to call
    $callback = NULL;
    if (preg_match('/rest\/([^\/]+)/', $_SERVER['REQUEST_URI'], $m)) {
        if (isset($GLOBALS['RESTmap'][$_SERVER['REQUEST_METHOD']][$m[1]])) {
            $callback = $GLOBALS['RESTmap'][$_SERVER['REQUEST_METHOD']][$m[1]];
        }
    }

    if (is_callable($callback)) {
        // get the request data
        $data = NULL;
        if ($_SERVER['REQUEST_METHOD'] == 'GET') {
            $data = $_GET;
        } else if ($tmp = file_get_contents('php://input')) {
            $data = json_decode($tmp);
        }

        // execute the function/method and return the results
        header("{$_SERVER['SERVER_PROTOCOL']} 200 OK");
        header('Content-Type: text/plain');
        print json_encode(call_user_func($callback, $data));
    } else {
        header("{$_SERVER['SERVER_PROTOCOL']} 404 Not Found");
        // print 404 page here
        exit;
    }
}

So there’s 3 main parts to this function. The first section checks if there’s a function for the current request method and URI in the map of functions. The second section gets the current request data and the third section executes the matching function/method.

I’ve made the executive decision that all data (both request and response) will be in JSON format because the encoding and decoding functions are readily available in PHP. The function above handles the encoding and decoding of data using json_encode and json_decode.

Plugging in our 4 functions
In the RESTServer function above, the code looks for the appropriate function/method to call in the RESTmap global variable. So to map the URLs we defined above to the appropriate functions we need to add them to this variable.

Note: this assumes you have already configured your web server to rewrite the URL’s appropriately. For more information on this see the examples in SOAP vs. REST API Implementation and URL rewriting with Apache and PHP.

Our 4 functions:

<?php

function my_get() { }
function my_post() { }
function my_put() { }
function my_delete() { }

And adding them to the RESTmap:

<?php

$GLOBALS['RESTmap'] = array();
$GLOBALS['RESTmap']['GET'] = array('my-get' => 'my_get');
$GLOBALS['RESTmap']['POST'] = array('my-post' => 'my_post');
$GLOBALS['RESTmap']['PUT'] = array('my-put' => 'my_post');
$GLOBALS['RESTmap']['DELETE'] = array('my-delete' => 'my_delete');

A few notes

  • The data for GET request method is handled differently. This is because data for the GET method will ALWAYS be sent through in the query string (e.g. tacked on to the end of the URL)
  • The PUT request method is generally disabled in Apache by default. If it is disabled for you, you will need to enable it either in the Apache configuration or in a .htaccess file (See SOAP vs. REST API Implementation).
  • You will notice that the my_put and my_post functions both map to the my-post URL. This is simply to show that you can have various request methods using the same URL.

Putting it all together
As I mentioned before, this is not necessarily the best way to go in a real world implementation. This article just shows the various components involved in setting up an API. Hopefully it will be useful to anyone needing somewhere to start.

If you thought this article was too simple, too complex, too long, too short or otherwise I would love to hear your thoughts. Please leave comments and feedback. If you’re interested in reading a more thorough implementation article please let me know. Also, as I mentioned above we will be releasing a REST server library some time in the future so keep an eye out for that.

  • Thanks for sharing your ideas and thoughts, i like your blog and bookmark this blog for further use thanks again.
  • Thanks for sharing such an informative post. Its really helpful to me..
  • Great informative post and i really likes your information, most of the peoples are likes your blog because its having the good knowledge. thanks for your good informative post
  • PHP is open source software. Every one can easy to download and run this program.I get it clear idea about your topic.
  • Varun123
    no comments
  • You made some good points there. I did a search on this topic and found most people will agree with your blog. Thanks
    hire web developers | hire a website developer
  • You got a really useful blog I have been here reading for about an hour. I am a newbie and your success is very much an inspiration for me. thanks a lot..
    Web Designer Riyadh | Riyadh website design company
  • There is an open source solution for exposing PHP class methods as RESTful api, called Luracacast Restler (http://luracast.com/products/r... Check it out
  • Nice article Michael, I believe it would be great contribution, if you provide complete download able RESTful example with of PHP.
  • Thanks for the article. Implementation information on rest is pretty limited so its great to see guides like this one that are clear and simple.
  • Brahma
    hi
  • Ahmadz
    Hello there... I wanted to say that this article was a little bit vague, I got an overview of REST and how to implement an API using the REST Way, but I can't ACTUALLY implement it.

    I'm really interested in reading a more thorough article and have a look on your interesting RESTServer Library.
  • i did a package look at http://develturk.com/2009/08/1...
  • Tim
    Great stuff Michael-- clearest info I've found on the issue.
    If you get a chance, I'd like to hear from you on the importance of the structure of the REST (eg. why have a single class for the services rather than having a meaningful directory structure with the functions broken out by directory).

    I'd love to see the class you're writing when that's done, too

    Thanks
  • Hi Graham,

    Thanks for your comments.

    I'm not sure I quite understand what your getting at exactly. At the point where the 404 is returned it is entirely possible that the resource, particularly for the specified request URI does not exist. Depending on how the URL rewriting is set up /not-a-valid-url might be rewritten to the script above but that does mean it exists in the RESTmap array which ultimately is responsible for determining what requests are valid.

    If in the example above a GET request was sent to the /my-delete URI I agree that a 405 should be returned. Due to the simplicity of my example and the lack of granularity in error checking it simply doesn't allow for it. A real world situation would obviously be much more complex and would make such considerations.
  • You can also check REST in Zend Framework.
  • Yes I might have been a bit too far but that's how far my understanding of REST goes (I look forward for more articles btw). According to the wikipedia link you gave, REST defines resources represented by a URL which can be accessed using different HTTP methods to do different actions. Having a different URL per action didn't seem very "RESTful". Good that it's cleared up.

    Oh and you might want to correct the "200 Not Found" that should be "404 Not Found" in your example, sorry for not having been more comprehensible about that earlier.
  • The "200 Not Found" which you meant to be 404 is not appropriate at that point in the code. A 404 indicates the resource is not found, but the resource exists; you just wrote it. It should be "405 Method Not Allowed" and must be accompanied by an Allow header indicating which methods are supported. In the case above, what you need is:
    header('HTTP/1.x 405 Method Not Allowed');
    header('Allow: GET, PUT, POST, DELETE');
    // print 405 page here
    exit;
  • Loïc,

    Thanks for your feedback.

    I had intentionally used different URLs to show the mapping of the different URLs to the functions. Although I wouldn't go so far as to say it is "the point of REST to have resources like http://example.org/mystuff and to be able to use all 4 methods" you do make a very valid point.

    As such, I have updated my post so I have updated my post so the my-post URL will now map to the my_post and my_put functions depending on the request method. The same thing could of course be done with the GET and DELETE methods.
  • 200 Not Found -> 404

    I'm not sure if you mentioned it but isn't the point of REST to have resources like http://example.org/mystuff and to be able to use all 4 methods (GET/POST/PUT/DELETE) on that unique resource? Your example shows an URL per method instead of a unique URL that can be accessed using all 4 methods. That's kinda misleading.
blog comments powered by Disqus