Best way to design a URI for REST API - rest

I am designing a REST API with similar functionality as of Posts and Comments in Facebook.
URI looks like:
/posts/{post-id}/comments/{comment-id}
To get all the comments I use the collection URI naming standard. For example:
/posts/{post-id}/comments
But I am having difficulty when I need comments for all the posts. What would be the best way to incorporate that keeping in mind that I want to use this design only for posts and comments?
Edit
I have to mention here that the resources I am using are a bit different from posts and comments in a way that the in my design I will have to use posts and cannot have comments as entirely different entity. Sorry for the misunderstanding.
Said that, is it recommended to design URI in any of these ways:
/posts//comments
/posts/"any-string"/comments

But i am having difficulty when i need comments for all the posts. What would be the best way to incorporate that keeping in mind that i want to use this design only for posts and comments.
HTTP includes the concept of redirection - a general facility for telling the client to send a request to some other resource.
GET /714eeebd-d89e-4f13-b2a8-cf8a3ee03481 ...
307 Temporary Redirect
Location: /7604abf9-d4f5-42c7-b687-96dbff32649f
What this means is that, if you choose the wrong spelling for your URI, you can correct it later.
The design of REST is such that identifiers are opaque - nobody other than the server is supposed to be extracting information from them.
Also, keep in mind that resources are not domain entities -- it's normal to have many more resources than you have domain objects. Any given Post in your domain model might have many different resources that show it.
If you are really developing a REST service, and you want to "help" clients by making it difficult to cheat, you may want to abandon the idea of using a hackable identifier.
All that said
/comments
is a perfectly reasonable collection identifier all on its own, and its perfectly reasonable to create an identifier hierarchy under that root.

Below URI should serve the purpose.
/comments
For the above given example, let's understand the relationship of entities and URI:
posts and comments are two entities on its own.
when you need only posts and just passing post_id
To retrieve the posts:
/posts
To retrieve a specific post:
/posts/{post_id}
when you need only comments and just passing comment_id
To retrieve all comments:
/comments
To retrieve specific comment:
/comments/{comment_id}
when you need comments for a given post by passing both post_id and comment_id
To retrieve comments on a post:
/posts/{post_id}/comments
To retrieve specific comment for given post:
/posts/{post_id}/comments/{comment_id}
Hope it solves your issue.

Related

RESTful page needs both GET and PUT?

My web site has a design where a grid of records is shown. For each record the user might edit it (a GET request) or change its status (this should be a PUT). Do I have a way of doing this without using Javascript?
That is, my current options are:
Use Javascript in a link handler to change the request type as needed.
Separate the GET and PUT activities to separate web pages.
Do the status change via a GET and turn a blind eye to REST specifications right here.
Are there other options?
Thanks,
Jerome.
A GET should not have any side-effects and a PUT would replace the whole resource at the location given by the URI. So the former should be a POST. The latter should be as well, unless it does in fact send the whole resource. A POST is possible without Javascript, obviously.

RESTful GET/POST Form Semantics

