jQuery has shortcut interfaces to their ajax functions for GET and POST request methods. The other two RESTful verbs can be called using the ajax functions directly, or you can create your own shortcuts.
I feel that using the shortcuts gives a supporting developer a better understanding of the flow, and how the front end communicates to the web services.
<script type="text/javascript"> function _ajax_request(url, data, callback, type, method) { if (jQuery.isFunction(data)) { callback = data; data = {}; } return jQuery.ajax({ type: method, url: url, data: data, success: callback, dataType: type }); } jQuery.extend({ put: function(url, data, callback, type) { return _ajax_request(url, data, callback, type, 'PUT'); }, del: function(url, data, callback, type) { return _ajax_request(url, data, callback, type, 'DELETE'); } }); </script>
So now you have your shortcuts established, we need to setup a form.
</p>
<form action="/service/user/">
<input type="text" name="name" value="" />
<input type="text" name="email" value="" />
<input type="text" name="twitter_acct" value="" />
<input id="gender[]" type="radio" name="gender" value="m" />
<input id="gender[]" type="radio" name="gender" value="f" />
<input id="ui-form-submit-ajax-method-put" type="submit" name="ui-admin-add-user" value=" Create User > " />
</form>
<p>We start with the document.ready (jQuery’s onreadystate function).
Disable all forms default behvior. Of course you can pick and choose to your liking which forms get this.
Then we add an “click” event trigger to all input[type=submit]. If you look at the HTML above you will see the method is in the id. A dash (-) separated namespace with the matching method to our shortcuts for jQuery.
jQuery(document).ready(function () { jQuery("form").submit(function (event) { event.preventDefault(); }); jQuery("input[type=submit]").click(function () { var method,wsUri,requestData; requestData = {}; method = jQuery(this).attr("id").toString().split("-").pop(); wsUri = jQuery(this).parents('form:first').attr("action"); jQuery(this).parents('form:first').find("input, select, textarea").each(function () { var inputType, dataName, dataVal; inputType = jQuery(this).attr("type"); if (inputType === "text" || inputType === "checkbox" || inputType === "radio") { dataName = jQuery(this).attr("name"); dataVal = jQuery(this).val(); if (dataVal != "") { requestData[dataName] = dataVal; } } inputType,dataName,dataVal = null; }); jQuery[method](wsUri,requestData,function (data, textStatus) { switch (data.responses[0].status.request_method) { case "GET": break; case "PUT": break; case "POST": break; case "DELETE": break; } }, 'json'); }); });
This is currently used with a simple web service patten in PHP that is easy to implement.
PHP Simple Web Service Pattern
.htaccess for pretty urls (apache and lighthttpd)
apache:
Options +FollowSymLinks RewriteEngine On RewriteCond %{SCRIPT_FILENAME} !-d RewriteCond %{SCRIPT_FILENAME} !-f RewriteRule ^.*$ ./index.php
lighttpd:
url.rewrite-once = ( "/(.*)\.(.*)" => "$0", "/(css|files|img|js|stats)/" => "$0", "^/([^.]+)$" => "/index.php/$1" )
Drop your .htaccess into the root of where you want your “app” to live.
Now your index.php is a very light controller, and should be fitted with more error checking and reporting, but you are capable of those details.
This script will consider everything after the base url of the script as parameters for the script.
My file structure is pretty simiple:
./
.htaccess
index.php
/assets
/css
/js
/php
/img
/views
home.phtml
service.phtml
<?php $request = str_replace ( array( str_replace("index.php","",$_SERVER['PHP_SELF']) , "?term=" ), "", $_SERVER['REQUEST_URI'] ); $params = split("/", $request); $viewPath = "./views/"; $viewExt = ".phtml"; /* redirect if not enough parameters are sent, quick work around that should have real error reporting */ if ( count($params) < 3 ) header ( "Location: ../index.html" ); $file = $viewPath . $params[1] . $viewExt; if ( file_exists($file) ) include_once ($file); ?>
We need a few classes for the example to work:
./assets/php/lib/class.ws_response.php :
<br />
<?php<br />
class ws_response<br />
{<br />
var $response;<br />
public function __construct()<br />
{<br />
$this->response->{'responses'} = array();<br />
}<br />
public function addResponse($responseMap)<br />
{<br />
foreach ($responseMap as $responseKey => $responseVal)<br />
{<br />
$response->{$responseKey} = $responseVal;<br />
}<br />
array_push($this->response->responses,$response);<br />
}<br />
public function getResponseAsJSON()<br />
{<br />
return json_encode($this->response);<br />
}<br />
}<br />
?><br />
./assets/php/lib/class.ws_status.php :
<?php class ws_status { var $statuses; public function ws_status() { } public static function addStatus($code, $message, $request_method, $type) { $status->{'code'} = $code; $status->{'message'} = $message; $status->{'request_method'} = $request_method; $status->{'type'} = $type; $status->{'http_headers'} = array(); return $status; } public function getStatus() { return $this->statuses; } public function getStatusAsJson() { return json_encode($this->statuses); } } ?>
Now let's look at service.phtml
<?php set_include_path(implode(PATH_SEPARATOR, array(realpath(dirname(__FILE__).'/../../assets/php/lib'),get_include_path(),))); require_once("class.database.mysql.php"); require_once("class.ws_response.php"); require_once("class.ws_status.php"); /* this is my simple web service response wrapper, it needs work */ $database = new database(); $response = new ws_response(); switch ($params[1]) { case 'itemById': switch ($_SERVER['REQUEST_METHOD']) { case 'GET': try { $sqlSet = "SELECT `items`.* FROM `items`" . ((count($params)>2 && !empty($params[2])) ? " WHERE `items_dev`.`id` = ".$params[2]:""); $item = $database->make_query($sqlSet); $item = count($item) === 1 ? array_shift($item):$item; $response->addResponse(array("status" => ws_status::addStatus(200,'success', $_SERVER['REQUEST_METHOD'],'screen'),$params[1] => $item)); } catch(Exception $e) { $response->addResponse(array("status" => ws_status::addStatus(500,'error: ' . $e->getMessage() , $_SERVER['REQUEST_METHOD'],'screen'),$params[1] => NULL)); } echo $response->getResponseAsJSON(); break; case 'POST': $len = count($_POST); $i = 0; $sqlSet = "UPDATE `items` SET "; foreach ($_POST as $name => $value) { if ($name != "id") { if ($i>0) $sqlSet.= ", "; $sqlSet.= "`".$name."` = "; $sqlSet.= (preg_match("/^\d/",$value)) ? mysql_escape_string($value):"'".mysql_escape_string($value)."'"; } $i++; } $sqlSet.= " WHERE `items_dev`.`id` = " . $params[2] . " ;"; try { if($database->make_query($sqlSet)) { $response->addResponse(array("status" => ws_status::addStatus(200,'success', $_SERVER['REQUEST_METHOD'],'screen'),$params[1] => "Item " . $params[2] . " has been updated.")); } else { $response->addResponse(array("status" => ws_status::addStatus(200,'success', $_SERVER['REQUEST_METHOD'],'screen'),$params[1] => "Item " . $params[2] . " was not updated.")); } } catch(Exception $e) { $response->addResponse(array("status" => ws_status::addStatus(500,'error: ' . $e->getMessage() , $_SERVER['REQUEST_METHOD'],'screen'),$params[1] => NULL)); } echo $response->getResponseAsJSON(); break; case 'PUT': /* ..code.. */ break; case 'DELETE': /* ..code.. */ break; } break; case 'service2': switch($_SERVER['REQUEST_METHOD']) { case 'DELETE': /* ..code.. */ break; case 'DELETE': /* ..code.. */ break; case 'PUT': /* ..code.. */ break; case 'DELETE': /* ..code.. */ break; } break; } ?>
That is the basics, as you can see the REQUEST METHOD is sent back in the status message, along with other useful information.
I welcome any feedback that improves on the basics here.
Comments (0) Just got checked in and am sitting in the room where Battle Deck is being held. Battle Deck is a karaoke style kamikaze presentation where your group gets up and has to improve a presentation to random slides. The slides are heavy on the anti-glen beck and vaginas. The slides are way better than the actual speakers. Best joke heard, “We need to get all the lighters back from Homeland Security and melt all the plastic people into the oil that America needs.”
These were the cont3stants…
And the winner was Josh A Cagan
Comments (0) After learning and laughing along with one of my favorite web comics – TheOatmeal.com’s comic 15 Things Worth Knowing About Coffee, I was inspired to search for and drink robusta coffee.
So I found some green non-roasted beans online and set out to not only try robusta (50% more caffeine than arabica), but to try my hand at roasting at home. Basically the roasting was a whole lot less than rocket surgery. Also I would like to thank my girlfriend, Annilee Ballentine for perfecting the roasting process with several more runs.
Part 1 – The Roast
Take your green beans, which cost half of what roasted beans cost, and place a quarter to half a cup onto a baking sheet. We found that an aerated pizza pan worked really well, but not that much better than a restaurant grade stamped aluminum sheet. Preheat your oven at 475 degrees, and then place the cooking tray of choice into the oven. Roast the beans at a high temperature for about 15 minutes, then drop the heat down to 375 degrees and roast until you reach the desired color.
This is basically the same process for rice, but you roast much longer. I think for our dark dark black beans, they sat in the oven for 4-6 hours.
Now selecting and roasting your own beans are only half the battle we found.
Part 2 – The Grind
We found that for the dark robusta in a either a press or a drip that finer than the normal suggested grind brought out a much richer, deeper flavor in the coffee. And this goes for most beans. If you have a grinder with specific settings for course, medium, and fine grinds, that playing around with in between settings may actually bring out more character to your coffee.
Part 3 – The Cup
As for the actually drinking of the robusta coffee, let me tell you that it is not for caffeine lightweights. Comments at work from, my eyes are twitching, to I am still up from yesterday, have followed a few pots that have been allowed to be brewed. So we have fallen back to blends, which is another post in itself.
Green Bean Resources
Well thanks for checking out my blog, which I think I finally have setup just in time to go to SXSW Interactive tomorrow. See you geeks there.
Comments (0)