<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>Saving the world from bad software and buggy code, one line at a time!</description><title>Code in Chaos Inc.</title><generator>Tumblr (3.0; @codeinchaos)</generator><link>http://www.codeinchaos.com/</link><item><title>RTFM! (or: Why every web developer should read RFC 2616)</title><description>&lt;p&gt;As a software developer you always have to deal with users who find it difficult to use your software, or may -in one way or another- find it challenging to understand the interface or the functionality you&amp;#8217;ve designed.&lt;br/&gt;
But that&amp;#8217;s okay, because we are geeks who spends most of your adult lives behind a computer screen, building software and applications that -to us- are interesting and make perfect sense.&lt;br/&gt;
The reality is, without &lt;b&gt;Graphic Designers&lt;/b&gt; to make our ugly interfaces sexy, and without &lt;b&gt;Marketers&lt;/b&gt; to put together a clear message that explains what our thousand lines of code does, and without &lt;b&gt;Sales Gurus&lt;/b&gt; to make these lines of text sell for $$$ we&amp;#8217;d all be the laughing stock of the rest of the world, with our crazy, ugly looking products that do what any capable human being can do.&lt;/p&gt;

&lt;p&gt;Try telling Don Draper back in the 50s that we could one day replace his secretary with a voice enabled application on a portable device that you can put in your pocket and operate it simply by touch it&amp;#8217;s glass surface. oh and it will be called Siri.&lt;/p&gt;

&lt;p&gt;He&amp;#8217;d probably punch you square in the face.&lt;/p&gt;

&lt;p&gt;So I&amp;#8217;m never upset, offended or at the least, bothered, by any feedback or criticism from people using software that I&amp;#8217;ve build, I&amp;#8217;ve always found it to be an enlightening and humbling experience to see into the way other people think and react to technology that I&amp;#8217;ve build.&lt;/p&gt;

&lt;p&gt;But! those are people who are not developers, software engineers or in any way shape or form, familiar with the inner workings of the technology they use day to day.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve always written software for people like that, and I always will. recently however, I created &lt;a href="http://www.restconsole.com" target="_blank"&gt;REST Console&lt;/a&gt; an HTTP Client for Google Chrome. this is an application directly targeted towards software developers, not your average consumer.&lt;/p&gt;

&lt;p&gt;Software developers (in my mind) are people who can create code in the form of software and applications, much like the way artists create art.
&lt;br/&gt;Most of us don&amp;#8217;t understand how the artist creates his art, we don&amp;#8217;t really know what the tools they use are beyond our basic knowledge or a paint brush. But we all appreciate their work, some of us love, some don&amp;#8217;t. &lt;br/&gt;Software is the same as Art, many people don&amp;#8217;t have the skill for it or the understanding of how it works, but they use it every day.&lt;/p&gt;

&lt;p&gt;Ever since &lt;a href="http://www.restconsole.com" target="_blank"&gt;REST Console v.4.0.0&lt;/a&gt; came out, I&amp;#8217;ve been getting emails, comments, and github issues telling me its broken.&lt;/p&gt;

&lt;p&gt;well, Its not. you are using it wrong!&lt;/p&gt;

&lt;p&gt;Too aggressive? how about this: &lt;b&gt;You don&amp;#8217;t know how the internet works!&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I find it utterly frustrating and completely shocking that the target audience for this particular software don&amp;#8217;t know how to use it!&lt;/p&gt;

&lt;p&gt;I figured Software Developers of all people need the least explanation, hand holding, or even guidance in using a software application that is &lt;b&gt;SO&lt;/b&gt; specific in nature to what they do every day as part of their daily jobs (or hobbies, whatever) that I didn&amp;#8217;t need to include a manual, or even do much explaining how the app works, they can figure it out themselves, they have the skills, they build apps like this every day!. Or at the very least, Google for some background information on the solution the application provides.&lt;/p&gt;

&lt;p&gt;v4.0.0 of REST Console was a major re-write, but other than the interface and the code, little has changed or was added, except for one little tiny thing:&lt;br/&gt;&lt;b&gt;Header fields are no longer pre-populated with a default value.&lt;b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This has apparently caused HAVOC.&lt;/p&gt;

&lt;p&gt;It seems a significant number of Software Developers out there don&amp;#8217;t really understand how the internet works, well, allow me to shine your way to a better understanding&amp;#8230;&lt;/p&gt;

&lt;p&gt;See, there is something interesting out there called &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"&gt;RFC 2616&lt;/a&gt; that, in simple terms: defines how HTTP requests are made over the internet.&lt;br/&gt;and HTTP Requests are exactly what REST Console is built to do.&lt;/p&gt;

