- Published on
CakePHP REST Plugin Presentation
- Authors

- Name
- Kevin van Zonneveld
- @kvz
At our company we have a lot of uses for a solid API. We can use it to distribute config files, have servers report in, let customers edit DNS records using their own interface, etc.
Now that I'm converting all of our legacy code to a big CakePHP application, the API needed a revisit as well. I chose to use REST as a standard, read about everything related to Cake & REST, and started hacking on a reusable plugin. The idea is that you can drop it in any application and unlock existing functionality to REST with minimal changes to your code.
It is still a work in progress, but as the first Dutch CakePHP event was held yesterday and I was asked to present something I thought this particular plugin might be of interest to the community. Here are the slides:
CakePHP REST Plugin from Kevin van Zonneveld
View on slideshare
And here's the source & documentation on github
I would love some feedback to help make it better. My todos can be found in the slides as well, to give you an idea where I'm heading with this.
More Info on the Dutch CakePHP Event
Legacy Comments (49)
These comments were imported from the previous blog system (Disqus).
Hi Kevin,
This plug-in is exactly what I\'m searching for. Will try it out today and when I have time I will return to give a feedback.
One thing I do not understand so far is, how to call this from a browser. Is it like:
www.hostname.com/rest/<mode... ???
And how to select whether to output to JSON or XML. As I see in the code XML is there in many places.
Thanks,
Regards,
Tamas
@ Tamas Jozsa: Hey. No you tie it in with existing controllers & actions. So if you already have:
/posts/view/1
you could add the Rest component to your PostsController and then you could do
/posts/view/1.json
to get the same data but in json format and with additional features like authentication
Hello
Thanks for your plugin. I have a products controller with index action working fine. When I added Rest.Rest component in my products controller I got \"Error: The requested address \'/products\' was not found on this server.\" for /products
And /products.xml give me\" XML Parsing Error: no element found\"
When I disable Rest.Rest component, /products are working fine. Can you tell me what\'s wrong?
Another thing, Do I have to place any additional code in index() action?
Many Thanks
@ gkibria: Only .json is supported for now. You should try that.
No the trick is you
[CODE=\"PHP\"]
$this->set(\'name\', \'gkibria\');
[/CODE]
like you would normally with your index()
Only the restcomponent can take the viewVars you specify, maybe even convert them into another (more rest-consistent) format, and them json_encode them.
XML serialization is being worked on.
Thanks for info. But when I enable Rest.Rest component in products controller, I can\'t browse neither /products/index nor /products/index.json and after disable the component it works fine. any idea?
And Here is my index()
[CODE=\"php\"]
function index() {
$this->Product->recursive = 0;
$this->set(\'products\', $this->paginate());
}
[/CODE]
my cake_core is 1.25 thanks
@ gkibria: Did you make the necessary parseExtensions adjustments in your router so that Cake will try to parse json?
Your index is fine.
If in that controller you specify:
[CODE=\"PHP\"]
public $components = array(
\'Rest.Rest\' => array(
\'debug\' => 1,
\'index\' => array(
\'extract\' => array(\'products\' => \'myProducts\'),
),
),
);
[/CODE]
It should show you the contents of products under \'myProducts\' in json format, when you browse to /index.json
Kevin,
Thank you very much for this plugin! I am a bit confused about the authentication. Does this plugin actually handle the Amazon-style authentication and return the appropriate HTTP response codes? Or, does it simply parse out the Amazon-style Header:
`Authorization: TRUEREST username=john&password=xxx&apikey=247b5a2f72df375279573f2746686daa`
into an array that can then be used effectively with some other security component?
Thanks,
Steve
@ steve: Hey, no your app still handles the authentication, that\'s what makes it flexible. But it parses the string for you and inside your login procedure you just check for it with
[CODE=\"php\"]
$this->Rest->credentials();
[/CODE]
as (kind of) explained on: http://github.com/kvz/cakep...
Kevin thanks for the reply! Do you have any hints on how I could handle this Amazon Authentication... Do you happen to have an expample I could see?
I am building a REST API now, and I could use all the advice I could get.
Thanks!
Steve
Hi... I figured out how to implement 2-legged OAuth with my API, but I now have another issue that I can\'t figure out. Have you ever executed a HTTP PUT with files? I keep getting 413 errors when send when I try to PUT anything to my API. Here are what the headers look like, any advice?:
[0] => Content-Disposition: attachment; filename=\"DSC01264.JPG\"
[1] => Content-Type: application/octet-stream
[2] => Content-Length: 64250
[3] => Authorization: OAuth realm=\"\", oauth_requester_id=\"720\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"Rom3hREK8p2PzMBXdzIJb3hy%2FF0%3D\", oauth_nonce=\"4c210a01d83d9\", oauth_timestamp=\"1277233665\", oauth_token=\"\", oauth_consumer_key=\"1385adb7be6ade0a0bf7d5493fd0722404c1795eb\", oauth_version=\"1.0\", xoauth_body_signature=\"8ap46NO3buRxIbzAtFc5OFa6FNY%3D\"
thanks,
Steve
@ steve: Look like it\'s your webserver: http://www.checkupdown.com/...
Furthermore, you may find the clien-side of this API interesting that I developed for my company:
http://github.com/true/true...
This REST plugin for cakephp is exactly what the Dr ordered. Does it indeed work for cakephp version 1.3 as well?
@ Paul Winkeler: Haven't tested it yet, in fact it's one of the last todos.
But if you feel like giving it a spin.. I'd be happy to learn your findings / accept your patches.
@ Paul Winkeler: Happy to announce my plugin now supports Cake 1.3!
Hi Kevin,
Great plugin!
Just wanted to say I was only able to get it working after creating the rest_logs table (using the sql in config/schema/rest_logs.sql) - if I didn't do that, I got a Page not found error message when attempting to get the .json version.
Might be helpful for anyone else experiencing the same issue.
Chris
@ Chris: Thanks, I've updated the readme file accordingly!
Hi,
i tried your plugin, but when i go to .xml or .json, i always got an error view not found.
Do i have to create views for xml and json?
I need to implement 2-legged oauth in my api with cakephp, if someone can help me.
Hi Kevin,
This will significant simplify my development, if I can get it to work.
Unfortunately, I'm getting the same results as Cazze. Whenver I try to access a .json or .xml, I get a "Missing View" error saying I need to create xml/index.ctp and json/index.ctp files.
I'm using Cake 1.3.6. Is there an incompatibility with this version?
Hi Kevin,
i am getting this Fatal error: Class 'XmlView' not found in D:\xampp\htdocs\ltf\cake\libs\controller\controller.php on line 775, and i am unable to debug it.
"A check if REST is active inside your error handler"
Can you provide a code sample for this? Slide #14 touches on this but I can't figure out to code it.
My problem is that code errors (not api call errors) get output in XML/JSON so debugging is messy.
Ideally code errors would cause rest output to deactivate and output the errors in regular HTML (instead of invalid xml/json).
Thanks!
Really nice work Kevin!
But I have same problem Cazza and Gary have, do we miss something?
Do you guys got this problem and managed to resolve?
Thanks in advance.
same issue here as Marco, Cazza and Gary
using CakePHP 1.3.7
@ luqash, Marco, Cazza, Gary: I've been investigating a bit. Could it be that you're not setting an Auth keyword in your client request headers? The component is now configured to let Cake handle it. So normal Cake would throw view not found.
This behavior is configurable but I changed the default:
https://github.com/kvz/cake...
Let me know if that helps!
Yes, it's working for me now that you've disabled the Auth by default.
Thanks!
@ Carlos: What I meant was, inside your normal error handler, do a check for rest and then e.g. output: json_encode(array('error' => $errmsg))
I'm trying to get the plugin to work using an add function (all GET requests work great) but when I send some data to be POSTed $this->data is empty. I'm trying to do it via AJAX w/ JQuery. I've tried xml and json but maybe I just don't know how. Could you help me out?
I've got the same problem than @Juan.
When I use the REST component, for ADD action $this->data is empty (it works fine when i don't use this component).
ps : sorry for my english, i'm french
I found, just comment the line $this->headers(); at the end of the initialize function.
This line are not important because the problem the function headers() want to fixe isn't a problem. The header are good when your debug level is 0 (both REST and Core).
Hey Kevin,
With CakePHP 1.3.8. running (fresh install) I tried to get your Rest plugin into action. But I'm getting errors when I try to access .json or .xml via browser.
I have the mapResources set and the parseExtensions etc, like your install notes says.
The parsing via the browser seems to handle the content-type well, like for xml and json, but the content itself are errors only..
Thanks, Florus
@ Freddy & Juan: Are you sure you are nesting the data correctly? e.g. inside proper model names? What about dumping $_POST? Does that give you any clues?
@ Florus: That's not really enough information to go on, sorry.
Hello Kevin, thanks for this nice piece of code, i've been using this for the past hours for a service that im working on and it is great.
But like some other people asked here, i would like to see an example of how to deal with checking if rest is enabled inside my error handler.
Right now i have a custom subclass of errorHandler for my custom errors, and unless i send a reference to the calling controller to my custom error function, i can not figure out how to get a reference to the Rest plugin, could you post some actual code example on how you dealt with this ?
Thanks.
Diego.
Hi Kevin, forgive my ignorance: what does your plugin do that the built-in Cakephp REST does not provide?
http://book.cakephp.org/vie...
As far as I can tell:
- authentication
- json support
- rate limiting
- logging
Did I miss anything?
This plugin is great! however I am super confused on how to authenticate. I read the amazon S3 authentication docs and I am still confused. Can you or someone post example of how to get a JSON response with authentication. I tried to follow the directions in the documentation but I remain bewildered. I am new to REST and JSON so more information would be much appreciated.
Great plugin! 2 issues I found with the current documentation when I was testing:
1. In Authorization the example does not set $credentials
[CODE="Javascript"]
// Try to login user via REST
if ($this->Rest->isActive()) {
$credentials = $this->Rest->credentials();
...
[/CODE]
2. The 2 examples in Usage are not in the new format ie. contained in an 'action' array. They should read
[CODE="Javascript"]
'Rest.Rest' => array(
'catchredir' => true, // Recommended unless you implement something yourself
'debug' => 0,
'actions' => array(
'view' => array(
'extract' => array('server.Server' => 'servers.0'),
),
'index' => array(
'extract' => array('rows.{n}.Server' => 'servers'),
),
),
),
...
[/CODE]
and
[CODE="Javascript"]
'Rest.Rest' => array(
'catchredir' => true,
'actions'=> array(
'extract' => array(
'index' => array('tweets'),
),
),
),
...
[/CODE]
Just makes it a lot easier to get going quickly!
hi, i don't understand how to implement REST in cake 1.3.x.x
can you help me how to create REST plugin in cake step by step???
Hi Kevin,
This is THE plugin I am dreaming of! It allows me to systematically convert existing cake app to REST based.
To test, I am using one of my cake app and play around with User Controller.
I have follow every step you mentioned in your read me etc, and read thru all comments, but I can't seems to get the right.
Currently, no authentication is implemented, just to make it as simple as possible until I get the desired result.
Below is the problem
My data is always empty, as shown below
{"data":[],"meta":{"status":"ok","feedback":[],"request":{"http_host":"127.0.0.1","http_user_agent":"Rested 2.0.1 (Macintosh; Mac OS X 10.7.2; en_MY)","server_addr":"127.0.0.1","remote_addr":"127.0.0.1","server_protocol":"HTTP\/1.1","request_method":"GET","request_uri":"\/ap5\/users\/index.json","request_time":1321202674},"credentials":{"class":null,"apikey":null,"username":null},"time_epoch":"1321202674","time_local":"Mon, 14 Nov 2011 00:44:34 +0800","version":"0.3"}}
Appreciate if you can point me to the solution.
component settings as below:
'Rest.Rest'=>array(
'catchredir' => false, // Recommended unless you implement something yourself
//'debug' => 2,
'view' => array(
'extract' => array('user'),
),
'index' => array(
'extract' => array('users'),
),
'ratelimit'=>false,
'log'=>null,
'extensions' => array('xml', 'json', 'csv'),
),
Users Controller index function
function index() {
$this->User->recursive = 0;
$users=$this->User->find('all');
//$this->set('users', $this->paginate());
$this->set(compact('users'));
debug($users);
}
thank you in advance
Am having same problem as chiacy and others - no data.
I have updated my controller to use actions => array but this only gives me {"data":{"mythings":[null]}...}
Any help most appreciated. Great plugin, thank you for opening it up (I have used it before on other sites - not sure why is not working now!).
I got it!
changes made here:
'actions'=>array(
'index' => array(
'extract' => array('users'),
),
),
instead of just
'index' => array(
'extract' => array('users'),
),
Thank you!!!
Back again with problem on Authentication.
I tried the authentication, first, I do not know how apikey is generated, but that's not really a matter.
What matters me is that once a client logged in with correct KEYWORD, username and password, and when trying to access subsequently the same site from the same client, as long as KEYWORD is correct, even without username and password, I can still access to the data.
I wonder if this is due to cookies, but I have disabled cookie from my cakephp component to eliminate the possibility, no good result.
Anyone out the can help pointing out I have done wrong?
added the following to component settings:
'onlyActiveWithAuth'=>true,
'catchredir' => false,
both either true or false, no effect.
before filter function of the controller
if (!$this->Auth->user()) {
// Try to login user via REST
if ($this->Rest->isActive()) {
$credentials=$this->Rest->credentials();
$this->Auth->autoRedirect = false;
$data = array(
$this->Auth->userModel => array(
'username' => $credentials['username'],
'password' => $credentials['password'],
),
);
$data = $this->Auth->hashPasswords($data);
if (!$this->Auth->login($data)) {
$msg = sprintf('Unable to log you in with the supplied credentials. ');
return $this->Rest->abort(array('status' => '403', 'error' => $msg));
}
}
}
Thanks
Hi, just trying to get this working. I thought I had everything but I get the following error: The requested address '/prospects/links.json' was not found on this server.
My controller code is
[code="PHP"]
public $components = array(
'RequestHandler',
'Rest.Rest' => array(
'catchredir' => true, // Recommended unless you implement something yourself
'debug' => 0,
'view' => array(
'extract' => array('server.Server' => 'servers.0'),
),
'index' => array(
'extract' => array('rows.{n}.Server' => 'servers'),
),
),
);
function links(){
$this->autoRender = false;
$this->autoLayout = false;
//var_dump($this->Rest->credentials());
//var_dump($this->Rest->isActive()); die();
Configure::write('debug',0);
$conditions = array('conditions'=>array('user_id'=>1));
$arr = $this->Prospect->find('all',$conditions);
$this->set('json',$arr);
$this->set(compact('json'));
}
[/code]
My htaccess looks like:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
# Adds AUTH support to Rest Plugin:
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
</IfModule>
And my routes.php is
[code="PHP"]
Router::mapResources(array('Prospects'));
// Add XML + JSON to your parseExtensions
Router::parseExtensions('json','xml');
[/code]
I figured my problem out after reading deeper into the comments. I was not defining which controller actions I wanted to expose.
[code="php"]
'actions'=>array(
'index'=>array(
'extract'=>array('prospects')
)
)
[/code]
That will make it work on function index() and json/xml encode the $prospects array.
What would it take to get this to work with CakePHP 2.0?
@ Gary: There is a 2.0 branch that works just fine for us
Hi,
I am facing problem while using POST method of rest API component. Am using below function to add data in database, its working fine in view but not with API.
[CODE="php"]
public function add() {
$this->layout = 'dashboard';
if ($this->request->is('post')) {
//print_r($this->request->data);exit;
$this->request->data['List']['user_id'] = $this->Auth->user('id');
if ($this->List->save($this->request->data)) {
$this->Session->setFlash('Your List has been saved.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to add your List.');
}
}
}
[/CODE]
I have tried commenting redirect method as well as auth component call in order to check but still its not working. your help will be highly appreciated. Also let me know which data format should i give in request body while executing API?
Thanks in advance!!!
Can you make short video tutorial of your rest plugin? This would realy helpful specialy for cake beginners.
How can i use this cakephp 2.0 ?, I am unable to get any material which can help me to configure this plugin with cakephp 2.0.
Hi, Can you please give us a small explanation/example on how to use the plugin in an add() method? I am struggling with this quite a lot.
Ok, I figured out how to do a post:
Set the header's Authorization as suggested in the post. Set Content-type: text/xml
and put your xml in the body:
<item>
<field1/>
<field2/>
.........
</item>
The request URL is your controller add/save or whatever method but with .xml or .json appended: controller/add.xml
Then in this add method in the controller do
if ($this->Rest->isActive())
$this->Rest->postData = $this->data;
Now test with sample data, You should get back the data variable with an id of the new record inserted into it.
Cheers