When I GET from http://example.com/organization/ I get a list of organizations.
When I GET from http://example.com/organization/xyz/ I get the record for the organization xyz.
When I POST form data to http://example.com/organization/ I create a new organization.
What URL should I use to GET a form to fill out to create a new organization via a POST to http://example.com/organization/?
Looking at How to do a RESTful request for an edit form? and other sources, it would seem that I am really looking for a form resource for organizations -- so I should GET that form at something like http://example.com/organization/form/ and POST to http://example.com/organization/ as described above. This seems...untidy though.
Update
tuespetre's comments have me thinking the best way to do this is to have a form resource. The organziation form is provided via a GET to /form/organization/ which is filled out and posted to /organization/.
A form in the sense that you speak of one is not a resource, but a template to gather user input to POST a new resource.
One really 'RESTful way' to do it would be to utilize some Javascript to 'include' that form in the collection page /organizations, either as a hidden 'slide-down' form or maybe a modal dialog that appears when a certain call to action button is pressed. This would make semantic sense for two reasons:
You won't have to have some arbitrary URI being used for the form (which is not really a resource in the sense that your domain objects are), and
the 'create' form is for POSTing to the collection, so it really closely relates to that collection and thus would not be at all out of place to have right there with the collection.
Of course, you will find many opinions on this, but I would rather not have arbitrary URIs that break the established pattern (i.e., you're not getting an organization with an id of 'new', so why have that inconsistency?)
If you're trying to implement it, I've seen it done in different ways and I don't think there's a rule (but there are different patterns/approachs that you could follow or not).
I would make it http://example.com/organization/new/

How to access links provided on one's timeline?

I would like to have access to the links one shared on their timeline.
Using the API Graph Explorer, I see there is a way to access "links". However, it returns empty data. I believe that this might have been used when posting links in FB was done in a special way, different than posting "usual" status.
Then, I thought, I should probably get all the stream and filter the data for links. But at that point, I'm a little confused:
There are THREE different actions that seem to provide the very same data:
- https://graph.facebook.com/me/feed
- .../me/posts
- .../me/statuses
Are they actually all the same?
In addition, all seem to provide me information that is not up to date, but is true for some point in the near past. Moreover, I would like to know how I can get the relevant data from the beginning of the FB usage, or at least, for a given period of time.
Do an HTTP Get to me/links to get the most recent links the user has shared.
To limit it to a timeframe, you can do me/links?since=YYY&until=ZZZ.
Or you can use the paging object to get the previous and next url to use to get that other page of data.

Facebook Graph API SEO Comments and Profanity Filter

I'm trying to integrate the Facebook comments left on our site in a way in which the content can be crawled by search engines and also for people (although I highly doubt there will be many) who don't have Javascript enabled on their browser.
Currently our Facebook comments are displayed via the use of the Facebook comment social plugin (using the <fb:comments href="MY_URL" num_posts="50" width="665"></fb:comments> tag). This ends up rendering an iFrame (which are mostly ignored by search engine crawlers) so the plan is to render this information and format it with basic HTML. To do this, the comments are pulled using the Graph API - this is then only be displayed to crawlers and people with Javascript disabled.
This all works nicely using the Graph API call (https://graph.facebook.com/comments/?ids=MY_URL), parsing the JSON result and displaying it on the page. The problem is that the <fb:comments> approach filters our results based on a blacklist we have set up on one of our Facebook Apps. The AppId with the relevant blacklist is stored on the page using metadata (<meta property="fb:app_id" content="APP_ID"/>) which the <fb:comments> control obviously must somehow use to filter the comments.
The problem is the Graph API method does not filter any results as I guess no blacklist (or App Id containing a blacklist) is specified. Does anyone know how to specify a Facebook App ID to the API call URL or of another way to not fetch commnents back that violate the terms of the blacklist?
On a side note, I know the debate about filtering content in comments rages on but it is a management decision to implement the blacklist, and one that I have no influence in changing - just incase anyone felt the need to explain the reasons why content filtering is or isn't a good idea!
Any thoughts on a solution?
Unfortunately there's no way to access a filtered list of comments using the API - it might be a reasonably request to have this in the API - you should file a wishlist item in Facebook's bug tracker
Otherwise, the only solution I can think of is to implement your own filter on your side when retrieving and displaying the comments from the API.
According to the Comments plugin documentation the filter on Facebook's side is implemented as a simple substring match, so it should be trivial to implement.
A fairly simple regular expression match should be able to check each comment against a relatively long list quickly.
(Unfortunately, the tradeoff here is that implementing a filter is easy, but you'd also need to write an interface so that whoever's updating the list of disallowed words can maintain the list for both the Facebook plugin, and your own filtering.)
Quote from docs:
The comment is checked via substring matching. This means if you blacklist the
word 'at', if the comment contains the sequence 'a' 't' anywhere it will be
marked with limited visibility; e.g. if the comment contained the words 'bat',
'hat', 'attend', etc it would be caught.
Pretty sure there is no current way of doing this from the graph API, the only thing I can suggest is taking the blacklist and build your own filter

MVC2 Routing and Security: How to securely pass parameters?

I'm a relative MVC noob coming from WebForms. I think I have a pretty good grasp of MVC with a couple exceptions, and I think I may have broken the pattern. I'm gonna try to keep this short, so I'm assuming that most of what I am asking is relatively obvious.
Let's say I have a news site with articles. In that case, a URL in the form of mynewssite.com/Articles/123 works just great because I don't care who views which article. The user can change the ArticleID in the URL to whatever they want and pull up that article. In my case, however, I only want the user to be able to view/edit data entities (articles, or whatever) that belong to them. To achieve this, I am using their UserID (GUID) as a foreign key in the database, and displaying a list of their data for them to choose from. Here comes the problem... when they click on the link that is created by Url.Action("Edit", New With {.id = item.id}) (I'm not using ActionLink because I need to add HTML content inside the link), the id shows up as a querystring parameter. I could add a route for it, but the id would still show up in the URL for them to tamper with. The obvious implication is that by tampering with the URL, they could view/edit any entity that they want.
What am I missing?
Is there a good way to pass the parameters without adding them on the URL? I know that I could put them in a form on the page and submit the form, but that seems cumbersome for my example, and I'm using jQuery.ajax in places that seems to conflict with this idea.
I could also check their UserID against the data in the Edit method, but that also seems cumbersome, too.
Is this question too broad? Please let me know what specifics you need. Thanks.
Even in Winforms, you would have to add special logic on each request to filter only the articles that the user owns. I don't see why MVC should be any different. Sure, you can use web.config to deny access to given url's, but not when you use a single page that takes a parameter of what data to show.
Your best bet is probably to filter this at the database level. By adding a where clause that includes the user id, then the app will return a "no records found" sort of error, and you can do whatever you want with it.
You could use forms authentication. This way when the user authenticates an encrypted cookie will be emitted which will contain his username which cannot be tampered with. Then you could verify whether the currently connected user has authorizations to edit this article.