&lt;p&gt;People were complaining that v4.0.0 is broken, why? because their &lt;b&gt;POST&lt;/b&gt; payload is not being received on their servers.&lt;br/&gt;It seems the mistake these developers have done (beyond not reading &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"&gt;RFC 2616&lt;/a&gt;) is forgetting to set their &lt;b&gt;Content-Type&lt;/b&gt; header before they send their &lt;b&gt;POST&lt;/b&gt; requests.&lt;/p&gt;

&lt;p&gt;This alone is not a big deal, I started telling people they may have forgotten to set their Content-Type header, and they proceeded to check the box to enable it and come back and complain that it still didn&amp;#8217;t work.&lt;/p&gt;

&lt;p&gt;Turns out none of these guys realized that they need to set their Content-Type to &amp;#8220;&lt;b&gt;application/x-www-form-urlencoded&lt;/b&gt;&amp;#8221; which is the Internet media type for sending HTML Form Data, something they would have known have they read &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"&gt;RFC 2616&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"&gt;RFC 2616&lt;/a&gt; actually has no mention of &amp;#8220;application/x-www-form-urlencoded&amp;#8221;, it only references &lt;a href="http://www.ietf.org/rfc/rfc1867" target="_blank"&gt;RFC 1867&lt;/a&gt; regarding Form-based File Upload in HTML, which mentions &amp;#8220;application/x-www-form-urlencoded&amp;#8221; which is actually defined in &lt;a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1" target="_blank"&gt;HTML 4.01 Specification, Section 17.13.4.1&lt;/a&gt; only to discuss its limitation and being: &amp;#8220;inefficient for sending large quantities of binary data or text containing non-ASCII characters.&amp;#8221; and suggests using &amp;#8220;multipart/form-data&amp;#8221; as it accommodates a wider spectrum of data to be transferred over HTTP.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;I find it actually scary that some developers don&amp;#8217;t know that.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;REST Console is a tool to build HTTP requests, not emulate an HTML form. it&amp;#8217;s that simple.&lt;/p&gt;

&lt;p&gt;PHP (and other languages) expects the Content-Type header to be set to &amp;#8220;application/x-www-form-urlencoded&amp;#8221; so it would parse the POST url-encoded string into a $_POST variable &amp;#8230; but that&amp;#8217;s not how all HTTP requests are made.&lt;/p&gt;

&lt;p&gt;While this is a &amp;#8220;typical&amp;#8221; behavior for sending data through HTML forms, you can in fact, send a payload of a url-encoded &amp;#8220;key/value&amp;#8221; string and tell the server its &amp;#8220;application/xml&amp;#8221;!&lt;/p&gt;

&lt;p&gt;Its up to the HTTP client library to determine what to set the Content-Type header to, and to the server to determine how interpret the request body, based on the Content-Type header it receives &amp;#8230;&lt;/p&gt;

&lt;p&gt;I feel really frustrated writing this post, I shouldn&amp;#8217;t have to, this should be common knowledge for people in our field, but there it is. and it scares me.&lt;/p&gt;

&lt;p&gt;Based on how many people have complained about POST data not being sent, maybe I&amp;#8217;ll make the Content-Type header pre-populated again, This post will not stop the questions, the bad reviews in the Chrome Web Store or the github issues. There are already a significant number of them, and people didn&amp;#8217;t bother reading the replies I made. so why should this post help?&lt;/p&gt;

&lt;p&gt;The one thing I&amp;#8217;m now almost certain people will never do, is read &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"&gt;RFC 2616&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please prove me wrong.&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/11091647462</link><guid>http://www.codeinchaos.com/post/11091647462</guid><pubDate>Thu, 06 Oct 2011 00:48:56 -0400</pubDate><dc:creator>ahmadnassri</dc:creator></item><item><title>Programming a Twilio phone menu with TwiML &amp; some PHP</title><description>&lt;p&gt;&lt;a href="http://www.twilio.com" target="_blank" title="Twilio's website"&gt;Twilio&lt;/a&gt; allows your web application to easily make and receive phone calls and SMS text messages using a simple web service API and basic web programming skills like HTTP, XML, and REST.  You can build hosted IVR, PBX and SMS applications with no up front costs and a very competitive pricing&lt;/p&gt;

&lt;p&gt;With so many possibilities and mash-ups ideas, the sky is the limit to the things you can do with Twilio &amp;#8230; however, in its most basic forms (and most popular usage I believe) Twilio lets you build a simple phone menu in no time at all.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m sure we will be utilizing Twilio in the future for some cool &amp;amp; rad Code in Chaos projects, but for now, we made a simple phone menu with a company directory that forwards the caller to the person&amp;#8217;s personal phone number and a message recording option that will let the caller record a two minute message, then emails that message along with the caller ID information to a specified email address.&lt;/p&gt;

&lt;p&gt;its a very simple implementation, we though we&amp;#8217;d share it, since we found the Twilio samples a bit too complicated than what they should be, they rely on too many files for something that can be achieved with just one.&lt;/p&gt;

&lt;b&gt;index.php&lt;/b&gt;
&lt;pre class="brush: xml"&gt;
&amp;lt;? header('Content-Type: text/xml') ?&amp;gt;
&amp;lt;? include 'email.php' ?&amp;gt;
&amp;lt;?= '&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;' ?&amp;gt;
&amp;lt;Response&amp;gt;
    &amp;lt;? if (!array_key_exists('Digits', $_REQUEST)): ?&amp;gt;
        &amp;lt;Say voice="woman"&amp;gt;You have reached Code in Chaos.&amp;lt;/Say&amp;gt;
        &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=0&amp;lt;/Redirect&amp;gt;
    &amp;lt;? else: ?&amp;gt;
        &amp;lt;? if (array_key_exists('RecordingUrl', $_REQUEST)): ?&amp;gt;
            &amp;lt;? email($_REQUEST['RecordingUrl']) ?&amp;gt;
            &amp;lt;Say voice="woman"&amp;gt;Thank you, we will contact you as soon as possible. Goodbye.&amp;lt;/Say&amp;gt;
            &amp;lt;Hangup/&amp;gt;
        &amp;lt;? elseif (array_key_exists('Dial', $_REQUEST)): ?&amp;gt;
            &amp;lt;? switch (@$_REQUEST['Digits']):
                case '0': ?&amp;gt;
                    &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=1&amp;lt;/Redirect&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? case '1': ?&amp;gt;
                    &amp;lt;Dial timeout="15" hangupOnStar="true"&amp;gt;+16477007703&amp;lt;/Dial&amp;gt;
                    &amp;lt;Say voice="woman"&amp;gt;Failed to connect your call, please try again later. Goodbye.&amp;lt;/Say&amp;gt;
                    &amp;lt;Hangup/&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? case '*': ?&amp;gt;
                    &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=0&amp;lt;/Redirect&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? default: ?&amp;gt;
                    &amp;lt;Say voice="woman"&amp;gt;Invalid Entry.&amp;lt;/Say&amp;gt;
                    &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=1&amp;lt;/Redirect&amp;gt;
            &amp;lt;? endswitch ?&amp;gt;
        &amp;lt;? else: ?&amp;gt;
            &amp;lt;? switch ($_REQUEST['Digits']):
                case '0': ?&amp;gt;
                    &amp;lt;Gather numDigits="1" timeout="10" action="index.php" method="POST"&amp;gt;                        
                        &amp;lt;Say voice="woman"&amp;gt;Main menu.&amp;lt;/Say&amp;gt;
                        &amp;lt;Pause length="1"/&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Press 1 for the company's directory.&amp;lt;/Say&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Press 2 to leave a message.&amp;lt;/Say&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Press 0 to repeat this menu.&amp;lt;/Say&amp;gt;
                        
                    &amp;lt;/Gather&amp;gt;

                    &amp;lt;? if (array_key_exists('Repeated', $_REQUEST)): ?&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Goodbye.&amp;lt;/Say&amp;gt;
                        &amp;lt;Hangup/&amp;gt;
                    &amp;lt;? else: ?&amp;gt;
                        &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=0&amp;amp;Repeated=true&amp;lt;/Redirect&amp;gt;
                    &amp;lt;? endif ?&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? case '1': ?&amp;gt;
                    &amp;lt;Gather numDigits="1" timeout="10" action="index.php?Dial=true" method="POST"&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Company Directory.&amp;lt;/Say&amp;gt;
                        &amp;lt;Pause length="1"/&amp;gt;                        
                        &amp;lt;Say voice="woman"&amp;gt;For Ahmad Nassri, press 1.&amp;lt;/Say&amp;gt;
                        &amp;lt;Pause length="2"/&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Press 0 to repeat this menu.&amp;lt;/Say&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Press star to return to the main menu.&amp;lt;/Say&amp;gt;
                    &amp;lt;/Gather&amp;gt;

                    &amp;lt;? if (array_key_exists('Repeated', $_REQUEST)): ?&amp;gt;
                        &amp;lt;Say voice="woman"&amp;gt;Goodbye.&amp;lt;/Say&amp;gt;
                        &amp;lt;Hangup/&amp;gt;
                    &amp;lt;? else: ?&amp;gt;
                        &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=1&amp;amp;Repeated=true&amp;lt;/Redirect&amp;gt;
                    &amp;lt;? endif ?&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? case '2': ?&amp;gt;
                    &amp;lt;Say voice="woman"&amp;gt;Record your message after the tone, when finished, press the star key.&amp;lt;/Say&amp;gt;
                    &amp;lt;Pause length="1"/&amp;gt;
                    &amp;lt;Say voice="woman"&amp;gt;Please leave your name, number and email address and the reason for your call.&amp;lt;/Say&amp;gt;
                    
                    &amp;lt;Record timeout="10" maxLength="120" action="index.php" method="POST" finishOnKey="*"/&amp;gt;
                    &amp;lt;? break ?&amp;gt;

                &amp;lt;? default: ?&amp;gt;
                    &amp;lt;Say voice="woman"&amp;gt;Invalid Entry&amp;lt;/Say&amp;gt;
                    &amp;lt;Redirect method="GET"&amp;gt;index.php?Digits=0&amp;lt;/Redirect&amp;gt;
            &amp;lt;? endswitch ?&amp;gt;
        &amp;lt;? endif ?&amp;gt;
    &amp;lt;? endif ?&amp;gt;
&amp;lt;/Response&amp;gt;
&lt;/pre&gt;

&lt;b&gt;email.php&lt;/b&gt;
&lt;pre class="brush: php"&gt;
&amp;lt;?php
function email($url) {
    $message = sprintf('&amp;lt;b&amp;gt;Caller:&amp;lt;/b&amp;gt; %s&amp;lt;br/&amp;gt; &amp;lt;b&amp;gt;City:&amp;lt;/b&amp;gt; %s&amp;lt;br/&amp;gt; &amp;lt;b&amp;gt;State:&amp;lt;/b&amp;gt; %s&amp;lt;br/&amp;gt; &amp;lt;b&amp;gt;Country:&amp;lt;/b&amp;gt; %s&amp;lt;br/&amp;gt;', $_REQUEST['From'], $_REQUEST['FromCity'], $_REQUEST['FromState'], $_REQUEST['FromCountry']);

    $boundary = uniqid();

    $headers = array(
        'From: Twilio &amp;lt;twilio@codeinchaos.com&amp;gt;',
        'Reply-To: No Reply &amp;lt;noreply@codeinchaos.com&amp;gt;',
        'MIME-Version: 1.0',
        'Content-Type: multipart/mixed; boundary = ' . $boundary,
        ''
    );

    $headers = join("\r\n", $headers);

    //plain text version of message
    $body = array(
        // plain text
        '--' . $boundary,
        'Content-Type: text/plain; charset=ISO-8859-1',
        'Content-Transfer-Encoding: base64',
        '',
        chunk_split(base64_encode(strip_tags($message))),
        // html
        '--' . $boundary,
        'Content-Type: text/html; charset=ISO-8859-1',
        'Content-Transfer-Encoding: base64',
        '',
        chunk_split(base64_encode($message)),
        // attachement
        '--' . $boundary,
        'Content-Type: audio/wav; name=message.wav',
        'Content-Transfer-Encoding: base64',
        'Content-Disposition: attachment',
        '',
        chunk_split(base64_encode(file_get_contents($url)))
    );

    $body = join("\r\n", $body);

    //send the email
    return @mail('contact@codeinchaos.com', 'New Voice Mail (' . $_REQUEST['CallSid'] . ')', $body, $headers);
}
&lt;/pre&gt;</description><link>http://www.codeinchaos.com/post/9789533846</link><guid>http://www.codeinchaos.com/post/9789533846</guid><pubDate>Sun, 04 Sep 2011 10:43:00 -0400</pubDate><category>PHP</category><category>TwiML</category><category>Twilio</category><dc:creator>ahmadnassri</dc:creator></item><item><title>Hi, I was about to install your REST Console from the Chrome web store. But why on earth do you need access to data on all websites I visit?</title><description>&lt;p&gt;actually, REST Console doesn’t need access to all your “data” on all website, I think that’s mis-wording on Google’swebsite behalf.&lt;/p&gt;

&lt;p&gt;the application asks for the following permissions:&lt;/p&gt;

&lt;p&gt;“permissions”: [&lt;br/&gt;
    “http://*/*”,&lt;br/&gt;
    “https://*/*”&lt;br/&gt;
]&lt;/p&gt;

&lt;p&gt;this basically allows the app to make HTTP calls to any URL, which is obviously the intent of the app, however it does not access any other information.&lt;/p&gt;

&lt;p&gt;the application is open-source so you are free to checkout the inner workings of it at the github project page: &lt;a href="http://github.com/codeinchaos/restconsole" target="_blank"&gt;http://github.com/codeinchaos/restconsole&lt;/a&gt;&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/8691491887</link><guid>http://www.codeinchaos.com/post/8691491887</guid><pubDate>Tue, 09 Aug 2011 11:45:00 -0400</pubDate><dc:creator>ahmadnassri</dc:creator></item><item><title>REST Console - a Google Chrome REST/HTTP Client</title><description>&lt;p&gt;&amp;#8220;REST Console&amp;#8221; is a REST/HTTP Client for Google Chrome to visualise and construct custom HTTP requests to test with any RESTful web service.&lt;/p&gt;

&lt;strong&gt;Features:&lt;/strong&gt;
&lt;ul&gt;&lt;li&gt;Syntax highlighting (multiple themes)&lt;/li&gt;
&lt;li&gt;Custom headers&lt;/li&gt;
&lt;li&gt;Construct POST or PUT body via raw input&lt;/li&gt;
&lt;li&gt;Auto Complete&lt;/li&gt;
&lt;li&gt;File upload&lt;/li&gt;
&lt;li&gt;Easy query parameters creation&lt;/li&gt;
&lt;li&gt;Add custom headers through intuitive ui&lt;/li&gt;
&lt;li&gt;Authentication support: Plain, Basic, OAuth + Custom&lt;/li&gt;
&lt;li&gt;Keyboard navigation and shortcuts&lt;/li&gt;
&lt;li&gt;Customizable Interface&lt;/li&gt;
&lt;/ul&gt;&lt;strong&gt;Resources&lt;/strong&gt;
&lt;ul&gt;&lt;li&gt;Follow us on Twitter: &lt;a href="http://twitter.com/restconsole" target="_blank"&gt;http://twitter.com/restconsole&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Get the source code: &lt;a href="https://github.com/codeinchaos/restconsole" target="_blank"&gt;https://github.com/codeinchaos/restconsole&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Report issues: &lt;a href="https://github.com/codeinchaos/restconsole/issues" target="_blank"&gt;https://github.com/codeinchaos/restconsole/issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Donate: &lt;a href="https://flattr.com/thing/156628/REST-Console" target="_blank"&gt;https://flattr.com/thing/156628/REST-Console&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;strong&gt;Changelog&lt;/strong&gt;
&lt;ul&gt;&lt;li&gt;v3.0.6 UI enhancements + File uploads + &amp;#8220;Save Default&amp;#8221; Option&lt;/li&gt;
&lt;li&gt;v3.0.5 More keyboard shortcuts&lt;/li&gt;
&lt;li&gt;v3.0.4 Bugfixes&lt;/li&gt;
&lt;li&gt;v3.0.3 Keyboard navigation + Bugfixes&lt;/li&gt;
&lt;li&gt;v3.0.2 Syntax Highlighting themes + Collapsible sections + Options&lt;/li&gt;
&lt;li&gt;v3.0.1 RAW request body + Bugfixes&lt;/li&gt;
&lt;li&gt;v3.0.0 Brand New UI&lt;/li&gt;
&lt;li&gt;v2.1.1 Bugfixes&lt;/li&gt;
&lt;li&gt;v2.1 Added OAuth1.0a support + bug fixes.&lt;/li&gt;
&lt;li&gt;v2.0 Revamped Design.&lt;/li&gt;
&lt;li&gt;v1.0 Released!&lt;/li&gt;
&lt;/ul&gt;&lt;strong&gt;Coming Soon:&lt;/strong&gt;
&lt;ul&gt;&lt;li&gt;Request history manager&lt;/li&gt;
&lt;li&gt;URL auto complete&lt;/li&gt;
&lt;/ul&gt;&lt;center&gt;
&lt;a href="https://chrome.google.com/webstore/detail/faceofpmfclkengnkgkgjkcibdbhemoc" target="_blank"&gt;&lt;img src="http://media.tumblr.com/tumblr_lldbttzEfA1qzt8cz.png" style="border:none"/&gt;&lt;/a&gt;
&lt;/center&gt;</description><link>http://www.codeinchaos.com/post/3610180596</link><guid>http://www.codeinchaos.com/post/3610180596</guid><pubDate>Tue, 17 May 2011 22:00:00 -0400</pubDate><category>REST</category><category>Google Chrome</category><category>Extension</category><dc:creator>ahmadnassri</dc:creator></item><item><title>RESTful services with Zend Framework (Part 2)</title><description>&lt;p&gt;Previously, &lt;a href="http://www.codeinchaos.com/post/3107629294/restful-services-with-zend-framework-part-1" target="_blank"&gt;I covered the basic steps to create a RESTful Application with Zend Framework.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, we&amp;#8217;re going to look into context switching, which will allow us to server different response formats based on the &amp;#8220;Accept&amp;#8221; HTTP header&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve seen many wasy of doing this, like using view scripts to generate JSON or XML, or creating the response DOM document manually, etc &amp;#8230; but I found the simplest way is to stick to what we know, and what we know best in ZF is the setting the result variables through the view object, which we can easily serialize into any format we want using Zend&amp;#8217;s own &lt;a href="http://framework.zend.com/manual/en/zend.serializer.html" target="_blank"&gt;Zend_Serializer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Zend Framework comes with a ContextSwitch action helper, but its only good to do JSON, so lets extend it and add more formats, I&amp;#8217;m going to add AMF3, XML, PHP serialization, but you can add your own using either standard Zend_Serializer Adapters or building your own like we will for XML serialization&lt;/p&gt;

&lt;pre class="brush: php"&gt;
class REST_Controller_Action_Helper_ContextSwitch extends Zend_Controller_Action_Helper_ContextSwitch
{
    protected $_autoSerialization = true;

    protected $_availableAdapters = array(
        'amf'   =&amp;gt; 'Zend_Serializer_Adapter_Amf3',
        'json'  =&amp;gt; 'Zend_Serializer_Adapter_Json',
        'xml'   =&amp;gt; 'REST_Serializer_Adapter_Xml',
        'php'   =&amp;gt; 'Zend_Serializer_Adapter_PhpSerialize'
    );

    public function __construct($options = null)
    {
        if ($options instanceof Zend_Config)
        {
            $this-&amp;gt;setConfig($options);
        }
        elseif (is_array($options))
        {
            $this-&amp;gt;setOptions($options);
        }

        if (empty($this-&amp;gt;_contexts))
        {
            $this-&amp;gt;addContexts(
                array(
                    'amf' =&amp;gt; array(
                        'suffix'    =&amp;gt; 'json',
                        'headers'   =&amp;gt; array(
                            'Content-Type' =&amp;gt; 'application/octet-stream'
                        ),
                        'callbacks' =&amp;gt; array(
                            'init' =&amp;gt; 'initAbstractContext',
                            'post' =&amp;gt; 'restContext'
                        ),
                    ),

                    'json' =&amp;gt; array(
                        'suffix'    =&amp;gt; 'json',
                        'headers'   =&amp;gt; array(
                            'Content-Type' =&amp;gt; 'application/json'
                        ),
                        'callbacks' =&amp;gt; array(
                            'init' =&amp;gt; 'initAbstractContext',
                            'post' =&amp;gt; 'restContext'
                        ),
                    ),

                    'xml' =&amp;gt; array(
                        'suffix'    =&amp;gt; 'xml',
                        'headers'   =&amp;gt; array(
                            'Content-Type' =&amp;gt; 'application/xml'
                        ),
                        'callbacks' =&amp;gt; array(
                            'init' =&amp;gt; 'initAbstractContext',
                            'post' =&amp;gt; 'restContext'
                        ),
                    ),

                    'php' =&amp;gt; array(
                        'suffix'    =&amp;gt; 'php',
                        'headers'   =&amp;gt; array(
                            'Content-Type' =&amp;gt; 'text/php'
                        ),
                        'callbacks' =&amp;gt; array(
                            'init' =&amp;gt; 'initAbstractContext',
                            'post' =&amp;gt; 'restContext'
                        )
                    )
                )
            );
        }

        $this-&amp;gt;init();
    }

    public function initAbstractContext()
    {
        if (!$this-&amp;gt;getAutoSerialization())
        {
            return;
        }

        $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
        $view = $viewRenderer-&amp;gt;view;

        if ($view instanceof Zend_View_Interface)
        {
            $viewRenderer-&amp;gt;setNoRender(true);
        }
    }

    public function restContext()
    {
        if (!$this-&amp;gt;getAutoSerialization())
        {
            return;
        }

        $view = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')-&amp;gt;view;

        if ($view instanceof Zend_View_Interface)
        {
            if (method_exists($view, 'getVars'))
            {
                $data = $view-&amp;gt;getVars();

                if (count($data) !== 0)
                {
                    $serializer = new $this-&amp;gt;_availableAdapters[$this-&amp;gt;_currentContext];
                    $body = $serializer-&amp;gt;serialize($view-&amp;gt;getVars());

                    if ($this-&amp;gt;_currentContext == 'xml')
                    {
                        $stylesheet = $this-&amp;gt;getRequest()-&amp;gt;getHeader('X-XSL-Stylesheet');

                        if ($stylesheet !== false and !empty($stylesheet))
                        {
                            $body = str_replace('&lt;?xml version="1.0"?&gt;', sprintf('&lt;?xml version="1.0"?&gt;&lt;?xml-stylesheet type="text/xsl" href="%s"?&gt;', $stylesheet), $body);
                        }
                    }

                    if ($this-&amp;gt;_currentContext == 'json')
                    {
                        $callback = $this-&amp;gt;getRequest()-&amp;gt;getParam('jsonp-callback', false);

                        if ($callback !== false and !empty($callback))
                        {
                            $body = sprintf('%s(%s)', $callback, $body);
                        }
                    }

                    $this-&amp;gt;getResponse()-&amp;gt;setBody($body);
                }
            }
        }

    }

    public function setAutoSerialization($flag)
    {
        $this-&amp;gt;_autoSerialization = (bool) $flag;
        return $this;
    }

    public function getAutoSerialization()
    {
        return $this-&amp;gt;_autoSerialization;
    }

}
&lt;/pre&gt;

&lt;p&gt;for the most part, there is nothing special about this Class, it relies mostly on Zend_Controller_Action_Helper_ContextSwitch and mimics its logic:&lt;br/&gt;The &lt;strong&gt;constructor&lt;/strong&gt; adds the new contexts and defines the Content-Type header to send with the response.&lt;br/&gt;&lt;strong&gt;initAbstractContext&lt;/strong&gt; disables the view renderer completely (this replaces the method we used in Part 1)&lt;br/&gt;&lt;strong&gt;restContext&lt;/strong&gt; is where the magic happens!&lt;/p&gt;

&lt;h2&gt;The Magic!&lt;/h2&gt;
&lt;p&gt;first we grab the &lt;strong&gt;viewRenderer&lt;/strong&gt; object through &lt;strong&gt;Zend_Controller_Action_HelperBroker&lt;/strong&gt; and grab all the variables set from the Controller logic.&lt;br/&gt;Next we run those variables through our serializer and set the serialized value as the response body!&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll notice there is some extra magic happening in there around XML and XSL Stylesheets. this is something I added to facilitate the usage of XSL Stylesheets in an XML Response, all it does is expect an optional X-XSL-Stylesheet header from the client request and inserts the xml-stylesheet declaration to the XML response.&lt;br/&gt;That way if you are viewing this XML in a modern browser, the browser will automatically render the page into a more readable format using the specified XSL stylesheet.&lt;/p&gt;

&lt;p&gt;We also look in the request for a &lt;strong&gt;jsonp-callback&lt;/strong&gt; parameter to wrap around the body JSON response, this is most helpful when building web clients.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I&amp;#8217;m using a custom Zend_Serializer_Adapter: &lt;strong&gt;REST_Serializer_Adapter_Xml&lt;/strong&gt;, which is a custom XML serialization class I&amp;#8217;ve created, there is no point in describing it in this article since its irrelevant to the main topic, you can find the source in the repository.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we need to apply the ContextSwitch to each of our controllers actions, the easiest way to do so is with an Action Helper:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
class REST_Controller_Action_Helper_RestContexts extends Zend_Controller_Action_Helper_Abstract
{
    protected $_contexts = array(
        'php',
        'xml',
        'json',
        'amf'
    );

    protected $_actions = array(
        'options',
        'head',
        'index',
        'get',
        'post',
        'put',
        'delete',
        'error'
    );

    public function preDispatch()
    {
        $controller = $this-&amp;gt;getActionController();

        if (!$controller instanceof Zend_Rest_Controller)
        {
            return;
        }

        $this-&amp;gt;_initContexts();
    }

    protected function _initContexts()
    {
        $contextSwitch = $this-&amp;gt;getActionController()-&amp;gt;getHelper('contextSwitch');

        $contextSwitch-&amp;gt;setAutoSerialization(true);

        foreach ($this-&amp;gt;_contexts as $context)
        {
            foreach ($this-&amp;gt;_actions as $action)
            {
                $contextSwitch-&amp;gt;addActionContext($action, $context);
            }
        }

        $contextSwitch-&amp;gt;initContext();
    }
}
&lt;/pre&gt;

&lt;p&gt;What this helper does is execute on &lt;strong&gt;preDispatch&lt;/strong&gt; and set the all contexts on all actions of the current controller.&lt;/p&gt;

&lt;p&gt;Now we need to initialize those two helpers, that can be done in &lt;strong&gt;Bootstrap.php&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
    protected function _initActionHelpers()
    {
        $contextSwitch = new REST_Controller_Action_Helper_ContextSwitch();
        Zend_Controller_Action_HelperBroker::addHelper($contextSwitch);

        $restContexts = new REST_Controller_Action_Helper_RestContexts();
        Zend_Controller_Action_HelperBroker::addHelper($restContexts);
    }
&lt;/pre&gt;

&lt;p&gt;But how is the context set for each request? by default, ZF uses the &lt;strong&gt;?format=&lt;/strong&gt; query parameter to define the context, but that is not very RESTful! the most elegant way is to rely on HTTP Accept headers to tell us what kind of response the client expects, to accomplish this, we need a plugin:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
class REST_Controller_Plugin_RestHandler extends Zend_Controller_Plugin_Abstract
{
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $this-&amp;gt;getResponse()-&amp;gt;setHeader('Vary', 'Accept');

        $mimeType = $this-&amp;gt;getMimeType($request-&amp;gt;getHeader('Accept'));

        switch ($mimeType) {
            case 'text/xml':
            case 'application/xml':
                $request-&amp;gt;setParam('format', 'xml');
                break;

            case 'application/octet-stream':
                $request-&amp;gt;setParam('format', 'amf');
                break;

            case 'text/php':
                $request-&amp;gt;setParam('format', 'php');
                break;

            case 'application/json':
            default:
                $request-&amp;gt;setParam('format', 'json');
                break;
        }
    }

    private function getMimeType($mimeTypes = null)
    {
        // Values will be stored in this array
        $AcceptTypes = Array ();

        // Accept header is case insensitive, and whitespace isn't important
        $accept = strtolower(str_replace(' ', '', $mimeTypes));

        // divide it into parts in the place of a ","
        $accept = explode(',', $accept);

        foreach ($accept as $a)
        {
            // the default quality is 1.
            $q = 1;

            // check if there is a different quality
            if (strpos($a, ';q='))
            {
                // divide "mime/type;q=X" into two parts: "mime/type" i "X"
                list($a, $q) = explode(';q=', $a);
            }

            // mime-type $a is accepted with the quality $q
            // WARNING: $q == 0 means, that mime-type isn't supported!
            $AcceptTypes[$a] = $q;
        }

        arsort($AcceptTypes);

        // let's check our supported types:
        foreach ($AcceptTypes as $mime =&amp;gt; $q)
        {
            if ($q &amp;amp;&amp;amp; in_array($mime, $this-&amp;gt;availableMimeTypes))
            {
                return $mime;
            }
        }
        // no mime-type found
        return null;
    }
&lt;/pre&gt;

&lt;p&gt;The plugin does two things: first it sets the response &amp;#8220;Accept&amp;#8221; header to &amp;#8220;Vary&amp;#8221; (this tells HTTP clients that we are able to serve multiple formats) then it sets the &amp;#8220;format&amp;#8221; parameter based on the best mime-type described in the request&amp;#8217;s Accept header (the utility method &amp;#8220;getMimeType&amp;#8221; extracts and sorts the differnt values)&lt;/p&gt;

&lt;p&gt;Here you can set any number of mime-types you want to support and match them with Serializers we&amp;#8217;ve created previously.&lt;/p&gt; 

&lt;p&gt;Next, enabled this plugin in your application.ini&lt;/p&gt;

&lt;pre class="brush: text"&gt;
resources.frontController.plugins[] = "REST_Controller_Plugin_RestParams"
&lt;/pre&gt;

&lt;p&gt;Going back to the FooController we created in Part 1, lets first get rid of the &lt;strong&gt;init&lt;/strong&gt; method we created and modify the action methods to something like this:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
    public function optionsAction()
    {
        $this-&amp;gt;view-&amp;gt;message = 'Resource Options';
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
    }

    public function indexAction()
    {
        $this-&amp;gt;view-&amp;gt;resources = array();
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
    }

    public function headAction()
    {
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
    }

    public function getAction()
    {
        $this-&amp;gt;view-&amp;gt;id = $this-&amp;gt;_getParam('id');
        $this-&amp;gt;view-&amp;gt;resource = new stdClass;
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
    }

    public function postAction()
    {
        $this-&amp;gt;view-&amp;gt;message = 'Resource Created';
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(201);
    }

    public function putAction()
    {
        $this-&amp;gt;view-&amp;gt;message = sprintf('Resource #%s Updated', $this-&amp;gt;_getParam('id'));
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(201);
    }

    public function deleteAction()
    {
        $this-&amp;gt;view-&amp;gt;message = sprintf('Resource #%s Deleted', $this-&amp;gt;_getParam('id'));
        $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
    }
&lt;/pre&gt;

&lt;p&gt;Test it in the command line:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
curl -v -H "Accept: application/json" http://localhost/v1/foo
curl -v -H "Accept: application/json" -X HEAD http://localhost/v1/foo
curl -v -H "Accept: application/json" -X OPTIONS http://localhost/v1/foo/1
curl -v -H "Accept: application/json" -X GET http://localhost/v1/foo/1
curl -v -H "Accept: application/json" -X POST http://localhost/v1/foo
curl -v -H "Accept: application/json" -X PUT -d '' http://localhost/v1/foo/1
curl -v -H "Accept: application/json" -X DELETE http://localhost/v1/foo/1

curl -v -H "Accept: application/xml" http://localhost/v1/foo
curl -v -H "Accept: application/xml" -X HEAD http://localhost/v1/foo
curl -v -H "Accept: application/xml" -X OPTIONS http://localhost/v1/foo/1
curl -v -H "Accept: application/xml" -X GET http://localhost/v1/foo/1
curl -v -H "Accept: application/xml" -X POST http://localhost/v1/foo
curl -v -H "Accept: application/xml" -X PUT -d '' http://localhost/v1/foo/1
curl -v -H "Accept: application/xml" -X DELETE http://localhost/v1/foo/1
&lt;/pre&gt;

&lt;p&gt;You&amp;#8217;ll notice that we are no longer setting the response body text directly, but rather setting the view object variables which will be serialized according to the Accept header we are sending in the request!&lt;br/&gt;like I said, MAGIC!&lt;/p&gt;
&lt;p&gt;All this is great, we got all sorts of magic happening in the output, but what about the input? shouldn&amp;#8217;t we accept multiple formats as well?&amp;#8230;&lt;br/&gt; hellz yeah! lets do it!&lt;/p&gt;

&lt;p&gt;Lets go back and edit REST_Controller_Plugin_RestHandler and add the following:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
    private $availableMimeTypes = array(
        'php'           =&amp;gt; 'text/php',
        'xml'           =&amp;gt; 'application/xml',
        'json'          =&amp;gt; 'application/json',
        'amf'           =&amp;gt; 'application/octet-stream',
        'urlencoded'    =&amp;gt; 'application/x-www-form-urlencoded'
    );

    private $methods = array('OPTIONS', 'HEAD', 'INDEX', 'GET', 'POST', 'PUT', 'DELETE');

    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        if (!in_array(strtoupper($request-&amp;gt;getMethod()), $this-&amp;gt;methods))
        {
            $request-&amp;gt;setActionName('options');
            $request-&amp;gt;setDispatched(true);

            $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(405);

            return;
        }
        else
        {
            $contentType = $this-&amp;gt;getMimeType($request-&amp;gt;getHeader('Content-Type'));
            $rawBody = $request-&amp;gt;getRawBody();

            if (!empty($rawBody))
            {
                try
                {
                    switch ($contentType)
                    {
                        case 'application/json':
                            $params = Zend_Json::decode($rawBody);
                            break;

                        case 'text/xml':
                        case 'application/xml':
                            $json = Zend_Json::fromXml($rawBody);
                            $params = Zend_Json::decode($json, Zend_Json::TYPE_OBJECT)-&amp;gt;request;
                            break;

                        case 'application/octet-stream':
                            $serializer = new Zend_Serializer_Adapter_Amf3();
                            $params = $serializer-&amp;gt;unserialize($rawBody);
                            break;

                        case 'text/php':
                            $params = unserialize($rawBody);
                            break;

                        case 'application/x-www-form-urlencoded':
                            $params = array();
                            parse_str($rawBody, $params);
                            break;

                        default:
                            $params = $rawBody;
                            break;
                    }

                    $request-&amp;gt;setParams((array) $params);
                }
                catch (Exception $e)
                {
                    this-&amp;gt;view-&amp;gt;message = $e-&amp;gt;getMessage();;
                    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(400);
        
                    $request-&amp;gt;setControllerName('error');
                    $request-&amp;gt;setActionName('error');
                    $request-&amp;gt;setParam('error', $error);

                    $request-&amp;gt;setDispatched(true);

                    return;
                }
            }
        }
    }
