Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cakephp - If Request is JSON?

Tags:

json

cakephp

I have read the RequestHandler part in cookbook. There are isXml(), isRss(), etc. But there's no isJson().

Any other way to check whether a request is JSON?

So when the url is mysite.com/products/view/1.json it will give JSON data, but without .json it will give the HTML View.

Thanks

like image 414
hrsetyono Avatar asked Jun 12 '13 03:06

hrsetyono


2 Answers

I dont think cakePHP has some function like isJson() for json data, you could create your custom though, like:

//may be in your app controller
function isJson($data) {
  return (json_decode($data) != NULL) ? true : false; 
}
//and you can use it in your controller
if( $this->isJson($your_request_data) ) {
 ... 
}

Added: if you want to check .json extension and process accordingly, then you could do in your controller:

$this->request->params['ext']; //which would give you 'json' if you have .json extension
like image 52
Sudhir Bastakoti Avatar answered Sep 21 '22 14:09

Sudhir Bastakoti


CakePHP is handling this correctly, because JSON is a response type and not a type of request. The terms request and response might be causing some confusing. The request object represents the header information of the HTTP request sent to the server. A browser usually sends POST or GET requests to a server, and those requests can not be formatted as JSON. So it's not possible for a request to be of type JSON.

With that said, the server can give a response of JSON and a browser can put in the request header that it supports a JSON response. So rather than check what the request was. Check what accepted responses are supported by the browser.

So instead of writing $this->request->isJson() you should write $this->request->accepts('application/json').

This information is ambiguously shown in the document here, but there is no reference see also links in the is(..) documentation. So many people look there first. Don't see JSON and assume something is missing.

If you want to use a request detector to check if the browser supports a JSON response, then you can easily add a one liner in your beforeFilter.

$this->request->addDetector('json',array('callback'=>function($req){return $req->accepts('application/json');}));

There is a risk associated with this approach, because a browser can send multiple response types as a possible response from the server. Including a wildcard for all types. So this limits you to only requests that indicate a JSON response is supported. Since JSON is a text format a type of text/plain is a valid response type for a browser expecting JSON.

We could modify our rule to include text/plain for JSON responses like this.

$this->request->addDetector('json',array('callback'=>function($req){
    return $req->accepts('application/json') || $req->accepts('text/plain');
}));

That would include text/plain requests as a JSON response type, but now we have a problem. Just because the browser supports a text/plain response doesn't mean it's expecting a JSON response.

This is why it's better to incorporate a naming convention into your URL to indicate a JSON response. You can use a .json file extension or a /json/controller/action prefix.

I prefer to use a named prefix for URLs. That allows you to create json_action methods in your controller. You can then create a detector for the prefix like this.

$this->request->addDetector('json',array('callback'=>function($req){return isset($req->params['prefix']) && $req->params['prefix'] == 'json';}));

Now that detector will always work correctly, but I argue it's an incorrect usage of detecting a JSON request. Since there is no such thing as a JSON request. Only JSON responses.

like image 44
Reactgular Avatar answered Sep 23 '22 14:09

Reactgular