close
Gen X Design | Ian Selby Gen X Design | Ian Selby
Search
Create a REST API with PHP
Create

One of the latest (sort of) crazes sweeping the net is APIs, more specifically those that leverage REST. It’s really no surprise either, as consuming REST APIs is so incredibly easy… in any language. It’s also incredibly easy to create them as you essentially use nothing more than an HTTP spec that has existed for ages. One of the few things that I give Rails credit for is its well thought-out REST support, both for providing and consuming these APIs (as its been explained by all the Rails fanboys I work with).

Seriously, if you’ve never used REST, but you’ve ever had to work with (or worse, create) a SOAP API, or simply opened a WSDL and had your head explode, boy do I have good news for you!

So, What on Earth is REST? Why Should You Care?

Before we get into writing some code, I want to make sure everyone’s got a good understanding of what REST is and how its great for APIs. First, technically speaking, REST isn’t specific to just APIs, it’s more of a generic concept. However, obviously, for the sake of this article we’ll be talking about it in the context of an API. So, let’s look at the basic needs of an API and how REST addresses them.

Requests
All APIs need to accept requests. Typically, with a RESTful API, you’ll have a well-defined URL scheme. Let’s say you want to provide an API for users on your site (I know, I always use the “users” concept for my examples). Well, your URL structure would probably be something like, “api/users” and “api/users/[id]” depending on the type of operation being requested against your API. You also need to consider how you want to accept data. These days a lot of people are using JSON or XML, and I personally prefer JSON because it works well with JavaScript, and PHP has easy functionality for encoding and decoding it. If you wanted your API to be really robust, you could accept both by sniffing out the content-type of the request (i.e. application/json or application/xml), but it’s perfectly acceptable to restrict things to one content type. Heck, you could even use simple key/value pairs if you wanted.

The other piece of a request is what it’s actually meant to do, such as load, save, etc. Normally, you’d have to come up with some sort of architecture that defines what action the requester (consumer) desires, but REST simplifies that. By using HTTP request methods, or verbs, we don’t need to define anything. We can just use the GET, POST, PUT, and DELETE methods, and that covers every request we’d need. You can equate the verbs to your standard crud-style stuff: GET = load/retrieve, POST = create, PUT = update, DELETE = well, delete. It’s important to note that these verbs don’t directly translate to CRUD, but it is a good way to think about them. So, going back to the above URL examples, let’s take a look at what some possible requests could mean:

  • GET request to /api/users – List all users
  • GET request to /api/users/1 – List info for user with ID of 1
  • POST request to /api/users – Create a new user
  • PUT request to /api/users/1 – Update user with ID of 1
  • DELETE request to /api/users/1 – Delete user with ID of 1

As you hopefully see, REST has already taken care of a lot of the major headaches of creating your own API through some simple, well-understood standards and protocols, but there’s one other piece to a good API…

Responses
So, REST handles requests very easily, but it also makes generating responses easy. Similar to requests, there are two main components of a RESTful response: the response body, and a status code. The response body is pretty easy to deal with. Like requests, most responses in REST are usually either JSON or XML (perhaps just plain text in the case of POSTs, but we’ll cover that later). And, like requests, the consumer can specify the response type they’d like through another part of the HTTP request spec, “Accept”. If a consumer wishes to receive an XML response, they’d just send an Accept header as a part of their request saying as much (”Accept: application/xml”). Admittedly, this method isn’t as widely adopted (tho it should be), so you have can also use the concept of an extension in the URL. For example, /api/users.xml means the consumer wants XML as a response, similarly /api/users.json means JSON (same for things like /api/users/1.json/xml). Either way you choose (I say do both), you should pick a default response type as a lot of the time people wont’ even tell you what they want. Again, I’d say go with JSON. So, no Accept header or extension (i.e. /api/users) should not fail, it should just fail-over to the default response-type.

But what about errors and other important status messages associated with requests? Easy, use HTTP status codes! This is far and above one of my favorite things about creating RESTful APIs. By using HTTP status codes, you don’t need to come up with a error / success scheme for your API, it’s already done for you. For example, if a consumer POSTS to /api/users and you want to report back a successful creation, simply send a 201 status code (201 = Created). If it failed, send a 500 if it failed on your end (500 = Internal Server Error), or perhaps a 400 if they screwed up (400 = Bad request). Maybe they’re trying to POST against an API endpoint that doesn’t accept posts… send a 501 (Not implemented). Perhaps your MySQL server is down, so your API is temporarily borked… send a 503 (Service unavailable). Hopefully, you get the idea. If you’d like to read up a bit on status codes, check them out on wikipedia: List of HTTP Status Codes.

I’m hoping you see all the advantages you get by leveraging the concepts of REST for your APIs. It really is super-cool, and its a shame its not more widely talked about in the PHP community (at least as far as I can tell). I think this is likely due to the lack of good documentation on how to deal with requests that aren’t GET or POST, namely PUT and DELETE. Admittedly, it is a bit goofy dealing with these, but it certainly isn’t hard. I’m also sure some of the popular frameworks out there probably have some sort of REST implementation, but I’m not a huge framework fan (for a lot of reasons that I won’t get into), and it’s also good to know these things even if somebody’s already created the solution for you.

If you’re still not convinced that this is a useful API paradigm, take a look at what REST has done for Ruby on Rails. One of its major claims to fame is how easy it is to create APIs (through some sort of RoR voodoo, I’m sure), and rightly so. Granted I know very little about RoR, but the fanboys around the office have preached this point to me many times. But, I digress… let’s write some code!

Getting Started with REST and PHP

One last disclaimer: the code we’re about to go over is in no way intended to be used as an example of a robust solution. My main goal here is to show how to deal with the individual components of REST in PHP, and leave creating the final solution up to you.