&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;preDispatch&lt;/strong&gt; runs just before any Controller method is initiated and does two things:&lt;br/&gt;first, it checks if the requested HTTP Method is acceptable, and sends an OPTIONS response if its not (in accordance with the HTTP spec)&lt;br/&gt;Then it looks for the request&amp;#8217;s &amp;#8220;Content-Type&amp;#8221; header and un-serialze the raw body with a matching Zend_Serializer&lt;/p&gt;

&lt;p&gt;and just like &lt;strong&gt;MAGIC&lt;/strong&gt; our application can now parse different request formats!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update [Monday, 07 March 2011]:&lt;/strong&gt; added JSONP support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update [Sunday, 01 January 2012]:&lt;/strong&gt; This article is out of date, please refer to the &lt;a href="https://github.com/codeinchaos/restful-zend-framework" target="_blank"&gt;GitHub repo&lt;/a&gt; for updated instructions, the same principles still apply, but with some changes and slight modifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; all examples used are part of &lt;a href="https://github.com/codeinchaos/restful-zend-framework" target="_blank"&gt;RESTful Zend Framework on GitHub&lt;/a&gt;&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/3645298058</link><guid>http://www.codeinchaos.com/post/3645298058</guid><pubDate>Fri, 04 Mar 2011 18:19:00 -0500</pubDate><category>PHP</category><category>REST</category><category>Zend Framework</category><dc:creator>ahmadnassri</dc:creator></item><item><title>RESTful services with Zend Framework (Part 1)</title><description>&lt;p&gt;I previously &lt;a href="http://www.codeinchaos.com/post/3072516207/restful-zend-framework" target="_blank"&gt;wrote&lt;/a&gt; about the opensource project I&amp;#8217;ve created: &lt;a href="https://github.com/codeinchaos/restful-zend-framework" target="_blank"&gt;RESTful Zend Framework&lt;/a&gt; which is a custom Zend Framework Application built to act as a &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank"&gt;REST&lt;/a&gt; API.&lt;/p&gt;

