Re: [Catalyst] Re: REST - like uri design for CRUD
Aristotle Pagaltzis wrote: * Ian Docherty [EMAIL PROTECTED] [2008-01-28 13:45]: OK, so I put the item into the request body, but this does not tell the remote client the ID of the created item. Why does it need it? Is the URI not enough? If not, is the URI *really* not enough (ie. could things be arranged so that it is)? The 'create' is a POST to the URI http://mydomain.com/svc/doc with the content being the document to save. However, the client has to know the ID of the created document (which at this point is only known by the server). Say for example that I am putting arbitrary documents (xml, text, images) etc. onto the server via a web service in a RESTful manner, I do this with a POST to my server. The server needs to respond with something in the header to indicate the ID of the document just POSTed. Well, then don’t render the body of the item in the 201 response, and do not set Content-Location, and instead just put some JSON or XML or whatever in there. OK, this would have been my first choice but I was misled I think by some other threads. I do this in the Location header. Location may only ever be a URI. If you put anything else there, you’re doing it wrong. Yes I agree. e.g. POST /svc/upload (the document save) Location /svc/view/1234 (the location of the item just saved, ID=1234) So the URI is parsed by the programmatic client to extract the '1234' yes/no? No. Clients should never parse URIs. If you need to tell them something they need to be able to understand, you put it in the body. (They should not construct URIs either. If they need to request parametrisable URIs, the server should send them a form. Or if you’re creating a non-browser HTTP API, you can send the client a URI Template.) This is something I have not seen mentioned before. I have no idea what a 'URI Template' would look like. I don't see what is wrong with 'constructing' a URI, e.g. what is wrong with the client 'knowing' that URI http://mydomain.com/svc/view/1234 is the location to retrieve item 1234? This is the hypermedia constraint in REST: clients only follow links and forms. They don’t have any hardwired knowledge of the server URI space. (Note, though, that things get muddled with Ajax clients. If the Ajax client is code served by the server (called _Code on Demand_ in REST), then it’s effectively a Turing-complete kind of form markup, so it’s fine for that code to have hardwired knowledge. But in practice, the Ajax client probably talks to a publically available HTTP interface, and making that interface require hard- wired knowledge of non-Code-on-Demand clients is wrong, so it’s probably better to follow the hypermedia constraint even in on- demand code.) Regards, ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
On Tue, Jan 29, 2008 at 08:19:42AM +, Ian Docherty wrote: This is something I have not seen mentioned before. I have no idea what a 'URI Template' would look like. See the RFC and the CPAN module. -- Matt S Trout Need help with your Catalyst or DBIx::Class project? Technical Directorhttp://www.shadowcat.co.uk/catalyst/ Shadowcat Systems Ltd. Want a managed development or deployment platform? http://chainsawblues.vox.com/http://www.shadowcat.co.uk/servers/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
Hi, On Jan 21, 2008, at 7:43 AM, Jonathan Rockway wrote: Along these lines, how is everyone doing multi-page forms? I like to do GET/POST/redirect, but that needs the session to get the data from page 1 to page 2. Without a session, I use the old POST returns the form with hidden fields that is page 1, but i *hate* that technique. So I use the session. I'm going through this as well right now, doing a small checkout- style multi-step form. The following is my current idea on how to deal with this. Its still a rough draft but I think it will work ok. Any feedback is appreciated. Below, when I mention PUT, i'm using PUT-tunneled-over-POST for web clients. Users start by POST'ing to /checkout/start. This will create a cart containing the items to include in this checkout. In our case, we always include all the items currently pending payment, other sites might have a different policy/requirements. The point of this first step is to create a cart, with a unique identifier. We associate the cart with the logged in user and we include a security hash based on the cart id and user id on each form. After all this, we redirect to / checkout/cart/UNIQUE_ID/step1. On each step, the GET will show the appropriate form. The user will fill the fields, and PUTs the result to the same address. Information received is checked and valid fields are stored in the cart state. After that, if all fields are correct, we redirect to the next step. If they are not correct, we redirect to the same URL. Previous values, and error messages or error codes are given back using URL parameters. Usually we have very little parameters and they are all limited in size, so it fits the 1k max URL size. Aside: If a field is unusually large, we need some kind of temporary storage, and this could break somewhat the Idempotence of each request. We could sha1 hash the bad content, store it somewhere keyed on this hash and send the hash to the client. This might solve it. Fortunately I never needed this. On each step, the process updates the fields on the cart, and at the final step, we change the status of the cart to 'ready_to_process' and redirect the user to a success page. The things I like on this approach: Every request is idempotent: you can reload to your hearts content any page, you can post several times each step to update previous entered information, you can go back and forward, everything. There is no final step of copying the cart usually stored in the session to your orders table. The cart is the order, you build the order step by step until its ready to be processed by our back-office staff. Old, unfinished orders can be cleaned up after some time, and if they are request in the future you can just create a new one and redirect to it, or you can give the user a error message and suggest the creation of a new one. I keep carts for one year or until the items in it expire, but that's my business :). Yours might need different timings. You could also erase old carts based on the step they are at. If you start a new checkout with another one still open, there are several options. My personal choice is to merge the old order with the new items, but you could also create a new one and suggest merging the old one (merging on demand). This part also depends on your business needs. Anyway, this is my currently thinking on this subject. Any feedback appreciated. (I also use the Flash for You've added a record successfully! messages. Totally non-RESTful, but the users seem to like it.) You not redirect with parameters? something like po_id=1p1=Pedro[EMAIL PROTECTED] to use message id 1 with two parameters, 1=Pedro and [EMAIL PROTECTED] RESTfull, no? Best regards, -- Pedro Melo Blog: http://www.simplicidade.org/notes/ XMPP ID: [EMAIL PROTECTED] Use XMPP! ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
On Jan 22, 2008 8:25 AM, Zbigniew Lukasiak [EMAIL PROTECTED] wrote: On Jan 22, 2008 1:30 AM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: * Zbigniew Lukasiak [EMAIL PROTECTED] [2008-01-21 07:40]: While we are at that - I do understand the need to divide the operations into the 'indempotent' and 'non-indempotent' classes (because of caching and predictive link loading) - but what is really the practical argument for having two more classes (PUT and DELETE)? I don't understand this question. It sounds like you have some confusion about several distinct things and that you don't actually understand what idempotence is. Can you try to explain a bit more what you are trying to ask? Are you just asking why there are more verbs than GET and POST? Are you asking about why it's important to categorise verbs as non-/safe in addition to non-/idempotent? Is it something all together different? The first one. Why you need to split the class of non-idempotent operations into three more categories (POST, PUT and DELETE). Just after sending it I have realized that DELETE can be also viewed as idempotent since a second call to it does not really change the state (even if it can return an error to the caller). And that shows another question - perhaps all we need is the simple division into safe and non-safe operations? -- Z. ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Re: REST - like uri design for CRUD
* Zbigniew Lukasiak [EMAIL PROTECTED] [2008-01-22 08:35]: On Jan 22, 2008 1:30 AM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: I don't understand this question. It sounds like you have some confusion about several distinct things and that you don't actually understand what idempotence is. Can you try to explain a bit more what you are trying to ask? Are you just asking why there are more verbs than GET and POST? Are you asking about why it's important to categorise verbs as non-/safe in addition to non-/idempotent? Is it something all together different? The first one. Why you need to split the class of non-idempotent operations into three more categories (POST, PUT and DELETE). * Zbigniew Lukasiak [EMAIL PROTECTED] [2008-01-22 11:10]: Just after sending it I have realized that DELETE can be also viewed as idempotent since a second call to it does not really change the state (even if it can return an error to the caller). And that shows another question - perhaps all we need is the simple division into safe and non-safe operations? It seems to me you are still confusing several things. “Idempotent” means that the request will have the same result if you make it repeatedly. GET, PUT and DELETE are all idempotent: no matter how often you repeat them, the resulting resource state on the server will always be the same. This is important insofar as if the request times out due to a network problem, say, the client can simply retry it without any ill effects. This also means proxies can retry such requests for you. POST is not idempotent, in contrast. “Safe” means the client may assume that the server will not do anything harmful in processing the request, and if the server does, the client is not responsible for it. GET is safe in addition to being idempotent: clients may assume that they can send GET requests and nothing terrible will happen. If you `GET /all-my-data/delete` and the server deletes all your data, and it should not have, then it’s the server’s fault, not the client’s. This makes it possible to write things like search engines and other web crawlers, f.ex. Another reason to have separate PUT and DELETE is because without them, you have to tunnel meaning through the body of POST, which muddles things. The semantics of POST depend on the URI which is being posted to, whereas the semantics of PUT are always clear: the client asserts that the resource state should from now on correspond to the request body entity. If the server decides to process a PUT request to a URI, it is always clear what is going to happen; if the server decides to process a POST request to a URI, as a client, you have no idea what it will do. Same reasoning goes for DELETE, and for the PATCH draft currently being written. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
Peter Karman wrote on 1/20/08 7:53 PM: Aristotle Pagaltzis wrote on 1/20/08 7:36 PM: * Peter Karman [EMAIL PROTECTED] [2008-01-20 22:10]: there's no checking of HTTP method at all. Yikes!! img src=http://example.org/foo/id/42/delete; I actually consider that a feature, since it seems legit to me that a GET could act on an object. That's not REST, but RPC, as you indicated. In my apps, I do server-side auth checks to verify that users can't act on data they should not have access to. Then again, all my apps use POST to delete too. :) That said, I did enable a method-check in v0.23 with a configuration option to turn it off. That API is intentionally RESTish It’s not REST if it ignores the uniform interface – it’s RPCish. URI design is completely orthogonal to REST. you are right of course. /me adds CatalystX::CRUD::REST to todo list... /me crosses item off list http://search.cpan.org/~karman/CatalystX-CRUD-0.23/lib/CatalystX/CRUD/REST.pm Thanks, Aristotle, for pointing out my naive understanding of REST. This thread helped me write the API in the module above. Comments, suggestions always welcome. pek -- Peter Karman . http://peknet.com/ . [EMAIL PROTECTED] ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
Aristotle Pagaltzis wrote: * Peter Karman [EMAIL PROTECTED] [2008-01-23 03:50]: In my apps, I do server-side auth checks to verify that users can't act on data they should not have access to. Peter, meet XSRF. XSRF, meet Peter. :-) My point with `img src=/foo/delete` was that an attacker tries to get an authenticated and authorised user to visit a page which contains that tag. Or maybe an authenticated and authorised user has software like the Google Web Accelerator installed. Regards, But surely the same is true for POST as well using a form/javascript. So what does that leave? signature.asc Description: OpenPGP digital signature ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Re: REST - like uri design for CRUD
* Zbigniew Lukasiak [EMAIL PROTECTED] [2008-01-21 07:40]: While we are at that - I do understand the need to divide the operations into the 'indempotent' and 'non-indempotent' classes (because of caching and predictive link loading) - but what is really the practical argument for having two more classes (PUT and DELETE)? I don’t understand this question. It sounds like you have some confusion about several distinct things and that you don’t actually understand what idempotence is. Can you try to explain a bit more what you are trying to ask? Are you just asking why there are more verbs than GET and POST? Are you asking about why it’s important to categorise verbs as non-/safe in addition to non-/idempotent? Is it something all together different? Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Re: REST - like uri design for CRUD
* Peter Karman [EMAIL PROTECTED] [2008-01-20 22:10]: there's no checking of HTTP method at all. Yikes!! img src=http://example.org/foo/id/42/delete; That API is intentionally RESTish It’s not REST if it ignores the uniform interface – it’s RPCish. URI design is completely orthogonal to REST. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
Aristotle Pagaltzis wrote on 1/20/08 7:36 PM: * Peter Karman [EMAIL PROTECTED] [2008-01-20 22:10]: there's no checking of HTTP method at all. Yikes!! img src=http://example.org/foo/id/42/delete; That API is intentionally RESTish It’s not REST if it ignores the uniform interface – it’s RPCish. URI design is completely orthogonal to REST. you are right of course. /me adds CatalystX::CRUD::REST to todo list... -- Peter Karman . http://peknet.com/ . [EMAIL PROTECTED] ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: REST - like uri design for CRUD
On Sun, 2008-01-20 at 23:58 -0600, Dave Rolsky wrote: On Mon, 21 Jan 2008, Aristotle Pagaltzis wrote: The part where web browsers really do suck – and I really mean suck utterly terribly – is HTTP Auth, which makes you have to… well, you don’t quite have to violate REST constraints, but you are forced to traipse into grey areas like cookie-based auth (not sessions!). I think sessions _can_ be RESTful if they are part of the URI, though you probably wouldn't want to use them for auth. I _do_ use sessions in VegGuide.Org in what I think is a RESTful way. Certain redirects will send you to a URI like http://www.vegguide.org/user/login_form/-/a746d3cba351bde58debde610b40715d49ec4312 This user represents a unique thing, which is the login_form + a session. I only use the session to hold very transient things, like error or success messages after a form submission. In the case of an error, it also holds the state of the form so we can repopulate it. Along these lines, how is everyone doing multi-page forms? I like to do GET/POST/redirect, but that needs the session to get the data from page 1 to page 2. Without a session, I use the old POST returns the form with hidden fields that is page 1, but i *hate* that technique. So I use the session. (I also use the Flash for You've added a record successfully! messages. Totally non-RESTful, but the users seem to like it.) Regards, Jonathan Rockway signature.asc Description: This is a digitally signed message part ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/