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.
Related
Since 2.4, we can inject the RequestStack in our services.
To retrieve the current Request, there is two methods:
/** #var Request */
$request = $requestStack->getCurrentRequest();
// OR
/** #var Request */
$request = $requestStack->getMasterRequest();
When should we use the currentRequest ?
And when should we use the masterRequest?
For example, if I need to retrieve the parameters in the body of the current Request, I would use:
$params = $request->request->all();
Which of the two methods should I use ?
When dealing with multiple requests, the non master request comes from internal requests. Usually from twig in the form of
{{ render(controller('foo')) }}
When the second request is created, only the request format and locale are copied to the new instance. Therefore, any data you would expect to come from the user, will not be available. This includes request parameters, ip address, and any HTTP headers.
In most situation, you will only need to deal with the current request. But, to answer your question, any time you need data coming from the user, you will require the master request. An example would be using the users IP address to pre-select a CountryType form control.
When using getMasterRequest()->getClientIp() you would be given the IP address of the user (something like 209.58.130.174). When calling it on the non master you will be given the localhost/loopback IP (127.0.0.1). There aren't really any methods that will return null, they simply return different information about how the request was created.
The master request is the one that comes from the original user; the subrequest is the one that you do internally — either with the forward() method of HttpKernel — or by the forward() helper of the framework's Controller class — or {% render ... %} in Twig.
https://stackoverflow.com/a/12456998/1078488
This means you would normally use the current request, if you don't explicitely want the actual request made by the user.
I've used a service for injecting the current request:
app.request:
class: Symfony\Component\HttpFoundation\RequestStack
factory:
- '#request_stack'
- 'getCurrentRequest'
Then you can inject it like this:
app.some_service:
class: AppBundle\Service\SomeService
arguments:
- '#app.request'
- '#some_other_service'
I have a controller for ProductController. I have 4 standard methods bound to respective HTTP methodslike
public function index() // GET
public function create() // POST
public function update() // PUT
public function destroy() //DELETE
So far so good, but i have to make few other functions like getProductsByCategory, getProductsAttributes() etc etc. After implementing this, Will my API still be called REST ? If not than how can i handle these requirements
Thanks
Resource URI for getProductsByCategory(...):
GET /products?category=books HTTP/1.1
Host: service.org
Resource URI for getProductsAttributes():
GET /products/bmw-528i/attributes HTTP/1.1
Host: service.org
How you implement handling of these request URIs is a implementation detail. If you are using some framework, you can do something like this:
Routes::add("/products/{product-id}/attributes", function($request, $response) {
// do something here
});
But it is a detail that can not affect RESTfullness of your service.
First off, REST is not a strict standard. The methods you posted comply the REST conventions but a REST service must have several other properties. The two most important ones are:
statelessness: no session, no cookies, authorization on a per-request basis
GET requeste never change any resource
There are other ones, feel free to edit or add in the comments.
The way i see such operations on resources implemented most of the time is:
/<resource-name>/<product-id>/<operation>
For example:
GET /product/<product-id>
GET /product/<product-id>/related
POST /product/<product-id>/purchase
GET /categories/tools
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.
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
Requiremen :- Yii, OAuth implemenation to authenticate and fetch user data.
I found out that there are two extensions. Eauth(support OAuth 2.0 and other social networking sites) and Eoauth(OAuth 1.0). Correct me If i am wrong.
I dont have to authenticate any social networking site. It's a different url from where I need to get the data.
Now i could successfully login and authenticate using "eoauth" extension but also I need to fetch information about the user. I don't find any function or way how to fetch data from url which lies under OAuth layer. Does Eauth or Eoauth supports fetching or it has to be custom coded ?
If this extensions does not do this then what is the other way I can authenticate and fetch data ?
Of course, Eauth supports fetching user's data.
Let's see on Eauth structure. We have directories /services, /custom_services and class EOAuthService. EOAuthService contains method makeSignedRequest(), that return the protected resource from third-party site.
So, this method we can call from our serviceClass, that extends EOAuthService. For example, class FacebookOAuthService in /services directory. The class contains protected method fetchAttributes(), it calls method makeSignedRequest($url) and get $info (in JSON) from third-party site (FB in our example). Properties of this object - it's our user's data.
What about /custom_services? The directory contains classes for tuning our "BaseServiceClass".
So, for example, CustomFacebookOAuthService extends FacebookOAuthService extends EOAuthService.
You need create your own class, which will make signed request for your third-party site and get proper response (in JSON, for example). Then fetch gotten info - and voila!
Of course, user must be authenticated by third-party site for fine auth on your application through oauth.
Though Old but You just need to use CURL request to the end URL and you will get your data. I guess those modules doesn't have the function to fetch a data. I hope this might help you. I have used in one of my code and It was successful
public function GetData($url){
$signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
$request = OAuthRequest::from_consumer_and_token($this->consumer,$this->token, 'GET', $url, array());
$request->sign_request($signatureMethod, $this->consumer, $this->token);
$fetchUrl = $request->to_url();
$response = Yii::app()->CURL->run($fetchUrl);
return json_decode($response);
}