&lt;p&gt;This is the first of couple of follow up articles describing how I built the REST implementation from scratch.&lt;/p&gt;

&lt;h2&gt;Some Assumptions:&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m going to skip the initial project creation and assume you already know the basics, if not, spend some time on &lt;a href="http://www.google.ca/search?q=Zend+Framework" target="_blank"&gt;Google&lt;/a&gt; figuring it out first (I don&amp;#8217;t recommend the ZF documentation since it&amp;#8217;s more confusing than helpful!)&lt;/p&gt;

&lt;p&gt;My entire application is meant to be a REST API, I don&amp;#8217;t have a mixed mode of web controllers and REST controllers, though it is easily possible to have both, with very little modifications to fit your needs once you read through the steps.&lt;/p&gt;

&lt;p&gt;I believe APIs should have maintainable revisions and as such I&amp;#8217;ve used &lt;a href="http://www.google.ca/search?q=Zend+Framework+Modules" target="_blank"&gt;Zend Framework Modules&lt;/a&gt; to separate my API revisions, again, its easy enough to skip that and suit your own needs.&lt;/p&gt;

&lt;h2&gt;Configuration:&lt;/h2&gt;

&lt;p&gt;As always, the first thing you&amp;#8217;d wanna do is customize your &lt;strong&gt;application.ini&lt;/strong&gt; file, here are the lines I&amp;#8217;ve added:&lt;/p&gt;

&lt;pre class="brush: text"&gt;
resources.frontController.defaultModule = "v1"
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.moduleControllerDirectoryName = "controllers"

resources.modules = ""
&lt;/pre&gt;

&lt;p&gt;You should also remove the following line from your &lt;strong&gt;application.ini&lt;/strong&gt; file, otherwise ZF will complain about missing Module Bootstrap calsses.&lt;/p&gt;

&lt;pre class="brush: text"&gt;
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
&lt;/pre&gt;

&lt;p&gt;This will enable Modules in your Application and setup the default module name as &amp;#8220;v1&amp;#8221;. (At this point you would want to re-organize your directory structure to accommodate modules.)&lt;/p&gt;
&lt;p&gt;You can skip this step if you don&amp;#8217;t want Modules as part of your Application.&lt;/p&gt;

&lt;h2&gt;Setting up the REST Route:&lt;/h2&gt;
&lt;p&gt;Now we need to setup routing, ZF comes with its own REST route, so lets make sure all our controllers are setup to go through it by adding the following to our &lt;strong&gt;application.ini&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: text"&gt;
resources.router.routes.rest.type = Zend_Rest_Route
&lt;/pre&gt;

&lt;p&gt;The REST route controls the URL scheme for our application, more on that later.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: this method will apply the REST route to &lt;strong&gt;ALL&lt;/strong&gt; controllers If you are thinking of having a mix of REST controllers and regular Zend_Action_Controller you need to customize the route rules by initiating it in your &lt;strong&gt;Bootstrap.php&lt;/strong&gt; instead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At this point, some clean-up of your application directory is probably a good idea &amp;#8230;&lt;br/&gt;depending on your set-up of the REST route, you might want to delete the &lt;strong&gt;views&lt;/strong&gt; folder if you apply REST to all your controllers.&lt;br/&gt;I created a new folder named &amp;#8220;&lt;strong&gt;v1&lt;/strong&gt;&amp;#8221; under &lt;strong&gt;application/modules&lt;/strong&gt;to match my module setup, and moved the &lt;strong&gt;controllers&lt;/strong&gt; &amp;amp; &lt;strong&gt;models&lt;/strong&gt; folders into it.&lt;/p&gt;

&lt;h2&gt;Controllers vs. Resources&lt;/h2&gt;

&lt;p&gt;In a typical ZF Application you would want to have your controllers extend Zend_Controller_Action, but in this case, we want them to extend Zend_Rest_Controller.&lt;/p&gt;

&lt;pre class="brush: php"&gt;
class FooController extends Zend_Rest_Controller
&lt;/pre&gt;

&lt;p&gt;Zend_Rest_Controller is just an abstract controller with a list of predefined Actions that we should implement in each of our Controllers:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
class FooController extends Zend_Rest_Controller
{
    public function indexAction()
    {}

    public function getAction()
    {}

    public function postAction()
    {}

    public function putAction()
    {}

    public function deleteAction()
    {}
}
&lt;/pre&gt;

&lt;p&gt;The first thing you&amp;#8217;ll notice is that the Actions represent the most basic HTTP Methods: GET, POST, PUT and DELETE which are the core of our RESTful implementation. at this point you should start thinking of your Controllers as Resources (you might wanna &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank"&gt;read up on REST&lt;/a&gt; to clearify this bit)&lt;br/&gt;Also, we didn&amp;#8217;t create any view scripts for this Controller, and as we are not going to need the view renderer anymore, lets disable it:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
public function init()
{
    $this-&amp;gt;_helper-&amp;gt;viewRenderer-&amp;gt;setNoRender(true);
}
&lt;/pre&gt;

&lt;p&gt;this is a temporary solution and will only disable the view rendered for this controller, we eventually want to disable it for all our REST controllers (covered in later steps).&lt;/p&gt;

&lt;p&gt;Now lets add some response output and give it a go!&lt;/p&gt;

&lt;pre class="brush: php"&gt;
public function indexAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('Hello World');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function getAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('Foo!');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function postAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('resource created');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function putAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('resource updated');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function deleteAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('resource deleted');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}
&lt;/pre&gt;

