I have a dilemma in my current project about my url. I would like opinions about how can I choice my route to access a resource.
For example, if a a USER can follow an other one, should I use /users/{user_1_id}/follow/{user_2_id} or /users/follow/{other_user} or /users/folllow with the id in parameters ?
I personally think that /users/follow/{other_user} think to be the best, but I don't know if it's the good choice.
Can I have your opinions ?
As for REST-Services you may consider having your services "state-less"... Therefore I would suggest to add all parameters needed for the service to process the request.
/users/{user_1_id}/follow/{user_2_id}
It gives you a.) better readability and better understanding of the service based on it's API (the URL) and b.) you will be thankful if you've to replace that service in the future (no headaches about where all the needed information is, no caching involved, less side-effects)... Other team-colleagues don't need to know more details about the service ("is the user cached in the background", "or is there a hidden user-id in the cookie", etc.)
Related
I'm developing an app on which regular users should have read and write permissions on their own data, while admins have read permission on everybody's.
In my design, admins can:
GET /users
GET /users/:id
But for regular users, two routing schemas came to mind. The first one being just a continuation of the first:
GET /users/:id
GET /users/:id/edit
PATCH /users/:id
and the second being another resource that is dependent on the user that's logged in:
GET /profile
GET /profile/edit
PATCH /profile
The advantage I see on the second approach is that the design itself doesn't allow users to change the URL and try to edit other people's records.
However, Wikipedia says:
A Uniform Resource Identifier (URI) is a string of characters that unambiguously identifies a particular resource.
and as I understand it, /profile doesn't fit that description since different users will see and update different records.
So, the questions are:
Does /profile make a proper URI?
Does it violate REST?
What might be other implications of such design?
Thanks <3
PS: probably URN is a more accurate term than URI in this situation.
As best I can tell, it isn't really a good idea, but you will probably get away with it if you go that route.
First, it's important to recognize that one of the very powerful implications of URI that identify a resource is that you can easily share that URI (for example, pasting it into a message), and the recipient can just use it. In the usual case, the identifier means the same thing no matter who is using it, which is to say that both clients and the server all agree what the URI refers to.
You lose some of that semantic agreement when you start experimenting with providing personalized representations of resources depending on the identify associated with the query.
A second issue is that the target-uri is an important element in HTTPs caching story; there are other condition in play, but a primary condition is whether the target-uri in the request matches the target-uri of the stored response.
So it's easy to image: Alice asks for a representation of some resource, but instead of seeing her own view of the resource, she sees a representation of Bob's view of the resource, because his was available in some public cache.
Which would be pretty awful.
That doesn't actually happen though; how do we tell Alice from Bob? The standard answer is that we have that information in the Authorization header field. HTTP caching, however, has special rules that take effect for shared caches when the request includes an authorization header.
So these rules are going to protect you unless you go out of your way to make a mess of it (for example, by using the public cache control directive).
In summary: can you? Yes, absolutely. Should you...? I eventually decided that I shouldn't. If I need to be clever with a pronoun URI then I will use it to redirect to the appropriate resource, rather than leaning upon content negotiation via the authorization header.
As with most questions, the answer is "it depends" - in this case it depends on who is the primary consumer of those URIs. If it's a user then /profile is perfectly acceptable since there's the additional requirement of user experience. Together with the state provided by the session cookie it uniquely represents a user. To give another example - which would be better on an e-commerce website /basket or /baskets/:id? Obviously it's the former since it allows a user to navigate directly to a URI without having to remember what their basket id is (which is likely to change over time).
Conversely, if the primary user is an API client then the format /users/:id may be more appropriate since that allows for a more consistent approach to coding. Though even here it may still be worthwhile providing some affordance with a URI like /users/current. Even if you follow the principle of HATEOAS in an API you'll still need to get the relevant URIs to call from some singleton resource like the root path.
In general the thing to remember is that these are guiding principles and not hard and fast rules - what makes sense for your application and context may not be the same for other people's applications.
I think the question is: "Should my route be called /profile based on the context of my program?" I don't think it should. I think you should have a base user and run something like permission levels. Like is_admin or is_moderator.
I'm looking at the Delicious API and see the following is the operation to create a new bookmark:
https://api.del.icio.us/v1/posts/add?&url={URL}&description={description}
It looks like they're using a GET request to create server-side database entries, which I've read elsewhere shouldn't be done with GET requests, only with POST requests.
I'm writing my own API right now and I think that it's fabulous to let users interact with the API directly from the URL. But you can't do this unless you allow CRUD operations over GET.
So, is Delicious really doing CRUD operations over GET? Is there an important reason I shouldn't do the same thing in my API, or is POST just mandated for CRUD to prevent accidental invocation?
Accidental invocation is part of it; that's what the HTTP spec means when it talks about "idempotent" methods. But you could argue that what Delicious is doing is actually idempotent as long as the URL only gets added once no matter how many times you GET. But more importantly is that GET is safe:
The important distinction here is that the user
did not request the side-effects, so therefore
cannot be held accountable for them.
From an interface design standpoint, you want user-agents to make POST and PUT and DELETE more difficult than GET, or at least distinctly different, so that users can rely on that difference to hint when their actions might cause a change in the resource state, because they are responsible for those changes. Using GET to make changes, even if idempotent, blurs that line of accountability, especially when prefetchers are widely deployed.
That depends if you follow the REST principles GET for changing things is forbidden. Therefore most people say with REST use POST for changes.
However there is a difference between GET and POST. According to the RFC GET requests have always a followup RESPONSE. And if you use POST you need to follow the Redirect-After-Post pattern.
Another limitation is that URLs may have a limited size. So GET will only work as long as your input data is short enough. So the delicious API has there a bug. You will not be able to add every possible url via a GET parameter.
For one of my project's (weird) requirements, I want to use cookie less sessions. At the same time, "session.use_trans_sid" can not be turned on :(
Does anybody please let me know if is there any other way out ??
Thanks
Manish
Make a custom session manager that identifies the user based on, for example, IP address and user agent and other identifying factors (as IP+UA might not and probably will not be unique). Another (ugly) solution is to just implement the use_trans_sid functionality yourself by adding a session identifier GET parameter to every link by hand (if it's a small site) or with a hidden form (that's non-standard).
If you really want sessions without cookies, you can always put the SID in all your URLs manually. People used to do this quite a bit. :-)
The only other option is to keep the session data on the client and pass it back and forth to and from the server with each request, although technically that would be a sessionless architecture.
That means that for GETs each link has to be rewritten to include all the session variables, and for POSTs they have to be included as hidden fields.
I'm designing a hosted software-as-a-service application that's like a highly specialized version of 37Signal's Highrise product. In that context, where SEO is a non-issue, is it worth implementing "pretty URLs" instead of going with numeric IDs (e.g. customers/john-smith instead of customers/1234)? I notice that a lot of web applications don't bother with them unless they provide a real value (e.g. e-commerce apps, blogs - things that need SEO to be found via search engines)
Depends on how often URLs are transmitted verbally by its users. People tend to find it relatively difficult to pronounce something like
http://www.domain.com/?id=4535&f=234&r=s%39fu__
and like
http://www.domain.com/john-doe
much better ;)
In addition to readability, another thing to keep in mind is that by exposing an auto-incrementing numeric key you also allow someone to guess the URLs for other resources and could give away certain details about your data. For instance, if someone signs up for your app and sees that their account is at /customer/12, it may effect their confidence in your application knowing that you only have 11 other customers. This wouldn't be an issue if they had a url of /customer/some-company.
It's always worth it if you just have the time to do it right.
Friendly-urls look a lot nicer and they give a better idea where the link will lead. This is useful if the link is shared eg. via instant message.
If you're searching for a specific page from browser history, human readable url helps.
Friendly url is a lot easier to remember (useful in some cases).
Like said earlier, it is also a lot easier to communicate verbally (needed more often than you'd think).
It hides unnecessary technical details from the user. In one case where user id was visible in the url, several users asked why their user id is higher than total amount of users. No damage done, but why have a confused user if you can avoid it.
I sure am a lot more likely to click on a link when I mouseover it, and it has http://www.example.com/something-i-am-interested-in.html.
Rather than seeing http://www.example.com/23847ozjo8uflidsa.asp.
It's quite annoying clicking links on MSDN because I never know what to expect I will get.
When I create applications I try my best to hide its structure from prying eyes - while it's subjective on how much "SEO" you get out of it - Pretty URLs tend to help people navigate and understand where they are while protecting your code from possible injections.
I notice you're using Rails app - so you probably wouldn't have a huge query string like in ASP, PHP, or those other languages - but in my opinion the added cleanliness and overall appearance is a plus for customer interaction. When sharing links it's nicer for customers to be able to copy the url: customer/john_doe than have to hunt for a "link me" or a random /customer/
Marco
I typically go with a combination -- keeping the ease of using Rails RESTful routing while still providing some extended information in URLs.
My app URLs look something like this:
http://example.com/discussions/123-is-it-worth-using-pretty-urls/
http://example.com/discussions/123-is-it-worth-using-pretty-urls/comments
http://example.com/discussions/123-is-it-worth-using-pretty-urls/comments/34567
You don't have to add ANY custom routes to pull this off, you just need to add the following method to your model:
def to_param
[ id, permalink ].join("-")
end
And ensure any find calling params[:id] in your controller is converted to an integer by setting params[:id].to_i.
Just a note, you'll need to set a permalink attribute when your record is saved...
If your application is restful, the URLs that rails gives you are SEO-friendly by default.
In your example, customers/1234 will probably return something like
<h1>Customer</h1>
<p><strong>Name:</strong> John Smith</p>
etc etc
Any current SEO spider will be smart enough to parse the destination page and extract that "John Smith" from there anyway.
So, in that sense, customers/1234 is already a "nice" URL (as opposed to other systems, in which you would have something like resource/123123/1234 for customer 1234 resource/23232/321 for client 321).
Now, if you want your users to be regularly using urls (like in delicious, etc) you might want to start using logins and readable fields instead of ids.
But for SEO, ids are just fine.
I'm designing (and developing) web software that will allow the general public to sign up for a service, become a customer, and exchange fairly sensitive data.
I'm working through the documentation and the tutorials, and of course the RESTful pattern adopted by the default routing in ASP.NET MVC is to do URL's like this: /customer/edit/3487.
I guess I am a little squeamish about displaying such technical details as customer ID in the URL bar.
What do the smart kids do these days? Does RESTful have to mean "put your record ID's on display"?
Edit: In an ASP.NET WebForm I would have stored this in the session, I think. But I'm finding that this is discouraged in ASP.NET MVC.
Edit:
I do not intend to rely on security through obscurity.
That still doesn't mean its a good idea to give the users any ideas, or any information about the underlying data. Let's say I have an app that's publishing information about the different business in a Chamber of Commerce, to be arbitrary. Once you are logged in, you have an administrative right to click on every business in the directory and see them all - but the application is supposed to spoon feed them to you as search results or the like. Just because the user technically is allowed to access all records, this doesn't mean it should be trivial for you to write a screen scraper that downloads all of my content in a few minutes. As well, the user can just look at customer ID's and make a guess about how many customers I might have. There's lots of good reasons not to display this.
As long is there is proper authentication and authorization being done on server side then displaying ids is not an issue.
Otherwise just try to encrypt the particular id or username in the URL, this way it will be difficult for the attacks.
You don't have to put the Id in the Url, you just need to use a unique value or unique combination of values to find the data you want to display.
I'd think that the actual bussinesses name would be good and also look good in the Url. So you would have something like this:
/Business/View/theouteredge/
Or if the business name is not unique you could use a combination of business name and zip/postal code.
/Business/View/theouteredge/78665/
You would have to write a new route to handle this.
routes.MapRoute(
"Bussiness",
"Business/{Action}/{name}/{zip}/",
new { controller = "Business", action = "Index", Name = "", PostalCode = "" }
);
All this action would need to be secured with the [authorize] attribute, or the controller its self.
If you also decorate your actions with [authorise] then if another user does use the id from another user, they will automatically be challenged for a login.
It's 6 of one and 1/2 dozen of the other as to whether you use an ID or a Name. Eventually they both resolve to a record.
The important thing is to only allow authorised persons to view the data by allowing them to log in.
I've got a site which has sensitive data but only if you are the holder of that info can you see it and I do that by decorating my actions and checking rights etc.
I think that putting an ID in a url is fine -- as long as it is a Surrogate Key. The key has no value, except to identify a record. Just make sure that the requester is authorized before you send sensitive data back to the client.
Update:
I can see how having a number as part of your URL is undesirable. After all, a URL for a web app is part of the user interface, and exposing such internal details can take away from the UI's elegance. However, you are faced with limited options.
Somehow, you have to identify the resource that you want to get. The crux of REST (IMO) is that a request to a server for a particular resource must be described entirely by the request. The key for the item you want has to be encoded into the HTTP GET somehow. Your options are: put it into the URL somehow, or add it to a cookie. However, adding a key to a cookie is frowned upon.
If you look at this site you will see the question id in the url. If you view your profile you will see your username. So you would probably want to use usernames intead of an id.
If you're really concerned about it you can use a Guid, which isn't very user friendly but would be very hard to guess. :)
If you use some other way than customer id simply because you're concerned about security, then that means you're using security through obscurity, which is a bad idea. Proper authorization would require something like you either 1) have to be logged in with that customer id, or 2) be logged in as an admin, to have that request succeed.