So, let’s dig in! I think the best way to do something practical is to create a class that will provide all the utility functions we need to create a REST API. We’ll also create a small class for storing our data. You could also then take this, extend it, and apply it to your own needs. So, let’s stub some stuff out:

class RestUtils
{
	public static function processRequest()
	{

	}

	public static function sendResponse($status = 200, $body = '', $content_type = 'text/html')
	{

	}

	public static function getStatusCodeMessage($status)
	{
		// these could be stored in a .ini file and loaded
		// via parse_ini_file()... however, this will suffice
		// for an example
		$codes = Array(
		    100 => 'Continue',
		    101 => 'Switching Protocols',
		    200 => 'OK',
		    201 => 'Created',
		    202 => 'Accepted',
		    203 => 'Non-Authoritative Information',
		    204 => 'No Content',
		    205 => 'Reset Content',
		    206 => 'Partial Content',
		    300 => 'Multiple Choices',
		    301 => 'Moved Permanently',
		    302 => 'Found',
		    303 => 'See Other',
		    304 => 'Not Modified',
		    305 => 'Use Proxy',
		    306 => '(Unused)',
		    307 => 'Temporary Redirect',
		    400 => 'Bad Request',
		    401 => 'Unauthorized',
		    402 => 'Payment Required',
		    403 => 'Forbidden',
		    404 => 'Not Found',
		    405 => 'Method Not Allowed',
		    406 => 'Not Acceptable',
		    407 => 'Proxy Authentication Required',
		    408 => 'Request Timeout',
		    409 => 'Conflict',
		    410 => 'Gone',
		    411 => 'Length Required',
		    412 => 'Precondition Failed',
		    413 => 'Request Entity Too Large',
		    414 => 'Request-URI Too Long',
		    415 => 'Unsupported Media Type',
		    416 => 'Requested Range Not Satisfiable',
		    417 => 'Expectation Failed',
		    500 => 'Internal Server Error',
		    501 => 'Not Implemented',
		    502 => 'Bad Gateway',
		    503 => 'Service Unavailable',
		    504 => 'Gateway Timeout',
		    505 => 'HTTP Version Not Supported'
		);

		return (isset($codes[$status])) ? $codes[$status] : '';
	}
}

class RestRequest
{
	private $request_vars;
	private $data;
	private $http_accept;
	private $method;

	public function __construct()
	{
		$this->request_vars		= array();
		$this->data				= '';
		$this->http_accept		= (strpos($_SERVER['HTTP_ACCEPT'], 'json')) ? 'json' : 'xml';
		$this->method			= 'get';
	}

	public function setData($data)
	{
		$this->data = $data;
	}

	public function setMethod($method)
	{
		$this->method = $method;
	}

	public function setRequestVars($request_vars)
	{
		$this->request_vars = $request_vars;
	}

	public function getData()
	{
		return $this->data;
	}

	public function getMethod()
	{
		return $this->method;
	}

	public function getHttpAccept()
	{
		return $this->http_accept;
	}

	public function getRequestVars()
	{
		return $this->request_vars;
	}
}

OK, so what we’ve got is a simple class for storing some information about our request (RestRequest), and a class with some static functions we can use to deal with requests and responses. As you can see, we really only have two functions to write… which is the beauty of this whole thing! Right, let’s move on…

Processing the Request

Processing the request is pretty straight-forward, but this is where we can run into a few catches (namely with PUT and DELETE… mostly PUT). We’ll go over those in a moment, but let’s examine the RestRequest class a bit. If you’ll look at the constructor, you’ll see that we’re already interpreting the HTTP_ACCEPT header, and defaulting to JSON if none is provided. With that out of the way, we need only deal with the incoming data.

There are a few ways we could go about doing this, but let’s just assume that we’ll always get a key/value pair in our request: ‘data’ => actual data. Let’s also assume that the actual data will be JSON. As stated in my previous explanation of REST, you could look at the content-type of the request and deal with either JSON or XML, but let’s keep it simple for now. So, our process request function will end up looking something like this:

	public static function processRequest()
	{
		// get our verb
		$request_method = strtolower($_SERVER['REQUEST_METHOD']);
		$return_obj		= new RestRequest();
		// we'll store our data here
		$data			= array();

		switch ($request_method)
		{
			// gets are easy...
			case 'get':
				$data = $_GET;
				break;
			// so are posts
			case 'post':
				$data = $_POST;
				break;
			// here's the tricky bit...
			case 'put':
				// basically, we read a string from PHP's special input location,
				// and then parse it out into an array via parse_str... per the PHP docs:
				// Parses str  as if it were the query string passed via a URL and sets
				// variables in the current scope.
				parse_str(file_get_contents('php://input'), $put_vars);
				$data = $put_vars;
				break;
		}

		// store the method
		$return_obj->setMethod($request_method);

		// set the raw data, so we can access it if needed (there may be
		// other pieces to your requests)
		$return_obj->setRequestVars($data);

		if(isset($data['data']))
		{
			// translate the JSON to an Object for use however you want
			$return_obj->setData(json_decode($data['data']));
		}
		return $return_obj;
	}

Like I said, pretty straight-forward. However, a few things to note… First, you typically don’t accept data for DELETE requests, so we don’t have a case for them in the switch. Second, you’ll notice that we store both the request variables, and the parsed JSON data. This is useful as you may have other stuff as a part of your request (say an API key or something) that isn’t truly the data itself (like a new user’s name, email, etc.).

So, how would we use this? Let’s go back to the user example. Assuming you’ve routed your request to the correct controller for users, we could have some code like this:

$data = RestUtils::processRequest();

switch($data->getMethod)
{
	case 'get':
		// retrieve a list of users
		break;
	case 'post':
		$user = new User();
		$user->setFirstName($data->getData()->first_name);  // just for example, this should be done cleaner
		// and so on...
		$user->save();
		break;
	// etc, etc, etc...
}