&lt;p&gt;We test this by using CURL in the command line:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
curl -v http://localhost/v1/foo
curl -v -X GET http://localhost/v1/foo/id
curl -v -X POST http://localhost/v1/foo
curl -v -X PUT -d '' http://localhost/v1/foo/id
curl -v -X DELETE http://localhost/v1/foo/id
&lt;/pre&gt;

&lt;p&gt;you&amp;#8217;ll notice that I&amp;#8217;ve added /id to GET, PUT, DELETE. This is by design of course, remember the REST route you setup earlier? well this is where it comes to play! now that you are creating &lt;strong&gt;Resources&lt;/strong&gt; not controllers, there are no need for any other actions other than to CREATE, READ, UPDATE &amp;amp; DELETE individual resources, otherwise known as &lt;a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete" target="_blank"&gt;CRUD&lt;/a&gt; and naturally: READ, UPDATE &amp;amp; DELETE require a resource identifier so Zend_Rest_Route takes care of mapping the URLs to match. here&amp;#8217;s the breakdown of how the HTTP methods map to CRUD functions:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;strong&gt;POST&lt;/strong&gt; = CREATE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; = READ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PUT&lt;/strong&gt; = UPDATE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DELETE&lt;/strong&gt; = that&amp;#8217;s right, you guessed it! DELETE!&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;That leaves one: The index action handles index/list requests; it should respond with a list of the requested resources.&lt;/p&gt;

