I've installed Recess:
http://www.recessframework.org/
Configured the database, added a table, generated model and controller.
In video tutorial you can see author uses URI like ../something.json to get JSON results. I generated a profile class so i navigate to ../profile.json, but get an error:
Unable to provide desired content-type. Does the view XXX exist?
Basically what i need is a proper formed Restful JSON service for a use in Ember.js.
I would love it if Recess return JSON without adding .json.
Have anyone of you know how to make it work?
How to make a JSON Restful service with Recess properly?
Recess forum is down, so you are only help.
You need to modify the controller class to allow it output data in JSON format
/**
* !RespondsWith Json, Layouts
* !Prefix something/
*/
If you want to get rid of adding .json to the request URL - just leave Json as a single possible output:
/**
* !RespondsWith Json
* !Prefix something/
*/
See this link for the details
On the other hand, you are able to force the JSON output using Accept: application/json header in your HTTP requests, so no .json word should be added to the request URL. However, you still need to enable the Json output in your controller class.
Related
Alright so I'm trying to make some sense of all these patterns.
Alright, so I'm coding an applicantion in CodeIgniter which needs to be able to send data about a car and a customer to different types of companies using SOAP, maybe XML, comma-separated and so on.
But they all need the same thing.
I wanna make it as dynamic as possible and make sure it's easy to write tests.
So the service should take a couple of things:
a handler
applicants [1-2]
params
object
I started up creating different classes
Gr8Exp
NordCar
SwePerf
each implementing the interface iServiceRequest
interface iServiceRequest{
/**
* Send the request to the company server.
*/
function sendRequest();
/**
* Saves the response into the database.
*/
function saveResponse();
/**
* Prepares the request to the company, setting info from form and shit.
*/
function prepareRequest();
/**
* Soap, XML, CSV, JSON
* #param type $method
*/
function setRequestHandler(iServiceRequestHandler $handler);
}
Then they need to structure up the Soap, XML, CSV, JSON request depending on what handler i put in.
After those who needed to be validated (not all did) I used:
interface iAdaptServiceRequest{
/**
* Structure the array information and put it into an object structure in the right place.
*/
function structure(array $info);
/**
* Make all the checks for the function
*/
function validateInfo();
}
But I'm stuck, It worked really good when I just used SOAP request; but now. Since I need to format them differently, use a different handler for each type of request or company I don't know what to do.
I could put them i different folders and recreate the class in the different folders. But that's not a good practice since I'm duplicating code all over.
In the end I want to run some chaining like this:
$result = $m->prepareRequest()->sendRequest()->saveResponse();
Any suggestions??
IMHO:
-- create/use a front controller.
-- The front controller determines which request handler to use (JSON, SOAP, XML, etc).
-- The request handler generates a common "Request" object that behaves the same across all interfaces, basically putting variables into a common named format inside a "Request object"
-- It determines which service to send the request to and sends the request object there
-- The service processes the request object and generates a response object
-- The controller creates an appropriate (JSON/SOAP/XML) View object to process the response object into the correct view type and the View outputs your response as that type.
I would use something like yours: $result = $m->prepareRequest('JSON')->sendRequest()->saveResponse();, but specifing what format of data I'm sending.
The method prepareRequest(string $type) would check the format and call another method to convert your data to the respective format.
Something like this:
function prepareRequest(string $type){
if ($type == 'json'){
$this->convert2json();
}
if ($type == 'xml'){
$this->convert2xml();
}
// And so on
}
There is often confusion about the MVC or Observer pattern. This is not a situation in which this pattern is applicable. In the MVC pattern are the View and Model related to one another. The View must update itself based on information of the subject. A view and the underlying tables in a database are a good example. That is not what you want here.
The design pattern which suits this problem is the Builder pattern. The Builder pattern consists of four cooperating classtypes:
1. a Builder,
2. a ReaderManager,
3. a ConverterManager, and
4. a DataObject.
The ReaderManager is using the Interpreter pattern. Conversion can be done using the State pattern. What is the output of the ReaderManager (some DataObject) is the input for the ConversionManager. That can be done using an abstract class instead of an interface (my preference for data focused classes). The Builder connects the ReaderManager with the ConverterManager and takes care of the transport of data.
Some years ago I wrote about design patterns. The builder pattern was one of the patterns I described and this is the link to that page:
http://www.loekbergman.nl/InsideArchitecture/TheProcess/DesignPatterns/Builder
It shows a UML diagram of the pattern.
In the next link you can download a jar with some examples of design patterns. One of them the builder pattern:
http://www.loekbergman.nl/InsideArchitecture/DownloadsAndLicense
I have written this code several years ago, therefor do I give you this code without warranty. (Is that the correct term in this context?)
In the code you can see a folder with the name specifications. That is another example of the Interpreter pattern. (In the Builder pattern there is of course also an example of this pattern).
To be complete is here the link to the MVC - pattern:
http://www.loekbergman.nl/InsideArchitecture/TheProcess/DesignPatterns/Observer
and the Interpreter pattern:
http://www.loekbergman.nl/InsideArchitecture/TheProcess/DesignPatterns/Interpreter
In Zend Framework 2, content negotiation happens on the view layer and I am pretty happy with it. An example in my controller:
public function viewAction()
{
$id = $this->params('id');
$user = $this->getRepository()->findUser();
return new ViewModel(array(
'user' => $user,
));
}
This either renders the view.phtml template to return html or it converts the user object to a JSON response. A so-called view strategy determines how to render the response based on the request.
"REST" Application Flow in my webapp
This type of content negotiation works pretty good for many use cases:
/user or indexAction() returns an array of users => html of JSON possible;
/user/1 or viewAction() returns user object => html or JSON possible (example from above);
/user/1/update or updateAction() returns a html form. A POST to this url returns html or JSON when errors are present. Or on success it redirects to viewAction() and thus returns the new version of the user => html and JSON again possible;
/user/create or createAction() returns a html form. A POST to this url returns html or JSON when errors are present. Or on success it redirects to viewAction() for the just created user => html and JSON again possible
My Question
There are a few use cases where the content negotiation is sort-of "required" in the controller layer. I am not sure if I overlook some possibilities: are there options I can use in for example the following cases?
Delete a user: POST to the /user/1/delete. In case of a html view, you will be redirected to the list of users (where the deleted user is now missing). In case you want a JSON response, you want to return 200 OK and a JSON object with a message the delete was successful.
Post a comment to a blog article. In case of a html view, you will be redirected to the post where you see your comment is appended. In case you ask for a JSON response, you want to return 200 OK and a JSON object with the comment you just placed.
My goal would be to not replicate the content negotiation already present in the view layer. It would also make my controllers more fat, since I have now two possible responses (JSON vs html) but that might not be the only case. If I later want to support XML or another format, I have for every action switches for those response types.
Interestingly, we're looking currently at moving the content negotiation aspect out of the view strategy listeners, and instead into controller plugins. The rationale is largely as you note -- it's the controller's job to match an incoming request to the appropriate model(s) and view. As such, yes, I think you're on the right track -- and likely the tools being developed now for 2.1 will fit the methodologies you have quite nicely. (See https://github.com/zendframework/zf2/pull/2615 for details.)
I have a simple CakePHP application that allows a user to create and edit posts. And I'm looking to get the application into PhoneGap at some point in the future.
Therefore I have created an API that spits out JSON for use in AJAX requests, but I get the feeling I'm doing it wrong as I'm not using REST or doing anything any different that sets it apart from other code in the controller.
e.g. (NOTE: I'm missing the part about turning it into JSON for this example)
class ApiController extends AppController {
function index() {
$posts= $this->Post->find('all');
$this->set(compact('posts'));
}
}
To create a url like: domain.com/api/posts/all (would create custom route to achieve this) which I can then call using AJAX to use in my mobile app.
Now my question is what differently would doing it using REST be? I'm very much a newbie to building applications and my strengths are in front-end rather than back-end development so any pointers, help with this would be much appreciated.
Turning on REST in CakePHP basically routes proper HTTP methods to actions. So, a GET request would be routed to an index or view action, a DELETE request routed to the delete action, and so forth.
This creates a very easy endpoint for people using your API. Then when calling this endpoint, depending on the HTTP method Cake will route it to the proper action (forgive any HTTP request syntax errors):
// single endpoint
http://example.com/api/posts
A GET request that routes to /posts/index.json
GET /api/posts.json HTTP/1.1
Host: example.com
A POST request that routes to /posts/edit/1.json
POST /api/posts/1.json HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 24
data[Post][name]=updated
Reading this will answer most of your questions: http://book.cakephp.org/2.0/en/development/rest.html
If your concern is to be true to the Rest principals.
Then, there are usually 4 points to keep in mind:
Base URI for the web service
The Internet media type of the data supported by the web service.
This is often JSON, XML or YAML but can be any other valid Internet
media type.
The set of operations supported by the web service using HTTP methods
(e.g., GET, PUT, POST, or DELETE).
The API must be hypertext driven
See, http://en.wikipedia.org/wiki/Representational_state_transfer for more details.
Now, with that said, I would suggest changing your above code to be some what close to the below pseudo codes.
1) The existence of resources is key, think of your post(s) as a collection of resources that can be accessed by a URI.(authentication & authorization are other concerns that you might also want to handle):
api.domain.com/resources/posts => This URI points to a collection of Posts
2) The set of operations that you will want to support using HTTP methods/verbs need to defined, as an example we might want to retrieve just one member of the collection by doing this:
api.domain.com/resources/posts/12
Below are request header & body that could be found in an incoming request for this URI:
Accept: application/json
Content-Type: application/json
Request Url: http://api.domain.com/resources/posts/12
Request Method: GET
Your application should be able to handle that type of request, without the need of stipulating the operation in the URI, bringing us back to point (1),
rather than having a URI written this way:
domain.com/api/posts/all
Your URI should be model this way:
resources/posts/12 as resources/type/item to retrieve one member from the collection,
resources/posts as resources/type to work with the entire collection.
Here's an example of codes:
Common abstract class
Here you could implement some common tasks.
If, you are using a service based implementation
this could also be accomplished by a service.
abstract class ResourcesController extends AppController {
}
class PostResourcesController extends ResourcesController {
/**
* By the time this method is called in your controller/class, you already know
* that the HTTP method is GET.
*
* #param Request\$_GET $request A request instance
* #param int $postId The post ID to retrieve
*
* #return Response A reponse instance
*/
function getPost(Request $Request, $postId = null)
{
/**
* Here you can use the request object to get
* the response content type
* the requesting client accepts. Example JSON or XML.
*/
/**
* using the $postId you can then query your database
* to retrieve a post with that ID or use a sort of
* service.
*/
/**
* Once you implemented a you logic
* you can build a response to return.
*/
}
}
This code is incomplete, but I hope it gives
you an idea of what a real Restful API might look like.
The key it to make sure that
"the application can interact with a resource by knowing two things: the identifier of the resource and the action required".
Hopefully, this helped.
I am trying to create an api with Recess and I have a question about its JsonView. Currently, if I do a GET request on, for example, /users/1 (which routes to a function that gets all the details for the user with id 1 and responds with Json), I get the following:
{"users":{"id":"1","username":null,"password":null,"datejoined":false}}
How can I make it so that I get the following instead:
{"id":"1","username":null,"password":null,"datejoined":false}
That is, I don't want all the details wrapped inside "users":{}.
By default, Recess's JsonView responds with the properties of your controller. So your $users property is getting directly encoded into JSON.
You can override this by returning a custom response object:
return new OkResponse($this->request, (array)$this->users);
Not sure about recess specifically, but if you are using JsonView method/function with an input parameter (array) $result, then changing $result to $result['users'] may give you the answer you are looking for.
For example using plain PHP:
first object: echo json_encode($result);
second object: echo json_encode($result['users']);
I'm working with a PHP MVC Framework. Works really well. I like the separation of the business layer (model) with the business logic (controller). But i just stumbled upon a problem. Here's the thing:
Suppose i navigate to the following url:
http://localhost/user/showall/
In this case the userController.php is called and within that file there is a method showallAction() which gets executed.
In the showallAction() method i simply do a request to a model which gets all the users for me. Something like this:
public function showallAction()
{
// create userModel object
$users = new userModel();
// get all users and assign the data to a variable which can be accessed in the view
$this->view->users = $users->getAllUsers();
// render views
$this->view->render();
}
So this method gets all the users, assigns the data returned from the userModel to a variable and i can easily work with the returned data in my view. Just a typical MVC thing.
Now here comes the problem.
I also need to create a native iphone variant. Ofcourse the looks will be totally different. So all i actually want to do is to request this url:
http://localhost/user/showall/
And that it just gives me the array (in json format) back. So i can use that for the mobile development.
But this obviously can't be done right now because the showallAction() method assumes that it is for web browser display. It doesn't echo JSON formatted, instead it simply assings the array of users to a variable.
So that means i have to create another method "showallMobileAction()" in order to get the data, but specifically for the mobile device. But this is not an elegant solution. I'm sure that are better ways...
Anyone any idea how can i solve this problem??
In your situation i would modify the routing mechanism.
It would be useful, if you could add extension at the end of URL, which represents the format you expect, like :
http://foo.bar/news/latest >> HTML document
http://foo.bar/news/latest.html >> HTML document
http://foo.bar/news/latest.rss >> you RSS feed
http://foo.bar/news/latest.json >> data in JSON format
It's a simple pattern to recognize. And you can later expand this to add .. dunno .. pdf output, or Atom feeds.
Additionally , two comments :
Model is not a type of objects. Instead it is a layer, containing objects responsible for business logic, and objects responsible for data storage/retrieval.
View should be a full blown object, to which you bind the domain objects (objects responsible for business logic).
You could pass parameters to your url:
/user/showall/json
and get the third URL segment with a custom function or a built-in one. For instance, with CodeIgniter: $this->uri->segment(3).
Some frameworks will pass the additional parameters to your method. Just try this with the URL I wrote above:
public function showallAction()
{
print_r(func_get_args());
}
I'm not familiar with PHP MVC but in general terms I'd use the "accepts" HTML header field to request the response in either "text/html" or "text/json", the controller would check for the accepts type and return the response accordingly.