RESTful Service and Client with PHP and AJAX
... and a little mod_rewrite :-)
Here I'm going to show you how you can implement a RESTful interface using exclusively JavaScript code on the client side, and PHP on the server side. In between them we are going to use minimal Apache's mod_rewrite for some URI manipulation.
All the source code for this example as well as a working version of it can be found here on the Labs section. And here's a ZIP archive containing the same files for download.
Files
Let's get started by listing the files that will be part of the solution:
myResource.php - Contains the PHP implementation of the service. In this case I have chosen to include the code for different methods in the same file.
client.html and client.js - Markup and JavaScript code for the client that will consume our service. On this example you'll see different methods being invoked and different responses being handled.
.htaccess - Contains the rule that translate the RESTful URL and redirects the request to our PHP implementation. The file htaccess.txt contains a copy of the hidden file's content for easy viewing.
RESTful URI's
Now, the URI's we want for this example have the following form:
/api/myResource/[RESOURCE_ID]
For example:
http://ccswf.ca/labs/restfulPhpAjax/api/myResource/1234
That means that if we want to get information for the resource number 1234 we need to perform a GET request to that URI. If we wanted to delete that same resource we would issue a DELETE HTTP request and if we wanted to list all resources we would omit the id part. You get the idea.
So the rule that interprets that URL is inside the .htaccess file and looks like this:
RewriteRule ^api/(myResource)(/\d{0,8})?$ serviceImpl/$1.php
It basically tells Apache to let our PHP file handle all requests involving that resource. The regular expression allows for the id to be optional.
The actual parsing of the URL will be made in the PHP code. Let's see how that is done.
Service Implementation (Server-Side)
The property that allows us to read the original URI is REQUEST_URI in the $_SERVER global object . In our example we are only interested on the id part of the string so that's what we extract:
$parts = preg_split("/\//", $_SERVER["REQUEST_URI"]);
$resourceId = $parts[count($parts) - 1];
The other thing we have to take care of with PHP is detecting the HTTP method invokes. The property for that is called REQUEST_METHOD. And here it is in action:
if($_SERVER["REQUEST_METHOD"] == "GET") {
...
} else if($_SERVER["REQUEST_METHOD"] == "DELETE") {
...
}
Our service only supports methods GET and DELETE, but any HTTP method can be used.
Some HTTP requests like POST allow data to be passed to the server. The easiest way to access that data from PHP is by opening the php://input pseudo-file. Like this:
$input = file_get_contents("php://input");
And finally, after we do our stuff -like deleting the resource- we send back a HTTP response code to the client. That is done by using the built-in header function. Here's an example:
header($_SERVER["SERVER_PROTOCOL"] . " 404 Not Found");
On that line the protocol taken from the $_SERVER global object, although we know it will probably be a version of HTTP. In this particular case, the response code we have chosen to return is a 404 code, as in "couldn't find a resource with the given ID". That response will be decoded on the client side.
Client Implementation (Service Consumer)
Let's jump to the client implementation to see how those methods are actually invoked. In a nutshell, what we do is use the AJAX technique to send requests to the URI. The JavaScript object that will do all that for us is the XMLHttpRequest object.
So in our single client.js Javascript file you will find something similar to the following code.
var req = new XMLHttpRequest();
...
req.open("PUT", "api/myResource/1234");
req.send("Some resource data");
On that snippet we call the PUT method on a specific resource identifier, passing along some text as data. What's been cut out from there is the actual handling of the response, which will look something like this:
req.onreadystatechange = function() {
if(req.readyState == 4) {
if(req.status == 200) {
// Ok
var returnedData = req.responseText;
} else if (req.status == 404) {
// Not found
var statusInfo = req.statusText;
} else if (req.status == 501) {
// Not implemented, this should not happen
}
}
}
Notice how the different response codes are handled explicitly and how the response data is obtained from responseText property.
So that is pretty much all you need to know in order to create a neat client-server interaction RESTstyle. Hope you liked it. Don't be afraid to add your questions or comments.
See you next time!
Attachments:
restfulPhpAjax.zip (2.5 KB)
Bazaar and SFTP to get control of version control
Motivation
As an independent web developer, I have always wanted a source code management solution (SCM) similar to the ones bigger organizations offer to their developers. Ideally, that solution would not only provide me with basic version control functionality but it would also help me backup, synchronize and share my projects.
Possible Solutions
Most of the companies I have worked with rely on centralized systems like Subversion, so naturally my first approach was to set up my own copy of the software on desktop PC at home. After a while I realized how time-consuming administering the service was. In order to access it from the internet, I even had to expose the PC to the internet using a dynamic domain name service, which isn’t the most secure or reliable thing to do.
So I decided to look into 3rd party project hosting services. I first checked out the free ones like SourceForge and Google Code. But they all required me to make every project open-source and I don’t always have that possibility.
I was then starting to evaluate some of the paid solutions when I realized I already was paying for a basic hosting service. Unfortunately my plan didn’t include SCM but maybe that didn’t matter. That was when I discovered Bazaar.
Bazaar Version Control System
Bazaar is just one of the many modern version control systems that unlike Subversion can work in a decentralized manner, but this one in particular doesn’t require a special protocol to work with. That means you can combine it with any FTP hosting account for reliable, affordable source code management that you can control in full.
What’s more, using a centralized-decentralized workflow you can collaborate with other developers that might or might not have their own FTP hosts.
Hands-On
Here’s one of the ways to use Bazaar.
First you need to set up an FTP/SFTP user on your server, for instance using CPanel. In this example that user is called “bzrusr”.
It is also a good idea to generate a key for that user and install it on the client so that you don’t have to type in the password.
$ cp bzruser.priv ~/.ssh
Since we are working with just one FTP user, the first thing to do with Bazaar is identify yourself:
$ bzr whoami "John Doe <johndoe@mail.com>"
To verify:
$ bzr whoami
John Doe <johndoe@mail.com>
If you want to add an existing project, you initialize it, add files to it and save it:
$ cd MyExistingProject
$ bzr init .
$ bzr add *
$ bzr commit -m “Initial Revision”
Once you have a local branch set up, you can upload it to your server:
$ bzr push sftp://bzrusr@yourdomain.com/BazaarProjects/MyProject
Now you can work locally if you want:
$ edit somefile.txt
$ bzr ci “edited some file”
And you can push the branch to your server anytime you want.
Someone else can pull the branch from the server:
$ bzr pull sftp://bzrusr@yourdomain.com/BazaarProjects/MyProject
You can even use the more traditional checkout command to work in a centralized way (just like CVS or Subversion):
$ bzr checkout sftp://bzrusr@yourdomain.com/BazaarProjects/MyProject
Bazaar even lets you bind or unbind your branch from the central repository to work locally:
$ bzr unbind
To go back online and use remote commits:
$ bzr bind
Finally, to download the changes someone else might have uploaded, you just have to use the merge command before pushing the branch again.
$ bzr merge
$ bzr commit -m “Merged branch”
$ bzr push
And that also works with the update command if you are bound to a remote repository:
$ bzr update
$ bzr commit -m “Merged branch”
For more information go to Bazaar’s official site, where you can download the tool, documentation and great tutorials:
HTML templates with JavaScript and external XML
Hello all and welcome to the C+C Software Factory blog.
On this, my first post, I would like to demonstrate a technique for storing XHTML templates on external files and applying them using standard JavaScript and DOM methods.
There are two main files involved in this example:
- myTemplate.xml - contains the common structure for all the pages that are instances of the template. In this case the layout consists of a table with header, footer, left column and right column cells.
- myPage.html - represents an entry point and an instance of the template. It contains the markup to be relocated within the corresponding region of the template.
For clarity, I separated the CSS and JavaScript code into two files named myPage.css and myPage.js.
So basically what we have is two separate markups -layout and content- that we want to merge, customize and display. That work is done by the applyTemplate() function invoked when myPage.html is accessed.
In a nutshell, here's what the applyTeplate() function does:
- Load the external XML document containing the template
- Import the template nodes into the main HTML document - without displaying it
- Move the original content (nodes) into the corresponding region of the layout
- Display the final layout by appending the imported node to the body element
Finally these are the most important snippets of the code:
myPage.html (entry point, template instance):
<body> <div id="rightContent"> <h1>Lorem ipsum dolor sit amet,</h1>
...
</div>
...
</body>
myTemplate.xml
<table xmlns="http://www.w3.org/1999/xhtml" class="layout">
... <tr> <td colspan="2"><div id="headerContainer">...</div></td> </tr> <tr> <td><div id="leftContainer">...</div></td> <td><div id="rightContainer"></div></td> </tr> <tr> <td colspan="2"><div id="footerContainer">...</div></td> </tr> ... </table>
myPage.js
function applyTemplate() { // our main function
// first thing, remove current content from document
var content = document.body.removeChild(document.getElementById("rightContent"));
// bring in the external template
var templateXml = getXml("myTemplate.xml");
// import template into main document
var templateNode = document.adoptNode(templateXml.firstChild);
// customize header
templateNode.getElementsByTagName("div")[0].childNodes[0].nodeValue = "Custom Page Header";
// insert template into document's body
document.body.appendChild(templateNode);
// put back custom content into the template
var totalNodes = content.childNodes.length;
for(var i = 0; i < totalNodes; i++) {
document.getElementById("rightContainer").appendChild(content.firstChild);
}
}
...
Some considerations:
- getXML() is a simple XHR call, in this case, a synchronous call (included with full source code)
- adoptNode() is a standard DOM method not implemented by IE so a substitute implementation is needed (included)
- Outer elements defined in the template XML must have the xmlns (name space) attribute to be imported propperly
- IE requires the table element defined in the template to contain a tbody element, this has no effect on other browsers
- IE requires certain attributes like class, style, for, colspan to be renamed, that's taken care of by the replacement adoptNode function
Acknowledgements:
- The original importNode() replacement was taken (and modified) from here
You can find the full source code attached to this post. A running example can be found at http://ccsoftwarefactory.com/labs/xmlJsTemplate
Thank you and stay tuned for more JavaScript tips and tricks!
Attachments:
xmlJsTemplate.zip (5.6 KB)