&lt;p&gt;Now lets modify our logic to give a proper REST response:&lt;/p&gt;

&lt;pre class="brush: php"&gt;
public function indexAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('List of Resources');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function getAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody(sprintf('Resource #%s', $this-&amp;gt;_getParam('id')));
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}

public function postAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody('Resource Created');
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(201);
}

public function putAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody(sprintf('Resource #%s Updated', $this-&amp;gt;_getParam('id')));
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(201);
}

public function deleteAction()
{
    $this-&amp;gt;getResponse()-&amp;gt;setBody(sprintf('Resource #%s Deleted', $this-&amp;gt;_getParam('id')));
    $this-&amp;gt;getResponse()-&amp;gt;setHttpResponseCode(200);
}
&lt;/pre&gt;

&lt;p&gt;Now lets test again:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
curl -v http://localhost/v1/foo
curl -v -X GET http://localhost/v1/foo/1
curl -v -X POST http://localhost/v1/foo
curl -v -X PUT -d '' http://localhost/v1/foo/1
curl -v -X DELETE http://localhost/v1/foo/1
&lt;/pre&gt;

&lt;p&gt;There, nice and clean RESTful response!&lt;/p&gt;

&lt;p&gt;Now lets add some more HTTP Mehods beyond the basic GET, POST, PUT, DELETE.&lt;br/&gt;Two very popular HTTP methods are: HEAD and OPTIONS.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;OPTIONS&lt;/strong&gt; method represents a request for information about the communication options available on the request/response chain identified by the Request-URI.&lt;br/&gt;This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;HEAD&lt;/strong&gt; method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification (cache).&lt;/p&gt;

