{"id":91,"date":"2010-02-13T18:45:39","date_gmt":"2010-02-13T17:45:39","guid":{"rendered":"http:\/\/www.speich.net\/articles\/?p=91"},"modified":"2010-02-13T18:45:39","modified_gmt":"2010-02-13T17:45:39","slug":"tutorial-part1-rest-with-dojo-and-php","status":"publish","type":"post","link":"https:\/\/www.speich.net\/articles\/en\/2010\/02\/13\/tutorial-part1-rest-with-dojo-and-php\/","title":{"rendered":"Tutorial Part 1: REST with Dojo and PHP"},"content":{"rendered":"<p>I only started recently to dig into REST, so I&#8217;m in no way an expert in this field. There are not that many tutorials on the internet, and the ones I found were only of limited help. They all seemed to miss something or, rather, I missed something. So I decided to write my own tutorial about my findings to help others that might have the same problems. On the client side, I&#8217;ll use the <a href=\"http:\/\/www.dojotoolkit.org\">Dojo Toolkit<\/a>, on the server side, PHP.<\/p>\n<p>I will focus mainly on providing and explaining some working code examples including server PHP code. At the end of this article you can find all code as a downloadable zip-file. As an introduction to REST, read some of the <a href=\"#tutorials\">tutorials<\/a> linked at the end of this article, because I&#8217;m not going to repeat some of the things you can read there.<\/p>\n<ul>\n<li>Jump directly to the first demo: <a href=\"\/articles\/php-rest-check.php\">Check availability of HTTP request methods<\/a><\/li>\n<li>Jump directly to the second demo: <a href=\"\/articles\/dojo-jsonreststore.php\">Lazy load, update, create and delete dijit tree items<\/a><\/li>\n<\/ul>\n<h2><!--more-->1. Url-confusion<\/h2>\n<p>What confused me the most at the beginning was the structure of the REST urls, for example in the article <a href=\"http:\/\/www.gen-x-design.com\/archives\/create-a-rest-api-with-php\/\">Create a REST API with PHP<\/a>. How on earth can an url be structured like:<\/p>\n<pre><strong>PUT request to \/api\/users\/1<\/strong> \u2013 Update user with ID of 1<\/pre>\n<p>Where&#8217;s the PHP page in this url that receives this request? And second, I always thought variables had to be posted with a querystring. It took me a while to figure out that the path in the url does not necessarily have to end with a filename such as mypage.php and that in this example it is simply omitted. Furthermore, \/api\/users\/1 is not a sort of variable, but just part of the path to the resource. To make this clear, just add a PHP filename in front of the resource&#8230;<\/p>\n<pre><strong>mypage.php\/api\/users\/1<\/strong><\/pre>\n<p>&#8230; and then you can process the request on the page mypage.php with:<\/p>\n<pre class=\"prettyprint lang-php\">$resource = $_SERVER['PATH_INFO'];\n$method   = $_SERVER['REQUEST_METHOD'];<\/pre>\n<p>Where the variable $resource would contain:<\/p>\n<pre class=\"brush:php\">\/api\/users\/1<\/pre>\n<p>and $method would contain:<\/p>\n<pre class=\"brush:php\">PUT<\/pre>\n<p>To extract additional variable data from the request body or request header you can use parse_string() and file_get_contents() or $_GET.<\/p>\n<pre class=\"prettyprint lang-php\">if ($method == 'POST' || $method == 'PUT') {\n  parse_str(file_get_contents('php:\/\/input'), $_DATA);\n}\nelse {\n  $_DATA = $_GET;\n}<\/pre>\n<p>The above code is exactly what I use in the demo file php-rest-check.php:<\/p>\n<pre class=\"prettyprint lang-php\">&lt;?php\n$resource = $_SERVER['PATH_INFO'];\n$method = $_SERVER['REQUEST_METHOD'];\n\n if ($method == 'POST' || $method == 'PUT') {\n  parse_str(file_get_contents('php:\/\/input'), $_DATA);\n}\nelse {\n  $_DATA = $_GET;\n}\n\n$arr = array(\n  'method' =&gt; $method,\n  'resource' =&gt; $resource,\n  'data' =&gt; $_DATA\n);\t\n\n\/\/ send (fake) HTTP status responses if forceError is set\nswitch($method) {\n  case 'POST':\n   if ($_DATA['forceError'] == 'false') {\n    $status = 'HTTP\/1.1 201 Created';\n  }\n  else {\n    $status = 'HTTP\/1.1 500 Internal Server Error';\n  }\n  break;\n  case 'GET':\n    if ($_DATA['forceError'] == 'false') {\n       $status = 'HTTP\/1.1 200 OK';\n    }\n    else {\n      $status = 'HTTP\/1.1 500 Internal Server Error';\n    }\n    break;\n  case 'PUT':\n    if ($_DATA['forceError'] == 'false') {\n      $status = 'HTTP\/1.1 200 OK';\n    }\n    else {\n      $status = 'HTTP\/1.1 404 Not Found';\n    }\n    break;\n  case 'DELETE':\n    if ($_DATA['forceError'] == 'false') {\n      $status = 'HTTP\/1.1 200 OK';\n      \/\/ With 204 there would be no status code available on the client-side\n      \/\/$status = 'HTTP\/1.1 204 No Content';\n    }\n    else {\n      $status = 'HTTP\/1.1 500 Internal Server Error';\n    }\n    break;\n}\nheader($status);\nif ($_DATA['forceError'] == 'false') {\n  \/\/ only send response data back when successful\n  echo json_encode($arr);\n}\n?&gt;<\/pre>\n<h2>2. Sending the RESTful requests<\/h2>\n<p>The only remaining question now is how you send a PUT or DELETE request. For that I&#8217;ll use the Dojo Toolkit, because that makes it very easy and I&#8217;m a big fan of it. If you don&#8217;t know Dojo, sorry, but it&#8217;s worth learning. The demo is meant as a working example to check if your server provides all four methods. The toolkit provides for each its own method, e.g. dojo.xhrPost(), dojo.xhrGet(), dojo.xhrPut() and dojo.xhrDelete().<\/p>\n<p>First we define a general argument object for all requests, because some attributes are all the same. If you want to send some variables along with your request, just add them as the content property. Dojo will either send them as part of the request header (e.g. in the querystring) in case of a GET\/DELETE or as part of the request body in case of a PUT\/POST. Use firebug to check what I mean. I added a forceError variable to tell PHP to send fake HTTP error messages.<\/p>\n<pre class=\"prettyprint lang-js\">&lt;script type=\"text\/javascript\"&gt;\nvar demo = {\n  \/\/ general arguments object for the different xhr methods.\n  args: {\n    url: 'php-rest-check.php',\n    handleAs: 'json',\n    content: {\n      forceError: false,\u00a0   \/\/ if set to true, server responds with an HTTP error\n      var1: 'someVal1',\u00a0\u00a0 \/\/ just some variables\n      var2: 'someVal2'\n    },\n    load: function(response, ioArgs) {\n      \/\/ log response\n      dojo.byId('log').innerHTML+= '&lt;p&gt;HTTP status: ' + ioArgs.xhr.statusText + ' ' + ioArgs.xhr.status + '&lt;br\/&gt;' +\n        'method: &lt;strong&gt;' + response.method + '&lt;\/strong&gt;&lt;br\/&gt;' +\n        'resource: ' + response.resource + '&lt;br\/&gt;' +\n        'query: ' + dojo.objectToQuery(response.data) + '&lt;\/p&gt;';\n    },\n    error: function(error) {\n      \/\/ log HTTP error status\n      dojo.byId('log').innerHTML+= '&lt;p&gt;HTTP error status: ' + error.status;\n    }\n  },\n...<\/pre>\n<p>Then, all that&#8217;s left is that you need to slightly adapt the args object for each request. Note the dojo.clone() method. I use it to work with a copy not a reference of the args object.<\/p>\n<pre class=\"prettyprint lang-js\">...\n  \/\/ create\n  post: function() {\n    var args = dojo.clone(this.args);\u00a0\u00a0 \u00a0\/\/ otherwise we would keep adding '\/name\/1' with each new post\n    args.url+= '\/images\/1'; \/\/ create new item with id = 1 at '\/images'\n    dojo.xhrPost(args);\n  },\n  \/\/ read\/load\n  get: function() {\n    var args = dojo.clone(this.args);\n    args.url+= '\/images';\u00a0\u00a0 \u00a0\/\/ load all items at '\/images'\n    dojo.xhrGet(args);\n  },\n  \/\/ update\n  put: function() {\n    var args = dojo.clone(this.args);\n    args.url+= '\/images\/1'; \/\/ update item with id = 1 at '\/images\n    dojo.xhrPut(args);\n  },\n  \/\/ delete\n  del: function() {\n    var args = dojo.clone(this.args);\n    args.url+= '\/images\/1';\u00a0\u00a0 \u00a0\/\/ delete item with id = 1 at resouce\n    dojo.xhrDelete(args);\n  }\n}\n...<\/pre>\n<p>Finally, add the calls to the links on page load:<\/p>\n<pre class=\"prettyprint lang-php\">...\ndojo.addOnLoad(function() {\n  \/\/ add each request method to one of the links\n  dojo.query('#ulDemo li').forEach(function(node, i) {\n    dojo.connect(node, 'onclick', function(e) {\n      dojo.stopEvent(e);\t\/\/ prevent link action\n      demo.args.content.forceError = dojo.byId('fldforceError').checked ? true : false;\n      switch(i) {\n        case 0:\n          demo.post();\n          break;\n        case 1:\n          demo.get();\n          break;\n        case 2:\n          demo.put();\n          break;\n        case 3:\n          demo.del();\t\/\/ note: delete is reserved word\n          break;\n        }\n     });\n  });\n});\n&lt;\/script&gt;<\/pre>\n<h2><a name=\"tutorials\"><\/a>Tutorials<\/h2>\n<ul>\n<li>Gen X Design: <a href=\"http:\/\/www.gen-x-design.com\/archives\/create-a-rest-api-with-php\/\">Create a REST API with PHP<\/a><\/li>\n<li>Medryx Observations: <a href=\"http:\/\/blog.medryx.org\/2008\/07\/24\/jsonreststore-overview\/\" rel=\"bookmark\">JsonRestStore \u2014 Custom Services, Schemas, and Lazy Loading<\/a><\/li>\n<li>Sitepen: <a href=\"http:\/\/www.sitepen.com\/blog\/2010\/01\/27\/efficient-lazy-loading-of-a-tree\/\">Efficient Lazy Loading of a Tree<\/a><\/li>\n<li>Sitepen: <a href=\"http:\/\/www.sitepen.com\/blog\/2008\/11\/21\/effective-use-of-jsonreststore-referencing-lazy-loading-and-more\/\">Effective use of JsonRestStore: Referencing, Lazy Loading, and more<\/a><\/li>\n<\/ul>\n<h2>Downloads<\/h2>\n<p>zipped demo 1 of part 1 <a href=\"\/articles\/downloads\/php-rest-check.zip\">php-rest-check.zip<\/a><\/p>\n<p>zipped demo 2 of part 1 <a href=\"\/articles\/downloads\/dojo-jsonreststore.zip\">dojo-jsonreststore.zip<\/a><\/p>\n<p>That&#8217;s the end of the first part. Second part in preparation&#8230;<\/p>\n<p><script type=\"text\/javascript\">\/\/ <![CDATA[\n       prettyPrint();\n\/\/ ]]><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I only started recently to dig into REST, so I&#8217;m in no way an expert in this field. There are not that many tutorials on the internet, and the ones I found were only of limited help. They all seemed to miss something or, rather, I missed something. So I decided to write my own &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.speich.net\/articles\/en\/2010\/02\/13\/tutorial-part1-rest-with-dojo-and-php\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Tutorial Part 1: REST with Dojo and PHP&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,6],"tags":[26,77],"class_list":["post-91","post","type-post","status-publish","format-standard","hentry","category-javascript","category-php","tag-dojo","tag-rest","entry"],"_links":{"self":[{"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/posts\/91","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/comments?post=91"}],"version-history":[{"count":0,"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/posts\/91\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/media?parent=91"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/categories?post=91"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.speich.net\/articles\/wp-json\/wp\/v2\/tags?post=91"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}