Please don’t do this in a real app, this is just a quick-and-dirty example. You’d want to wrap this up in a nice control structure with everything abstracted properly, but this should help you get an idea of how to use this stuff. But I digress, let’s move on to sending a response.

Sending the Response

Now that we can interpret the request, let’s move on to sending the response. We already know that all we really need to do is send the correct status code, and maybe some body (if this were a GET request, for example), but there is an important catch to responses that have no body. Say somebody made a request against our sample user API for a user that doesn’t exist (i.e. api/user/123). The appropriate status code to send is a 404 in this case, but simply sending the status code in the headers isn’t enough. If you viewed that page in your web browser, you would get a blank screen. This is because Apache (or whatever your web server runs on) isn’t sending the status code, so there’s no status page. We’ll need to take this into account when we build out our function. Keeping all that in mind, here’s what the code should look like:

	public static function sendResponse($status = 200, $body = '', $content_type = 'text/html')
	{
		$status_header = 'HTTP/1.1 ' . $status . ' ' . RestUtils::getStatusCodeMessage($status);
		// set the status
		header($status_header);
		// set the content type
		header('Content-type: ' . $content_type);

		// pages with body are easy
		if($body != '')
		{
			// send the body
			echo $body;
			exit;
		}
		// we need to create the body if none is passed
		else
		{
			// create some body messages
			$message = '';

			// this is purely optional, but makes the pages a little nicer to read
			// for your users.  Since you won't likely send a lot of different status codes,
			// this also shouldn't be too ponderous to maintain
			switch($status)
			{
				case 401:
					$message = 'You must be authorized to view this page.';
					break;
				case 404:
					$message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';
					break;
				case 500:
					$message = 'The server encountered an error processing your request.';
					break;
				case 501:
					$message = 'The requested method is not implemented.';
					break;
			}

			// servers don't always have a signature turned on (this is an apache directive "ServerSignature On")
			$signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];

			// this should be templatized in a real-world solution
			$body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
						<html>
							<head>
								<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
								<title>' . $status . ' ' . RestUtils::getStatusCodeMessage($status) . '</title>
							</head>
							<body>
								<h1>' . RestUtils::getStatusCodeMessage($status) . '</h1>
								<p>' . $message . '</p>
								<hr />
								<address>' . $signature . '</address>
							</body>
						</html>';

			echo $body;
			exit;
		}
	}

That’s It! We technically have everything we need now to process requests and send responses. Let’s talk a bit more about why we need to have a standard body response or a custom one. For GET requests, this is pretty obvious, we need to send XML / JSON content instead of a status page (provided the request was valid). However, there’s also POSTs to deal with. Inside of your apps, when you create a new entity, you probably fetch the new entity’s ID via something like mysql_insert_id(). Well, if a user posts to your API, they’ll probably want that new ID as well. What I’ll usually do in this case is simply send the new ID as the body (with a 201 status code), but you could also wrap that in XML or JSON if you’d like.

So, let’s extend our sample implementation a bit:

switch($data->getMethod)
{
	// this is a request for all users, not one in particular
	case 'get':
		$user_list = getUserList(); // assume this returns an array

		if($data->getHttpAccept == 'json')
		{
			RestUtils::sendResponse(200, json_encode($user_list), 'application/json');
		}
		else if ($data->getHttpAccept == 'xml')
		{
			// using the XML_SERIALIZER Pear Package
			$options = array
			(
				'indent' => '     ',
				'addDecl' => false,
				'rootName' => $fc->getAction(),
				XML_SERIALIZER_OPTION_RETURN_RESULT => true
			);
			$serializer = new XML_Serializer($options);

			RestUtils::sendResponse(200, $serializer->serialize($user_list), 'application/xml');
		}

		break;
	// new user create
	case 'post':
		$user = new User();
		$user->setFirstName($data->getData()->first_name);  // just for example, this should be done cleaner
		// and so on...
		$user->save();

		// just send the new ID as the body
		RestUtils::sendResponse(201, $user->getId());
		break;
}

Again, this is just an example, but it does show off (I think, at least) how little effort it takes to implement RESTful stuff.

Wrapping Up

So, that’s about it. I’m pretty confident that I’ve beaten the point that this should be quite easy into the ground, so I’d like to close with how you can take this stuff further and perhaps properly implement it.

In a real-world MVC application, what you would probably want to do is set up a controller for your API that loads individual API controllers. For example, using the above stuff, we’d possibly create a UserRestController which had four methods: get(), put(), post(), and delete(). The API controller would look at the request and determine which method to invoke on that controller. That method would then use the utils to process the request, do what it needs to do data-wise, then use the utils to send a response.

You could also take it a step further than that, and abstract out your API controller and data models a bit more. Rather than explicitly creating a controller for every data model in your app, you could add some logic into your API controller to first look for an explicitly defined controller, and if none is found, try to look for an existing model. For example, the url “api/user/1″, would first trigger a lookup for a “user” rest controller. If none is found, it could then look for a model called “user” in your app. If one is found, you could write up a bit of automated voodoo to automatically process all the requests against those models.

Going even further, you could then make a generic “list-all” method that works similar to the previous paragraph’s example. Say your url was “api/users”. The API controller could first check for a “users” rest controller, and if none was found, recognize that users is pluaralized, depluralize it, and then look for a “user” model. If one’s found, load a list the list of users and send that off.