&lt;p&gt;Zend_Rest_Controller does not force any methods other than ones we&amp;#8217;ve already used, and since HEAD and OPTIONS in my example behave the same across all controllers, lets create a new Class &lt;strong&gt;REST_Controller&lt;/strong&gt; and implement the optionsAction and headAction there.&lt;/p&gt;

&lt;p&gt;First step is to add the custom REST_ namespace to our application.ini:&lt;/p&gt;
&lt;pre class="brush: text"&gt;
autoloaderNamespaces.rest = "REST_"
&lt;/pre&gt;

&lt;p&gt;the REST_Controller class should look something like this:&lt;/p&gt;
&lt;pre class="brush: php"&gt;
abstract class REST_Controller extends Zend_Rest_Controller
{
    public function headAction()
    {
        // you should add your own logic here to check for cache headers from the request
        $this-&amp;gt;getResponse()-&amp;gt;setBody(null);
    }

    public function optionsAction()
    {
        $this-&amp;gt;getResponse()-&amp;gt;setBody(null);
        $this-&amp;gt;getResponse()-&amp;gt;setHeader('Allow', 'OPTIONS, HEAD, INDEX, GET, POST, PUT, DELETE');
    }
}
&lt;/pre&gt;

&lt;p&gt;now lets make sure our FooController extends the newly created class:&lt;/p&gt;&lt;pre class="brush: php"&gt;
class FooController extends REST_Controller
&lt;/pre&gt;

