The agavi framework uses the PUT request for create and POST for updating information. Usually in REST this is used the other way around (often referring to POST adding information while PUT replacing the whole data record).
If I understand it correctly, the important issue is that PUT must be idempotent, while POST does not have this requirement. Therefore, I wounder how creating a new record can be idempotent (i.e. multiple request do not lead to multiple creations of a record) in particular when usually the ORM uses an id as a primary key and the id of a new record would not be known to the client (since it is autocreated in the database), hence cannot be part of the request. How does agavi maintain the requirement of idempotence in light of this for the PUT request.
Thanks.
PUT can be used both for creation and for updating complete records. POST is usually used for partial updates and related operations as well as for creating a new type of record on the server without specifying a URL for the resource (e.g. POST to /articles/23/comments returns a 201 status and a Location: /articles/23/comments/283136 header). So in your case (with a sequence/autoincrement ID), you would use that approach.
However, HTML (and thus web forms) is different. It only knows GET and POST, not DELETE and PUT. For deletion and updating operations, it overloads the POST method.
That's why Agavi, by default, maps POST to "write" and GET to "read" - it's the most common use case, and "read" and "write" were chosen because they are relatively neutral and also in a way represent the safety aspects of GET vs POST (safety as in "GET can be called without side effects" and blah).
You can change the mapping of verbs for the AgaviWebRequest implementation in factories.xml; refer to the Agavi users mailing list or the IRC channel if you need help with that (or ask away here). A lot of people on the IRC channel are also quite experienced with URL scheme design in case you need more help with making your API pretty.
Instead of thinking of PUT as creating, think of it as "putting". You put a resource at a URI (ie send an entire resource to a URI).
PUT http://example.com/articles/1
If you repeat this (send the same entire resource to the same URI) you get the same result and you haven't changed the resource at that URI, that's what makes it idempotent.
If agavi's implementation of PUT is idempotent then it is implementing PUT correctly. Otherwise it's not.
PUT can be used to create a resource, except that if the resource already exists (or has already been created by a previous PUT) it will just update it. POST should not update resources, however, if this is simple CRUD. Note that the HTTP verbs do not have a defined mapping to certain actions necessarily, since they're useful for a lot more than just CRUD.
Also note that this question has nothing to do with REST - just proper HTTP usage. So please remove the REST tag.
I've had this problem before. This can be solved by changing the factories.xml
Related
I'm developing my first RESTful api, which (unfortunately) is being done on an already existing system and the idea is to allow third-parties to access this system.
Everything was fine until I realised that I have multiple ways to access the same resources. I will try to explain it using one of the parts of the system. The system has been built using Laravel 5.8 and has, among others, the following database tables:
users
emails
sms
Each user can have many emails, and each email belongs to only one user. The same applies for text messages.
I've "ignored" all the current code, because it wasn't built on a proper way to make it an RESTful api, so I've created a new folder Api and all my code is there.
I thought it would make sense to have the following endpoints
/api/v1/users
/api/v1/users/1
/api/v1/users/1/emails
/api/v1/users/1/emails/1
/api/v1/users/1/sms
/api/v1/users/1/sms/1
In this way I can have a list of users, get all the details of a user, get a list of emails/text messages and also get all the details of a specific email/text message. However, one of the requirements is to have a page with a list of emails/text messages, so it's starting to make sense to have:
/api/v1/emails
/api/v1/emails/1
/api/v1/sms
/api/v1/sms/1
To avoid having 2 endpoints to get the same resource (/api/v1/users/1/emails/1 and /api/v1/emails/1 will return the email with id 1) I'm considering to get rid of the deep endpoints /api/v1/users/1/emails and change them to something like /api/v1/emails?user_id=1.
Is this against RESTful principles? I couldn't reach a conclusion on my research about having 2 endpoints to access the same resource, but it doesn't "feel" right. On the other hand, having /api/v1/emails?user_id=1 may rise some security/privacy concerns (for example, I need to make sure that user 1 can only access /api/v1/emails?user_id=1 and not /api/v1/emails?user_id=2), but seems more flexible because I can use it alone to get all the resources or with the user_id filter to get only specific resources.
Is there a convention for this case?
It may help to review how we understand "resources" in a REST context.
Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource.
/api/v1/users/1/emails
/api/v1/emails?user_id=1
/66eb6757-254e-49b4-bc8a-d04330f4482e
REST treats identifiers as semantically opaque -- general purpose clients do not use the spelling of the identifier to understand what is going on. Consider a web browser - it knows that http://example.org/cat.jpg is an image not because jpg, but because img.
That means that the server may use any spelling it likes -- any information encoded into the URI itself is done at the server's discretion and for its own use.
This isn't to say that there aren't advantages to using "guessable" spellings; just that REST is completely agnostic about whether or not identifiers should be guessable.
Choosing spellings for your identifiers that make your implementation simpler is completely within bounds.
I have a model Project which have many Orders. On the page of the project, I have a list of its orders and create/update buttons.
Now I pass project_id in GET params in url. I need watching that each url and redirect have this parameter (in the update and create views/controllers and in the list of orders view/controller).
Is there a better way, to pass parameter through views and controllers?
This doesn't really have anything to do with MVC. In a web context, each HTTP request must be self-contained. All the information your server needs to fulfil the request must be contained within the request. Either within the URL, or within the request body.*
Whenever your server generates a URL somewhere to send back to the client, you need to embed all the information necessary in that URL so a request made to that URL gives your controller all the information it needs to fulfil the request. So, yes, you'll need to pass all the information through to that place in your code. That's pretty much the same whether you use MVC or plain spaghetti PHP files.
The only alternative is for you to reduce the amount of information the controller needs to fulfil the request, e.g. because you can implicitly get one part of information from another, like the project id when given just an order id.
* (I'll forego something like session storage here, since that's stateful across all requests and generally cannot be used for transporting information specific to individual requests.)
Session is retrieved in SF2 through the Request object. Hmm, this becomes kind of problematical when some architecture is considered - in cases where access to a session vars is needed from within a service.
Or perhaps, I'm not quite correct in this matter? (Hope so).
Obviously each request from a user through a webbrowser is a Request. So as long as we use controller actions in standard SF2, we have Request. But should we then pass the Request object to any service we need?
Passing Request object to all of the services that needs their methods to be run (e.g. storing info, checking settings, putting filters for displaying data etc. - well in some bigger apps it's quite a lot of them!) because it might be needed because of the dependent services, seems to be a very stupid idea to me. It also breaks the "S" in S.O.L.I.D. recommendation for OOP.
So I came up to a conclusion I need either to:
Pass the Request obj to many services just because the dependant service might need some data from it (i.e. broken "S" as above)
Retrieve and process data from Request every time I needed in every single controller action (i.e. code duplication) - in this case I don't pass a Request obj, but previously prepare all data needed - but I must do it then in many action methods in almost all controllers (retrieving/processing data from Request is just a simple call for another service, but then it's not centralized)
I'm putting this question, because I have e.g. the following problem to solve:
I'm using the same filters for all different data (from different data-sources) on the whole page.
Filters can be enabled and disabled - and they should be remembered for all the pages for the single session
I decided that saving "disabled" filters to a session is probably the best approach (because by default all data should be seen, i.e. all filters should be in "enable" state)
The 3rd point - saving data (filters) to a session - is what makes trouble in SF2, as described above. For displaying filtered data on page, I need access to a session, and thus access to the Request obj. And this means I have difficulties in keeping "S" in SOLID, because of making dependency on a service's method to always pass a Request obj to it.
Is there any other, better solution than the 2 mentioned (i.e. one, breaking SOLID, or two, code duplication)?
The session is also a service in the symfony di container, you can simply inject session into your servives
Backbone tutorials I have read implement some type of a mini-framework (i.e. Slim) with a RESTful architecture performing CRUD on a server db, like this. The Backbone docs state you need a RESTful api, which I believe is due to the Backbone Route and Sync functionality that keeps models up to date, which is a huge aspect of my choosing to use Backbone.
For example, the line below maps a faux url (route) to the 'addWine' function (within a Slim api):
$app->post('/wines', 'addWine');
Assumption 1: If I have a (PHP) CMS backend (and not a mini-framework) I assume I could simply replace the 2nd parameter (addWine) with my own CMS class method call and return a json object.
Assumption 2 But I would not be able to directly call that same class method from a link in the html without causing backbone to lose state and thus it's ability to sync the model data (and remember the browsers history).
Assumption 3 In that case, I will need to use the Slim api and route backbone urls through (Slim) RESTful CRUD calls in order to access my CMS database to keep backbone happy.
If those assumptions are correct, then it would seem backbone is intercepting those HTTP calls - which leaves me wondering how the whole RESTful + Backbone relationship works. Can you explain some of it?
If my assumptions are incorrect, then I need more help than I thought. Can you help with that?
Thanks
I can't speak intimately to your three assumptions, but as for your final question -- Backbone does not "intercept" HTTP calls -- it constructs them, just as any other javascript library would to create an AJAX request.
Backbone is relatively agnostic to your server side language/framework. Here is what Backbone expects any time "sync" is called:
Backbone's sync function uses different HTTP request types based on which method was called. These different HTTP request types are:
POST
GET
PUT
DELETE
Your framework needs to support all of the above to support the "out of the box" functionality of Backbone. This means that you must specify all of the above routes within your application in order to work with Backbone.
One other thing to note is the "create" and "update" method does not carry post data with the request specifically -- instead it sends a content body with a json digest of the data and expects the server side to properly parse a JSON object and deal with it appropriately.
I say yes to all three assumptions and also agree with #Andy Baird.
Also, the only problem to your project is how to notify Backbone that you have updated the database and you would like it to update itself in the front-end. I can only see two solutions:
1) using Javascript's setInterval() - if you do not need the front end to be updated immediately on DB update, you can check for changes every 1 minute, Backbone knows to only update what has changed and add new stuff but of course this is not healthy to the server if you have 1k active people making repeated request every minute
2) using SocketIO or similar service - this way you can send from the server to Backbone either the entire list of modifications to your DB or a simple 'Please refresh, new stuff waiting'. Check this discussion.
can i call a web service like this
and not use put and delete method?
is this a REST web service really?
....
$url = 'webservice.php';
$data = array(
'username' => 'a',
'password' => 'a',
'param1'=> 'param1',
'operation'=> 'delete',
'output'=>'xml'
);
$client = curl_init($url);
curl_setopt($client, CURLOPT_POST,1);
....
...................
//webservice.php
$operation=$_POST['operation'];
$param1=$_POST['param1'];
if ($operation=='delete')
{
$r=mysql("delete from list where id='$param1'");
}
if ($operation=='insert')
{
$r=mysql("insert into list values ('$param1')");
}
.....
One of the major ideas behind REST is to not give operational methods as part of the argument (in this case the 'operation' parameter).
Instead, each resource has its unique URL and the HTTP verbs (GET, POST, PUT or DELETE) are used on those resources.
Your approach is not RESTful.
Example:
Deleting a comment using the flickr API:
GET /services/rest/?method=flickr.photos.comments.deleteComment&comment_id=28
Note how they use a 'method' parameter to determine what operation to perform (like in your example).
The RESTful implementation would accept something like:
DELETE /comment/28
Best practise in this case would be to use POST for creating new resources, DELETE for removing them, GET for retrieving existing and PUT to update existing.
This kind of technique is sometimes called "tunneling" because it buries the true operation in the body of a generic POST operation. In my opinion it's kind of a hack and defeats the purpose of REST but sometimes it's necessary if your web host doesnt allow the required HTTP verbs.
Using standard verbs and understanding the implications they make about your service is an important aspect of REST that should not be overlooked. For example, you should be able to issue a DELETE operation repeatedly on the same resource and that should result in only the first DELETE having any effect (idempotent). With GET it should be assumed that no changes are being made on the server (safe). But hiding the operation inside of a POST obscures that.
This isn't really a RESTful service. You don't need to implement all HTTP verbs to be RESTful, but you shouldn't use POST to DELETE data.
Personally I'd implement DELETE for removing items and only use POST for inserting data.
I'm going to go against the tide here and say it is perfectly fine to create RESTful services without PUT and DELETE. The only key thing that you need to be aware of is what you are giving up in doing so.
1) Intermediary components(e.g. proxies, caches, load balancers) will not know whether you are creating/updating or deleting resources, they will only know if the operation is safe (GET) or unsafe (POST). My question is, do you know of any intermediary components that take advantage of this knowledge?
2) The programmer who is going to be accessing your service will not be able to guess how to DELETE a resource, you are going to have to include a link with a link relation that has some documentation that explains to the programmer that they will need to POST to the link's URI to do a delete. It's a bit more work for the client developer but at least you are being explicit about how to do it.
And before I get downvoted into oblivion, here is a quote from Roy Fielding who says it is ok too!
In any case, there are plenty of
RESTful services that do nothing but
GET and POST. The key is how those
methods are used, not what methods are
used. To give a specific example, what
makes a wiki more or less RESTful is
almost always determined by how it
(ab)uses GET and sessions -- whether
it uses PUT or POST for editing pages
is sugar topping in comparison.
http://code.google.com/p/implementing-rest/wiki/FAQ
Having said all of this, creating a single resource called webservice.php and passing a "operation" parameter is a nasty design smell from the perspective of REST.