Finally, you could add digest authentication to your API quite easily as well. Say you only wanted properly authenticated users to access your API, well, you could throw some code like this into your process request functionality (borrowed from an existing app of mine, so there’s some constants and variables referenced that aren’t defined in this snippet):

			// figure out if we need to challenge the user
			if(empty($_SERVER['PHP_AUTH_DIGEST']))
			{
				header('HTTP/1.1 401 Unauthorized');
				header('WWW-Authenticate: Digest realm="' . AUTH_REALM . '",qop="auth",nonce="' . uniqid() . '",opaque="' . md5(AUTH_REALM) . '"');

				// show the error if they hit cancel
				die(RestControllerLib::error(401, true));
			}

			// now, analayze the PHP_AUTH_DIGEST var
			if(!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || $auth_username != $data['username'])
			{
				// show the error due to bad auth
				die(RestUtils::sendResponse(401));
			}

			// so far, everything's good, let's now check the response a bit more...
			$A1 = md5($data['username'] . ':' . AUTH_REALM . ':' . $auth_pass);
			$A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
			$valid_response = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);

			// last check..
			if($data['response'] != $valid_response)
			{
				die(RestUtils::sendResponse(401));
			}

Pretty cool stuff, huh? With a little bit of code and some clever logic, you can add a fully functional REST API to your apps very quickly. I’m not just saying that to cheerlead the concept either, I implemented this stuff into one of my personal frameworks in about half a day, and then spent another half day adding all sorts of cool magic to it. If you (the reader) are interested in seeing my final implementation, drop me a note in the comments and I’d be happy to share it with you! Also, if you’ve got any cool ideas you’d like to share, be sure to drop those in the comments as well… if I like it enough, I’d even let you guest author your own article on the subject!

Until next time…

UPDATE: The much-requested follow-up to this article has been posted: Making RESTful Requests in PHP