&lt;p&gt;Now lets test the new actions:&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
curl -v -X HEAD http://localhost/v1/foo
curl -v -X OPTIONS http://localhost/v1/foo/1
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Update [Friday, 04 March 2011]:&lt;/strong&gt; using application.ini to setup the REST route, added OPTIONS, HEAD actions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update [Sunday, 01 January 2012]:&lt;/strong&gt; This article is out of date, please refer to the &lt;a href="https://github.com/codeinchaos/restful-zend-framework" target="_blank"&gt;GitHub repo&lt;/a&gt; for updated instructions, the same principles still apply, but with some changes and slight modifications.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="http://www.codeinchaos.com/post/3645298058/restful-services-with-zend-framework-part-2" target="_blank"&gt;next part&lt;/a&gt; I&amp;#8217;ll explain how to add context switching and add multi format input/output&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; all examples used are part of &lt;a href="https://github.com/codeinchaos/restful-zend-framework" target="_blank"&gt;RESTful Zend Framework on GitHub&lt;/a&gt;&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/3107629294</link><guid>http://www.codeinchaos.com/post/3107629294</guid><pubDate>Fri, 04 Feb 2011 13:34:00 -0500</pubDate><category>PHP</category><category>REST</category><category>Zend Framework</category><dc:creator>ahmadnassri</dc:creator></item><item><title>RESTful Zend Framework</title><description>&lt;p&gt;This seems to be one of the most obscure topics on the web, building a RESTful Application or Services with Zend Framework, I&amp;#8217;ve spent a lot of time researching different solutions and eventually came up with the perfect one, but that was a long time ago and ever since, I&amp;#8217;ve had to re-trace my steps every time I need to create RESTful services with ZF.&lt;/p&gt;

&lt;p&gt;So to make my life easier and to contribute something back to the community, I&amp;#8217;ve collected my RESTful implementation of Zend Framework and created a &lt;a href="http://code.google.com/p/restful-zend-framework/" target="_blank"&gt;Google Code Project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will be posting a follow up article describing the steps in which you can re-create the same solution, which should serve a good documentation of the source code.&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/3072516207</link><guid>http://www.codeinchaos.com/post/3072516207</guid><pubDate>Wed, 02 Feb 2011 15:17:00 -0500</pubDate><category>PHP</category><category>REST</category><category>Zend Framework</category><dc:creator>ahmadnassri</dc:creator></item><item><title>Hello World!</title><description>&lt;p&gt;Being in the Tech industry, and since we&amp;#8217;re all hardcore geeks, it&amp;#8217;s obligatory to start our blog with the traditional &amp;#8220;&lt;a href="http://en.wikipedia.org/wiki/Hello_world_program" target="_blank"&gt;Hello World&lt;/a&gt;&amp;#8221; which carries a sense of adventure for us! after all, every project starts with a few lines of code that print out &amp;#8220;Hello World&amp;#8221;.&lt;/p&gt;

&lt;p&gt;World, say hello to &lt;span class="name"&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Code:in&lt;/span&gt; &lt;span&gt;Chaos&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;[queue awesomeness]&lt;/p&gt;</description><link>http://www.codeinchaos.com/post/2858281276</link><guid>http://www.codeinchaos.com/post/2858281276</guid><pubDate>Fri, 21 Jan 2011 11:59:00 -0500</pubDate><category>Hello World</category><dc:creator>ahmadnassri</dc:creator></item></channel></rss>

