When you design URL schema for your application, which rules you use?
example.com/post/ or example.com/posts/ for list of posts
example.com/post/new/ or example.com/post/create/ for new post
example.com/posts/ + example.com/post/23/ or example.com/post/ + example.com/post/23/ for list and detail of post?
example.com/post/23 or example.com/post/23/ for details
example.com/post/edit/23/ or example.com/post/23/edit/ for editing.
I'm prefered: /post/ for list, /post/23/ for details, /post/23/edit/ for editing, just b/c I'm can very easy work with that URL by hand in browser location bar. I'm wrong? Suggest me, please.
Thanks.
You should probably use the HTTP POST method when creating a new resource. So, for a new customer, you might POST to example.com/customer. Then if you want information on that customer, do a GET to example.com/customer/{your recently created customer id}. If you want all customers, do a GET to example.com/customer If you want to edit a customer you'll probably want to PUT to example.com/customer/{your customer id}
It seems that your fundamental issue is that you are dealing with is that you are specifying your action (or verb) in your URL. You don't need to do that. Instead of doing something like example.com/edit/23, you should use the HTTP PUT method with example.com/23 (or example.com/customers/23).
Have a look at what is RESTful/REST for a review on creating RESTful resources.
Have a look at PUT vs POST in REST for the difference between POST and PUT (edit and create).
For building more complex RESTful URLs, I generally refer to this presentation from the LinkedIn nerds.
I use:
GET /posts for list
GET /posts/new to
get empty HTML form for 'static'
sites only ('ajax' sites and
'stand-alone' clients don't need it)
POST /posts for create ('action' attr
in previous form)
GET /posts/23 for
detail (not for editing!)
GET
/posts/23/edit to get filled HTML
form with hidden '_method=PUT' field
to emulate PUT in browsers
PUT
/posts/23 for editing ('action' attr
in previous form)
DELETE /posts/23
for deleting ('inline' HTML form with
'_method=DELETE' to emulate)
POST
/posts/23 for emulate PUT and DELETE in browsers
And I never use /posts/ or /posts/23/ because it makes hard (or dirty) to change response format. I can use /posts (synonym for /posts.html) for browsers , /posts.xml for XML services, /posts.json for 'ajax' data and /posts.smth_else for smth else :) in future. Also all of them may be static files (cache or archive) to free CPU and memory on high load.
Related
I have a main page and special information for this particular page, how to better implement the editing form at url, for example / home-page-edit / without /: id?
You can do something like this.
1. Fetch edit page and form with the passed params: id, and_other_params
2. After loading edit form for specific resources based upon that params od value you can insert data.
3. Custom update action but updated based upon passed params and id.
** Please this may not be the ideal way for http-rest requests. Try to avoid this way.
I have built a simple website and have the requirement to display all post from a blog for a year.
For example www.mysite.com/blogs/2015 should display all posts of 2015.
However, this year is not the real creation date of the post but it is given as input while creating the post (I have added new field to the editor).
I should also have a way to access a post with a unique URL like www.mysite.com/blogs/2015/2, which should display the second post of 2015.
The post number is unique for the year. So I cannot use the content id.
I was able to make this work with my own controller, but an issue remains:
When posts are listed it will attach the URL created by the AutoroutePart, which will be like www.mysite.com/blogs/first-post.
I attempted to change this URL while creating the post by updating the Path property of the AutoroutePart but had no luck.
Any suggestions or advise are appreciated.
You can define you own route for any content item which has the AutoroutePart.
Example in you situation you need to edit the content definition of the blog posts. So under the Content Definition menu you select Blog Post, then edit, then you click on the expando arrow next to the Autoroute label and you'll see the Patterns field where you can define your own pattern.
I have been banging my head over this for the past 3 days (No kidding!!!)....It seems like a very simple thing but I am just unable to do it. So I'm putting the question out here, and am open to any method which would work.
BACKGROUND : An advanced search form on submission used to generate an URL too large for the server. So the form had to be submitted via POST. So far, so good. Form submitted successfully, and the result was displayed. Only remaining problem was pagination.
As it's a POST call, it ruled out will pagination. While will-pagination merges param page to the existing params, but the problem is that it shows on url which results in the same error.
QUESTION: So is there any way, if the user clicks a link NEXT, I can
a) Update the page param
b) Keep the existing params
c) While not changing the URL
d) Transfer control back to the action in controller?
The only solution so far suggested was have a hidden form, repopulate it's value and submit again. The form's pretty complex, so if there is a cleaner way I'd like to know.
I see what you want from your comment. So editing my reply accordingly. You want the information as to which column is being selected in the sort to be available to the controller without having that information available in the url string, and you want to use GET for this not POST
The challenge you have is that you want to preserve state between requests and you need a mechanism for doing this. POST preserves that information by sending it in the body of the POST request. GET does this by allowing you to populate the query string. The other method for preserving state is to use a cookie.
You can manipulate the url with javascript on the page. There are tutorials online for that.
But if you just want a simple controller hack as you say in your comment then the simplest one I can think of is to allow the user to make the GET request to the url with the query params in it, then handle this request in two steps - step one saves the query information to the cookie, step two redirects them to the url with that query string data stripped, and you look on the cookie to see if it has those fields before building your data for that page. It's hacky but it works.
def sort
session[:sort] = params[:sort]
redirect_to url_without_the_query_string
end
There is also the new html 5 feature:
window.history.replaceState(“Replace”, “Page Title”, “/mypage”);
from this stackoverflow answer here: How to remove query string from url using javascript
However I'm not sure I'd recommend messing with the url after load like that (I don't know enough about that solution so I'd recommend you read that answer and see if that fits). So, if you MUST lose that data from the url string, because you need to somehow pass it between requests you either have to use POST, or use the session cookie/redirect method I describe above.
Does your html <form> have an action attribute? If not, add one that points to the page.
If you want to preserve the current GET params so that results from the POST can use , you will also need to modify the javascript triggered on the heading links so that as well as (or instead of) modifying the query string, they write the same data to hidden form fields (which of course then get posted in the body of the request). Your JS library may already include helpful functions for that.
I'm fairly familiar with REST principles, and have read the relevant dissertation, Wikipedia entry, a bunch of blog posts and StackOverflow questions on the subject, but still haven't found a straightforward answer to a common case:
I need to request a resource to display. Depending on the resource's state, I need to render either a read-only or an editable representation. In both cases, I need to GET the resource. How do I construct a URL to get the read-only or editable version?
If my user follows a link to GET /resource/<id>, that should suffice to indicate to me that s/he needs the read-only representation. But if I need to server up an editable form, what does that URL look like? GET /resource/<id>/edit is obvious, but it contains a verb in the URL. Changing that to GET /resource/<id>/editable solves that problem, but at a seemingly superficial level. Is that all there is to it -- change verbs to adjectives?
If instead I use POST to retrieve the editable version, then how do I distinguish between the POST that initially retrieves it, vs the POST that saves it? My (weak) excuse for using POST would be that retrieving an editable version would cause a change of state on the server: locking the resource. But that only holds if my requirements are to implement such a lock, which is not always the case. PUT fails for the same reason, plus PUT is not enabled by default on the Web servers I'm running, so there are practical reasons not to use it (and DELETE).
Note that even in the editable state, I haven't made any changes yet; presumably when I submit the resource to the Web server again, I'd POST it. But to get something that I can later POST, the server has to first serve up a particular representation.
I guess another approach would be to have separate resources at the collection level:
GET /read-only/resource/<id> and GET /editable/resource/<id> or GET /resource/read-only/<id> and GET /resource/editable/<id> ... but that looks pretty ugly to me.
Thoughts?
1) It is perfectly valid to have two distinct resources, one for viewing and one for editing some domain concept. Just be aware that because they are two different URIs from REST's perspective they are two different resources. Too often people conflate resource with domain object. That's why they end up being stuck only doing CRUD.
2) Don't get too hung up on the name of the resource. The important thing is that you realize that what the URI points to is a "thing", "a resource". If that's more obvious to you with editable instead of edit then use that. Having a verb in your URL doesn't make your application wrong, it just makes it a bit less readable to the human developer. Using a verb in the URL to try and redefine the semantics of the HTTP method, now that's a violation of the uniform interface constraint.
In REST, editing an existing resource is accomplished by a client GET-ing a representation of that resource, making changes to the representation, and then doing a PUT of the new representation back to the server.
So to just read a resource your REST client program would do a:
GET http://www.example.com/SomeResource
And to edit that resource:
GET http://www.example.com/SomeResource
... edit it ...
PUT http://www.example.com/SomeResource
Normally simultaneous updates are handled by letting the last PUT arriving at the server overwrite the earlier ones, on the assumption that it represents a newer state. But in your case you want to guard against this.
Carefully consider #Jason's suggestion to maintain an optional parallel lock resource for each main resource. Your client would first create the lock, do the edit, then delete the lock. Your system would need to release a lock automatically if the user making the lock subsequently never saves any changes. This would look like:
GET http://www.example.com/SomeResource
... user presses an edit button ...
PUT http://www.example.com/SomeResource/lock
... user edits the resource's representation ...
PUT http://www.example.com/SomeResource
DELETE http://www.example.com/SomeResource/lock
You'd need to do some appropriate error handling if the user is trying to edit a resource that's locked by someone else.
It sounds like you feel you're constrained by the current limitations of HTML. If you use a server-side REST framework like Restlet (for Java), it supports the notion of "overloaded POST", where you can use POST but tack on a query string argument like method=PUT or method=DELETE. If you're writing your own server-side components they can use this trick too.
There are tricks you can play at the HTML level too. For instance your page can have a read-only part that's initially displayed, and an input form that's initially not shown. When the user presses the edit button, your JavaScript hides the read-only part and shows the input form.
Be sure to read Richardson and Ruby's Restful Web Services (O'Reilly) too. It's extremely helpful.
I don't think returning a form or just values is up to a REST server, but the responsibility of the client. Whether a resource is editable is a property of the resource, and not something defined by the URL.
In other words: The URL for getting the resource is GET /resource/<id>. This has a property editable. If a user wants a form it can retrieve the resource from the same URL and populate the form. The client can than PUT/POST changes.
How do I construct a URL to get the read-only or editable version?
There's an underlying problem here, which is that you are constructing URLs in the first place - appending IDs to hard-coded URLs is not REST. Roy Fielding has written about this very mistake. Whichever document prompts you to edit the resource should contain the URI to the editable variant of that resource. You follow that URI, whether that's /resource/editable or /editable/resource is outside the scope of REST.
If instead I use POST to retrieve the editable version, then how do I distinguish between the POST that initially retrieves it, vs the POST that saves it?
You perform a GET (not a POST) to read the resource, and POST (or PUT) to write the resource.
If you want to create a lock on the resource in question, use POST to write to the resource (or the resource's container, with the resource ID encoded in the body of the POST), and have the server create a lock as a new resource, and return an ID of that resource as the response to the POST. (with authentication issues beyond the scope of your question or this answer)
Then to unlock the lock, either use a DELETE on the lock resource, or POST to the lock's container.
I guess your question could be "how to identify the readonly representation that return with GET action in PUT action?". You could do this:
<Root>
<readonly>
<p1><p1>
...
<readonly>
<others>
...
<others>
<Root>
After parsing the request XML from PUT you can ignore the readonly part and process others. In Response, return 200 status and leave a message saying the part in readonly is ignored.
Is it your expected?
I have a detail page that gets called from various places and has a nice readable url like
"www.mypage.com/product/best-product-ever".
The calling pages (list of products) have a more complex url like:
"www.mypage.com/offers/category/electronic/page/1/filter/manufacturer/sony/sort/price" and
"www.mypage.com/bestseller/this-week".
How can I make a backlink from the detailpage to the calling product list?
I cannot use javascript
I don't want to have the calling page in the URL, because it gets to long
I really want links between pages, no http-post
I cannot use Sessionstate
EDIT:
Sessionstate is ruled out, because if there are 2 Windows open, then they would share the same "Back" page information.
Like Lee said, use the referrer value:
Back
If you don't want the URL in the link because it's too long, try running some sort of simple compression algorithm over the URL, display the compressed data as unicode text and then append the compressed URL as a parameter to a redirect page, e.g:
Back
What about using the referrer header value?
Here's a crazy idea that will require a fair but of work and may not be healthy for performance (depending on your users).. but here we go:
Create a repository for caching 'ListResults' (and wire it to persist to the DB of you like.. or just leave it in memory on the server).
In short what this Repo can do is store a ListResult which will include everything to persist the state of the current view of the list any given user is looking at. This might include routes and other values.. but essentially everything that is needed to redirect back to that specific page of the filtered and sorted list.
As the ListResult item is added to the repo a small unique hash/key is generated that will be url friendly - something like this "k29shjk4" - it is added to the item along with a datetime stamp.
ListResults are only persisted from the moment a list gets off the default view (ie. no filtering, sorting and Page 1) - this will help in a small way for performance.
A ListResult item may never actually get used but all detail actionlinks on the particular list view have the ListResult.Key hash value added to the route. So yes, it might end up as a querystring but it will be short (url friendly) and if you wanna mess with routes more, you can tidy it up further.
For navigation "back" to the list, you may need a new small controller which accepts simply the ListResult.Key hash value and redirects/re-creates the state of the list view (paging, filtering and sorting included) from the lookup in the repo.
So we have met the requirements so far: no calling page in the url (in the sense that its not the whole page - just a hash lookup of it); no POSTing, no sessions, no js.
To stop the ListResult repo from getting to big (and dangerous: if you persist it to the DB), you can use a ASP.NET background service to periodically prune the 'old' routes by way of the timestamp.. and 'extend' the life of routes that are continuously being used by adding time to the stamp of a ListResult item when it's requested via the new controller. No need to persist a route indefinitely coz if a user wants a permalink to a list view, they can bookmark the long list route itself.
hope this helps somehow
Do you have a cookie?
If so, you can put it in there, or use it to create your own session state.
I think this is more like a "Back to results" then a generic "<< back" link, because you would expect the generic back link to return to the genetic list, not the heavily filtered list you described, right?
I don't know if this falls into your "no post" condition, but the only option I can see is having the Detail action be POST-only ([AcceptVerbs(HttpVerbs.Post)]) and include another parameter like string fullRoute which is converted to the 'link' on the detail page for "Back to results". Overload the Detail action missing the fullRoute param and have the overloaded action be a GET action so that the POST fullRoute value is not required (for when users are ok with the 'generic' "Back" link). This should serve both 'generic' GET requests to the Detail page and the POST request which will include the specific "Back to results" link for the filtered list.