arrow127 Comments

  1. 73 mos, 2 wks ago

    …and how do i make PUT and DELETE request ?

  2. PierralF
    73 mos, 2 wks ago

    really great stuff

  3. 73 mos, 2 wks ago

    That, my friend, is the substance of my next article :)

  4. 73 mos, 2 wks ago

    Great overview on how to get REST going in PHP. Very thorough. For folks looking on some other tips (perhaps an abbreviated answer to the teaser of PUT / DELETE) I’ve got an article on REST PHP tips.

    I’ve also been working on a free php framework called Recess (play on words with Rest) that is built around HTTP and REST and simplifies some of the challenges of doing REST in PHP manually (like routing, PUTs, etc.)

    Overall one of the best articles on implementing REST in PHP I’ve seen on the net. Great work Ian!

  5. 73 mos, 2 wks ago

    Thank you sir, as usual, for your kind words. Took a look at your framework last time you commented, but it wasn’t available for download. I’m gonna check it out, and be sure to let you know what I think.

  6. PierralF
    73 mos, 2 wks ago

    i’ll wait for your next article, this one has really tempted me

  7. Ignace
    73 mos, 1 wk ago

    case ‘delete’:
    $deleteContents = file_get_contents
    parse_str($deleteContents, $_DELETE);
    break;

  8. 73 mos, 1 wk ago

    You could do this, but technically speaking DELETE requests shouldn’t have any parameters. In any event, if your API allows for that then, yes, you can process them the same way you process PUTs

  9. 73 mos, 1 wk ago

    Congratulations on writing the first article on REST without the words “Roy Fielding” in it! Seriously, well done!

  10. 73 mos, 1 wk ago

    Thanks :)

  11. Tom
    73 mos, 1 wk ago

    I believe your ‘api’ resource URI namespace is more RPC than REST, and is untrue to the idea of resources, so you’re telling me something like:
    “GET /users/1″ and “GET /api/users/1″ are the same thing, except the API namespace returns JSON or XML or whatever representation (it’s unclear by the URI)? I fear that you’re unintentionally misleading your readers, as the topic of resources and representations has been left entirely out of this post. A resource is represented by a URI, and it’s representation is determined by it’s extension (or, should be). A more correct scenario would be:
    GET /users/1.json
    POST /users.json

    I think the rest (no pun intended) is fairly obvious.

  12. 73 mos, 1 wk ago

    Tom, you make a good point, but I do want to point out that I mentioned you could use extensions. That being said, there’s a lot of validity to what you say, and I think it’s important to consider. I just didn’t want to make any stern assertions one way or another about how things should be implemented as there’s unfortunately no standard way to do so on the web as it is. I like your approach the best, however, and long story short think you’re right :) Thanks for the tip!

  13. 73 mos ago

    Really great stuff, can anybody pass me a any article link which have basic learning of REST with example.

  14. 73 mos ago

    Thanks for a fantastic post. I’ve been considering creating a REST API and I think I’ll be referencing this quite a bit going forward.

    Also, I learnt a few other neat tricks whilst reading it.

    Thanks again!

  15. 73 mos ago

    No problem, glad you found it helpful

  16. 72 mos, 4 wks ago

    Hello, This is THE best process I have ever seen.
    I’m actually looking for something like this to bridge from PHP to ASP.Net and I think i can do it now.
    But God knows, why I havent used PHP till date… , and how to depoly the above files? Can you please show me a resouce of how to use these files…?
    Should i install some kind of REST or something on my IIS…. ?
    Or can i simply put the above in php files and to run them?

    Please help me, i cant wait from using the above example.

  17. 72 mos, 4 wks ago

    Excellent, excellent post. I’ve just completed a first draft of the Zoopy RESTful API using Zend Framework. Saddens me that most PHP frameworks don’t even consider REST: ZF has the contextSwitch() helper to display output in different formats but traditional routers don’t work RESTfully because they route based on URL only and not on URL + request method.

  18. 72 mos, 4 wks ago

    Well, I don’t know that I can really teach you PHP, or help you out with your situation. As I stated several times in the article, you wouldn’t want to use this simplified implementation for any production stuff. I’d say the best thing to do is start getting your hands dirty with PHP and go from there :)

  19. 72 mos, 2 wks ago

    Loved it. Please, please show me your final implementation :)

  20. loKi
    72 mos, 2 wks ago

    Hey there..

    liked this one! It’s really a good start if you dont’t know what the heck REST is.
    But the part on authentication is a bit hard to understand..

  21. 72 mos, 1 wk ago

    the last code example has: emptyempty instead of just empty

  22. Evan
    72 mos, 1 wk ago

    Thanks so much for this! I just started tackling the question issue of building an API, and this really helped put things in perspective.

  23. 72 mos, 1 wk ago

    Where do I have to put the to put the before last and the last snippet in order to get everything working? Ian could’nt you provide a downloadable full working example of that article? Would be great =)

  24. 72 mos, 1 wk ago

    PoNx, I’m not quite sure I understand your question… Basically, however, all you need to do is take the class shell created in the first snippet and fill in all the functions that are completed throughout the course of the article to get a full working sample.

  25. Philipp
    72 mos ago

    great tutorial, thanks.

    We’re implementing a RESTful API using a lot of your input, but for one problem we have not found a good solution:

    For a call like /users/[userid] how do you map all your requests, that obviously all come to a different URI since the userid is part of the URI, to a starting point for that ressource?
    What we did is a apache rewrite rule, that sends /users/* to /users/index.php. But that is a solution I don’t like very much…

  26. Kris P
    72 mos ago

    Great Article, thanks for sharing.
    Currently I’m working on my own “pseudo” framework, and I’ve literally lost my nerves during soap api implementation. I came across REST while ago, but I’ve figured out
    it may be great for my project instead of constantly fighting with soap or xml-rpc.
    Do you mind sharing your actual implementation with me? it will save me a lot of time ;]

  27. 71 mos, 3 wks ago

    I’m hoping to soon follow this article up with a more real-world implementation, so that should hopefully help you out :)

  28. 71 mos, 3 wks ago

    Looks like a really good roundup on REST.

    Just one thing I am curious about is your direct mapping of POST to Create and PUT to Update. Some would say that PUT should be used whenever the entirety of a resource is being uploaded, regardless of if this is an Update of a Create. From an API point of view this would probably put more onus on the client to consider what it is that they are submitting, and use the right method. What do you think of this?

  29. 71 mos, 3 wks ago

    Well, according to the HTTP spec, that’s correct. However, your assertion is correct in that using PUT per the spec is generally more confusing for both the API developer and the actual consumers. I’m pretty sure that’s why it’s become a generally acceptable standard to map the verbs to particular actions instead… sometimes convention is better than following a spec to a T :)

    My thoughts are to do whatever you feel is right, but I personally stick to doing things the way I outlined them in this article, as that’s the most commonly used set of rules in practice.

  30. 71 mos, 2 wks ago

    Nice article!. Once you have your REST API, you can offer it in a nice way connecting it with the 3scale system. there are PHP plugins in here: http://cli.gs/XEau5h
    , and once connected, it will automatically add signup, analytics and other cool features.

  31. stephen
    71 mos, 2 wks ago

    hi ian, thanks for the article, i also dislike heavyweight frameworks and end up writing the pieces that i require on my own. was curious as to how you parse the incoming url requests, you must use apache mod_rewrite to accomplish this, can you disclose part?

  32. 71 mos ago

    Nice article.
    Really helpful. When you are writing more on it?

  33. 71 mos ago

    any news on the next article?

  34. 71 mos ago

    Very soon, I hope. I’ve recently changed jobs, so life’s been a bit hectic. However, everything’s calming down for me, and I should have time to get some writing done.

  35. Sruthi
    70 mos, 2 wks ago

    Hi Lan

    Thank for sharing this code with us. It is really useful and I am going to try your code. Can contact you for further help through mail? If you mind could you accept this request?

    Sruthi

  36. 70 mos, 2 wks ago

    I appreciate your thanks, but I really don’t have time to help out with anything more than general questions. Feel free to post them in the comments and either myself or another member of the community will try and help you out.

  37. 70 mos, 2 wks ago

    Hi..
    I’ve been searching for the example code to build rest api from scratch. Only at your site I find it. You give me the solution and inspiration how to code rest api.
    thanks Ian.

  38. anchoito
    70 mos, 1 wk ago

    Thanks you! It was really good to have an example php code about REST. I was looking for something about this and there´s nothing in the web. If you could share the final implementation with my, it makes my happy. Thanks!

  39. Hasan
    69 mos, 3 wks ago

    Hello Ian,

    thanks for the wonderful tutorial. But I am rather new to PHP. Can you share the final implementation with me? IT would make me really happy to have a small startup, where I can get a lot of hints of how to create a REST API in PHP. Probably the RewriteRules for the Apache will help, or do you solved it an another way?

  40. 69 mos, 2 wks ago

    Hiya Ian,
    I would love to see your implementation of this article. Any chance you could share that with us? Great work here btw!

  41. 69 mos, 1 wk ago

    Ian, great write up! I have been trying to wrap my mind around implementing a new API, and this was perfect! Thank you for sharing!
    Brandon

  42. 68 mos, 4 wks ago

    Great article.
    Please share your implementation :)

  43. 68 mos, 3 wks ago

    Great article indeed! After searching through many articles, this is the best I’ve found. Thanks

  44. 68 mos, 3 wks ago

    What text editor are you using? Looks pretty schwippy…

  45. Vdvm
    68 mos, 3 wks ago

    Like it!

    Please share :)

  46. 68 mos, 3 wks ago

    I develop in either Aptana or TextMate depending on my mood or what I’m doing. Of course, I’ve applied custom color schemes to Aptana, since I’m not a huge fan of the ones they ship :)

  47. 68 mos, 3 wks ago

    This is what I did in a .htaccess-file to route the requests to the right script:

    RewriteEngine on
    RewriteBase /

    RewriteRule ^service\.php – [L]
    RewriteRule ^service/ service.php [L]

    e.g. one can request http://ws.meneon.com/service/customer1 (not active yet) and then my service.php does all the rest (validate, authenticate, send response, etc.

  48. mitaj
    68 mos, 2 wks ago

    After searching the net your post has proven to be the most comprehensive and useful indeed. Thanks!

    P.S. The array with all the response codes is very handy :P

  49. mitja
    68 mos, 2 wks ago

    By the way, is there really any penalty for not using query strings? I see Christof suggesting an .htaccess file rule but once you start adding more resources, i.e. service, users, article, and what have you, that means constant maintenance, changes to the file, and of course the extra Apache overhead.

    What I’ve done with my API at work is I simply catch the $_SERVER["PATH_INFO"] variable, and that way I don’t have to bother touching the .htaccess ever again — all I do is set up 3 mod_rewrite rules for rewriting something like http://site.com/index.php/users/4 to http://site.com/users/4 as such:
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]

    Then explode the PATH_INFO string using a slash as a delimeter, pop off the first empty array entry, and off I go. You can even set up functions named after verbs, and do function ‘mapping’. Assuming you don’t trust your users and take preventative measures I think that’s a much better way of going about it.

  50. arindam ganguly
    68 mos, 1 wk ago

    following christof and mitja,

    am i right when i say, christof would have independent pages like service.php, users.php to handle the different possible actions based on the url?

    while mitja, would have only one page index.php that would handle all possible request actions through some type of switch case method??

    tks

  51. iDVB
    67 mos, 1 wk ago

    Great post! I found it very useful in clarifying a number of things regarding REST that were plaguing me. However, I think there is one last one that it does not address that maybe someone can help with….
    the line:
    $user->setFirstName($data->getData()->first_name);
    Does not take into consideration that “first_name may not exist”….Eg. how to protect the server against users sending junk args to the server?
    My REST_controller is functioning as the interface between the requests and the Model however, right now I’m iterating thru each arg making sure that depending on the model->method being called it makes sure that the given args are valid and there are not extra (junk) args. I almost wish there was a function like method_exists() called method_with_args_exists().
    This is an issue that has been plaguing me…can anyone provide maybe an example?

  52. Jason
    66 mos, 4 wks ago

    Good article. Helped me get a nice intro to REST design with a fundamental implementation. May I request a copy of the API source code?

  53. Drew
    66 mos, 3 wks ago

    How do i create controllers?
    Maybe i should look there first ;-)

  54. 66 mos, 1 wk ago

    Fantastic post.

  55. abhishek
    66 mos, 1 wk ago

    what kind of json or xml response we have to send to user?
    i want to know the format of response for REST.

  56. abhishek
    66 mos, 1 wk ago

    please provide exact sequence of code or sample code, as where to write which code?

  57. 65 mos, 3 wks ago

    This is alittle messy you should tell them where to put what code and if they need to create new files etc etc. I know you just show them code exampels but they will never learn anything if they dont see and example of how this would look like.

  58. 65 mos, 1 wk ago

    I’ve found people don’t learn when I put complete code examples together… they merely copy and paste. Also, it would be far messier to put together a complete app as an example, and potentially misleading. As these concepts could be integrated into any number of apps and frameworks in any number of ways, I’ve chosen to go the route of explaining the key concepts and let the reader choose how they ultimately implement THEIR solutions. My intention here is not to provide complete solutions, it is to educate.

  59. reader
    65 mos, 1 wk ago

    Would be nice to have a printable version of the entire article and not just inside the code boxes, with tend to hamper reading of the code.

    That said. Thanks for the article; would not mind if there was an expansion( more advanced) on this articles.

  60. pedro
    65 mos ago

    hello… I want the complete implementation… please!

  61. Avi
    65 mos ago

    > First, you typically don’t accept data for DELETE requests, so we don’t have a case for them in the switch.
    Why not?
    After all, you are deleting a certain record, so it would make sense to accept at least a record_id.

  62. Avi
    65 mos ago

    BTW… very good article – both parts of it.
    Thanks!

  63. 64 mos, 3 wks ago

    Hi Ian, thanks for this, it is exactly one of the things I am working on right now. I would love to take a look at your final implementation if it is still on offer!

  64. Dim
    64 mos, 2 wks ago

    Hi Yan, thank for this post, it was really helpful!

    Just wanted to ask smth. You suppose some JSON data could be transfered with request, so the Content-Type would be “application/jsonrequest” instead of “application/jsonrequest”? But PHP $_PUT var doesn’t content anything in this case… Do I miss the concept or I should read directly from the stream as for PUT in this case?

    Thank a lot again!

  65. 64 mos, 2 wks ago

    Great article, thanks. I’m trying to make this work but I’m using php 5.2.11 and suspect it does not like the “$data = RestUtils::processRequest();” construct.
    I know its nothing to do with REST and everything to do with my knowledge of php, just curious if anyone else has a quick fix before I bury myself id documentation to work out the alternatives

  66. 64 mos, 2 wks ago

    @Avi, This is because the record ID would be a part of the resource – or the url. For example, you wouldn’t make a DELETE request against “foo.com/api/users” to delete a user, you’d make it against “foo.com/api/users/123″ where 123 was the record ID. Obviously the URL can be structured however you want, but the big point of REST is to make your URLs more or less resource maps.

  67. Dim
    64 mos, 1 wk ago

    Do you know Is there any good tutorial about auth for RESTful services? How to arrange a public-key encryption in the way Amazon does, for example? Or any other way of doing it (basic, digest, etc..) Thanks!

  68. Nizzy
    64 mos ago

    Hi Ian,

    I liked your post and I like to see how you extend this class onto other classes.

    Could you please share your implementation with me?

    thanks
    Nizzy

  69. 63 mos, 1 wk ago

    I read the half and it is good. wish to read it fully later

  70. David
    63 mos, 1 wk ago

    I wasn’t able to send a simple “get” response. Please help. Great article for learning rest api with PHP.

    class Restutils
    //etc
    class RestRequest
    //etc
    $data = RestUtils::processRequest();
    switch($data->getMethod)
    {
    case ‘get’:
    $user_list = “test response”;
    RestUtils::sendResponse(200,json_encode($user_list),’application/json’);
    break;
    case ‘post’;
    //etc
    }

    On the request side:
    class RestRequest
    //etc
    $request = new RestRequest(’http://localhost/api/index.php’, ‘GET’);
    $request->execute();
    echo ” . print_r($request, true) . ”;

    on the response in the browser:
    [responseBody:protected] => (It’s empty, I was expecting “testing response”.)
    [content_type] => text/html; charset=UTF8 (I was expecting “application/json”.)
    [http_code] => 200

    Happy holidays!

  71. 63 mos, 1 wk ago

    awsome share man!
    i’ve been wondering how to make my java apps communicate with my web apps and this is definately the way forward. this is a wonderful starting app and really useful
    this has helped a great deal thank you

  72. Jon
    62 mos, 1 wk ago

    This is the best article I have read on REST APIs and it helped a lot. I was wondering if I could get a copy of the final implementation?

  73. 62 mos, 1 wk ago

    Not only is this very informative, but so thorough…seriously, nobody is posting big posts like this one..so thanks. And your info will wind up being a catalyst for me. I too would like the implementation you mentioned. Thanks again for the great post!

  74. 62 mos, 1 wk ago

    I’ve read several articles about REST in net and I found it’s one of the best article among them. Good Work!

  75. JimboZ
    62 mos ago

    Fantastic article mate. I searched the net for ages with utter rubbish until I came across this. One thing though isn’t it defaulting to XML at the line:

    $this->http_accept = (strpos($_SERVER['HTTP_ACCEPT'], ‘json’)) ? ‘json’ : ‘xml’;

    and not JSON? Or am I missing something simple?

    Thanks for the help mate just this bit is confusing me.

  76. Edwin
    61 mos, 4 wks ago

    Great article, I’d like to see your personal framework with this. Can you share please?

  77. adam
    61 mos, 1 wk ago

    hey ian, great article. you stated i could request the full implementation from you, so…. could i get a copy of your full implementation so i can bridge the gaps? thanks!

  78. Jorge
    61 mos, 1 wk ago

    Great job! This post is very usefull for me, so thank you ver much.

    Can I see your final implementation, I’m really interested in it.

    Bye!

  79. km
    61 mos ago

    get/post were not any new… we only need to see put/delete

  80. Drew
    60 mos, 3 wks ago

    Really enjoyed your article. Keep up the good work.

    Cheers

  81. 60 mos, 2 wks ago

    Nice article, i’m looking for PHP REST article and find this site..really helps..

  82. Mickey
    60 mos, 2 wks ago

    very good article. please show me your final implementation, too.

  83. 60 mos, 1 wk ago

    thank you a lot, really great article.. i’ve learned rest on this site ;)

  84. 59 mos, 3 wks ago

    Ian, Would you mind sharing your final implementation? I’m almost getting it, but not quite. Thanks.

  85. kazey
    59 mos, 2 wks ago

    Hi,
    Great article, thanks for sharing. I would love to see your final implementation. Do you mind sending it to me via email?

    Thanks ahead.

  86. 59 mos ago

    This is the best resource on the subject I have found – I too would really like to take a peak at your implementation.

  87. James
    58 mos, 4 wks ago

    Hiya, I was wondering how I return data/information from the server to the requesting script instead of printing the array out?

    Many thanks

    James.

  88. 58 mos, 3 wks ago

    Hey, Nice post! Thanks for Sharing your thoughts. Please Drop me à Mail with your Final Version, like to See the Magic you are Talking about
    cheers, nils

  89. 58 mos, 2 wks ago

    thanks. really useful.

  90. 58 mos, 2 wks ago

    Hey Ian!

    You really do create impressive blog articles, Sir. I laugh every time I search for something I really need and you are the number one hit on the search results. This time my keywords were “PHP restful API” and you were numero uno, and with good reason.

    So, I am working on PHP API project right now as a matter of fact, and could very much use the headstart/insight I would gain from your example if you could send me a copy of the full implementation. Since I am familiar with and implicitly trust your coding style from past shared experiences, I think it would be a great starting place for me to have a look at how you went after doing this.

    Folks, if you are reading Ian’s tut’s, you are certainly in the right place for some expert advice. I’ve personally worked with him and his understanding of programming is excellent, as well as the clarity of his coding style and his teaching style. Good work my friend, and to everyone else, you should bookmark this site. You’ll be smarter for it!

  91. 58 mos, 1 wk ago

    Hi, I just scanned your article, I am trying to understand how I can use REST on my apache server. I am curious to see how you set everything up. Do you have anything on that subject to share?

    Dick

  92. Alex
    58 mos ago

    Great article,

    Will you please little bit explain how to use server by write code for client.

    Thanks.

  93. 58 mos ago

    Hey Ian,

    You rock dude. I think I get it now. I’m curious as to what framework(s) you use. If CI or Kohana, check out http://dev.kohanaframework.org/projects/restful

    Oh hey, I’m friends with Phil Harrington too. Keep blogging!!

  94. Kenneth
    57 mos, 3 wks ago

    very good one. I was looking for a article like this.

  95. Vishnu
    57 mos, 2 wks ago

    Really cool article.. I’d like to see your personal framework with this. Can you share please?

  96. Larry
    57 mos, 1 wk ago

    No any touch with REST before, just use SOAP sometimes, begin to learn it. Not understand: Why REST sometimes be compared with SOAP, and sometimes be compared with MVC? However, I never think any close relationship between SOAP and MVC. I am new comer, could give some indication for this question?

  97. Rob Scott
    57 mos ago

    Excellent article! I’ve tried pointing people at the Fielding dissertation to get a grip on the REST concept but they just can’t get through it. Your article really gets them in quickly to the content they don’t know.

    I agree with you on not supplying complete examples. No thinking means no learning.

  98. arka
    56 mos, 3 wks ago

    Ian, Thanks for the posts…

    I’ve got the server and client running, and can make a call to the api, the only problem I’m having is figuring out where to put my custom functions for data, where/how to send parameters to request data from the api, and where the string/content is being sent back. If you could share your finished implementation or provide some direction it would be much appreciated.

  99. Hardik
    56 mos, 1 wk ago

    Thanks a lot for this article. Its really very informative documentation.

  100. Andreas
    56 mos, 1 wk ago

    This is still the only good PHP REST tutorial online (what I’ve found anyway). I would very much appreciate to have a look on your implementation. Thanks.

  101. 56 mos, 1 wk ago

    This is great. I’d love to see your implementation, if possible. I’m struggling with mine. Could you send it to me?

  102. 56 mos ago

    Thanks! You are a champ.

  103. nishanth
    55 mos, 2 wks ago

    Great…………

  104. 55 mos, 1 wk ago

    Hey Ian,
    Great article…. and I like your tutorial technique. In fact, one day, when I finally grow up, I’ll teach my readers just like you, lol.

    Anyway, following up on your “If you (the reader) are interested in seeing my final implementation…” statement, I am indeed very interested in seeing it.

    CHEERS!

  105. 55 mos, 1 wk ago

    Hi Lan.
    Thank you very much for such an useful article, after reading it I was full of ideas and solutions for my first RESTful API implementation, but after days I have some new ideas in my own that absent in this article and I’m not sure about their trueness, I really want to take a look at your own production implementation of the RESTful API, that you mentioned at the end of the article.
    Please drop me a line or codes to email when you have a minute.

    Thank you again.

  106. Mohsen
    54 mos, 1 wk ago

    Please @lan, Share your framework with us, if u don’t mind :)

    This article is amazing thank you very mush for shearing this tut with us

  107. 54 mos, 1 wk ago

    I’d love to see the framework too, mail is appreciated :)

  108. Chris
    53 mos, 4 wks ago

    I have read your article through 3 times now, and although I understand all the concepts and individual components, I am struggling to pull together a working example.

    I dont know if its my htaccess, process request, or instantiation of the class that is letting me down, but I would really appreciate you or someone posting a full working example of this. Maybe its just the fact I have been up coding for 16 hours and my brain is a bit fried :P

    I know you say you find people dont learn if you give it to them on a plate, and I appreciate that, but people also dont learn if they cant get a working environment in order to progress and experiment. Please help!!

    I have even looked at Kris Jordans recess framework, but to be honest thats just too huge and complex, and I only want to try and create a small barebones environment for me to get to grips with and learn :(

  109. 53 mos, 2 wks ago

    Hi, am looking to create a api to call my online backup server, please could someone help me £££

    support@123-backup.com

  110. 53 mos ago

    Great post, thanks for the help. I like your method, TEACH, it makes one think. I am looking forward to future posts.

  111. Gule
    52 mos, 4 wks ago

    Perfect

  112. 52 mos, 3 wks ago

    Good information!

  113. 52 mos, 3 wks ago

    Things look like they are picking up in your area. . I’m currently working on Fishbone Diagram project.

  114. 52 mos, 2 wks ago

    Very good Article! simple and clear, goes directly into the argument without too much “code philosophy”… :-)

  115. Lalit
    52 mos ago

    Hi Ian,

    I am very much interested in seeing your final implementation. Can you please send it to me?

    -Lalit

  116. 51 mos, 4 wks ago

    Bravo! Between this as a starting point and http://gluephp.com/ … you can’t miss.

  117. 51 mos, 2 wks ago

    Nice article, thanks for your thoughts.

  118. 50 mos, 3 wks ago

    VERY good article. Did you ever do the follow up?

    So how would you do BULK operations? Specifically the URL?
    BULK operations like :
    10,000 POSTS (Create entities)
    10,000 DELETES (based on a parameter or a list of IDs)
    10,000 UPDATES (use the whole entity, or just he values needing changes?)

    Take this into account?

    collection:
    http://sub.domain.tld/entity.format
    POST to create new entity in collection
    GET to search collection
    PUT replace the entire collection with another one?
    DELETE delete the entire collection?

    member
    http://sub.domain.tld/entity/id.format
    POST treats this as ’sub’collection and ceates entity in it
    GET get the entity
    PUT replace the entity with a new one
    DELETE delete the entity

  119. 50 mos, 2 wks ago

    Using GET REST to google customsearch, it’s ok?

  120. Subathra
    50 mos, 2 wks ago

    Great article Ian! Thanks for sharing. I would love to take a peek at your final implementation as well if you don’t mind?

    Thanks,
    Subathra

  121. 50 mos, 1 wk ago

    Great tutorial. Thanks!

    I’d appreciate seeing the full implementation.

  122. 49 mos, 3 wks ago

    Awesome article , thanks :)

  123. pankaj
    49 mos, 3 wks ago

    How to implement the REST API for CLI (command line interface ) based client.

    Here is my case: My clients are written in c/perl they run on command line. now they wil send me the PUT request through REST http request to my APi server.
    How we can send xml request (WSDL request kind) from PUT call/

  124. pankaj
    49 mos, 3 wks ago

    How to implement the REST API for CLI (command line interface ) based client.

    Here is my case: My clients are written in c/perl they run on command line. now they wil send me the PUT request through REST http request to my APi server.
    How we can send xml request (WSDL request kind) from PUT call.

    Thanks,
    Pankaj

  125. 49 mos, 3 wks ago

    Great Work dude, I am going to create my own API now. I love this tutorial. Save my day.

  126. 48 mos, 4 wks ago

    Very informative and interesting. Tour article will be of great help in rolling out a RESTfull architecture for my web services.

  127. Dan
    48 mos, 2 wks ago

    Excellent article!

Leave A Comment