Rest API, relationships and subsets - rest

I have some questions about Rest API and relationships.
I know the questions of relationship is always tricky with Rest.
I have some users, posts (created by user), relationships between users (imported from fb), interactions on posts (created by user) and users can like a post.
User can create a posts which will be seen only by others users who have a relationship (up to 2 jump, like friends of friends) with the poster and then can create interactions on the post.
We do a filtering on the backend based on your authentification and just do the magic on /posts which will return you the list of post that you can see.
It feel a bit funky to me because it make the same endpoint (/posts) will return different set of data based on the current user. We could of course pass a parameters (?viewable_by_user_id=:id) to reflect it a bit more, but I wonder if I can do anything to improving caching.
I'm thinking of improving our API to a v2 with this endpoints:
GET/PATCH/DELETE /users/:id
POST [post] /posts: create a post (using current auth user as the owner of the post)
or
POST [post] /users/:id/posts: create a post for this user
GET /users/:id/posts : get posts created by the user
GET /users/:id/stream : get posts "viewable" by the user (this is the one I'm strugeling with)
or
GET /posts?viewable_by_user=:id
GET /users/:id/like : get posts liked by the user
POST [post_id] /users/:id/like : like a post
POST [interaction] /posts/:id/interactions : create an interaction on the post for the current user
GET /posts/:id/interactions : get post's interactions
GET/PATCH/DELETE /interactions/:id
Any thoughts on how I could make the path reflect a bit more the relationship?
I've thinking on creating an endpoint for relationships but seem a bit to complex to maintain (users don't create relationship manually, we pull them from fb)
Thank you for any feedback, and let me know if my question is too ambiguous or irrelevant.

What if you think of it as this: (Note that I just like putting "posts" first since it tells what and then the restrictions go to the right of that. You may like the other order.)
GET /users/posts/<viewer>/<creator>
This gives some degenerate cases:
GET /users/posts/<me>/<me>
to get all the posts I have created
GET /users/posts/<me>
to get all the post from all other users
GET /users/posts/<me>/<stranger>
would return nothing because I am not allowed to see the stranger's posts
GET /users/posts/<me>/<friend>
would return the posts from my friend.
NOTE: In all cases, all posts returned are those allowed to be seen

Related

REST: nested resource url when you don't want the parent ID visible

I read that the route for getting a nested resource in REST should look like this
/articles/:articleId/comments
The owner (:articleId) of the child resource will be visible.
But what if you have an owner that you don't want the client to know about?
For example, let's say I have an app where users have anonymous posts. I wouldn't want other users to see the client fetching the post by /users/123/post/321 because users could identify who wrote the post from the id and it wouldn't be anonymous.
Is the id necessary? Is it ok to instead do /users/posts/321 if all posts have a unique id?
There are no actual requirements for the URL format. It can be whatever you'd like it to be.
If it were me, I would use simply /posts/321 and leave users out of it, since a particular user isn't specified in your URL at all. I think that's the clearest way to handle it in your case.

Sub-collections in REST api

How many sub-collections can have a resource?
Just imagine that we have this model:
accounts -> posts -> comments
Everything is clear for accounts-posts pair.
/accounts/{account_id}/posts/{post_id}
But what about comments? What is a proper way to point to a single comment?
/posts/{post_id}/comments/{comment_id}
or
/accounts/{account_id}/posts/{post_id}/comments/{comment_id}
or (direct pointing)
comments/{comment_id}
The general rule of thumb is to only go one layer of subresources deep. An account may have many posts like you show, and a post may have many comments, but since the post id is unique, including the account id is a bit redundant when trying to get the comments for a post.
/accounts/:account_id/posts
/posts/:post_id/comments
Ruby On Rails also lists this in their docs (just for a bit of a citation). https://guides.rubyonrails.org/routing.html#limits-to-nesting
Additionally, if you already have the id of a resource you don’t need to nest it. As short of a route that gets the job done is preferred.
/comments/:id

Restful Collections - how to either remove OR delete items

I read quite some stuff about RESTful API Design.
But when it comes to the implementation, it wasn't that easy anymore.
I got stuck at the following problem:
Assume the following 2 endpoint:
/api/v1/users/:id
/api/v1/users/1/friends/:id
As we all can see, friends is a collection of the resource user.
A user can have n-friends in his friendslist (by standard this would be many to many, but for now, let's assume this to be one to many).
Okay, now i want to REMOVE a user (id=3) from the friendslist of user 1 by doing the following HTTP-Request:
DELETE api/v1/users/1/friends/3
And this is where i got stuck - either the request deletes the whole user resource which has id = 3 or removes the resource from the collection. Because both would be valid Restful implementations i think.
So the question is:
How to remove an item from the collection without deleting the original resource
I hope that this question is no duplicate - but i did google a lot to find the answer. Maybe i don't know the related technical term to find some pleasing results...
Thanks in forward.
The approach to REST looks fine but that really only speaks to path format and HTTP verb. The problem must be in your application code or app routes.
I think it is better that DELETE api/v1/users/1/friends/3 would be used to delete user 3, just like DELETE api/v1/users/1 would be used to delete user 1.
To remove just user 3 from being a friend of user 1 I would use DELETE api/v1/users/1/friends and specify a filter to only remove friends with the id of 3.
DELETE api/v1/users/1/friends without a filter would remove all friends of user 1.
Likewise to add friends of user 1 I would use PUT api/v1/users/1/friends and specify the ids of the friends to add.

Facebook Graph API: Find graph object from post URL

Given the URL of a public Facebook post, how can one find the post object in the FB Graph API? (secondarily, why are so many user feeds empty or nearly empty when accessed through the API?)
We would like to be able to comment on or like a post via the v2.x
Graph API, given the post's URL. Doing so requires the post's object
ID, which we can make some educated guesses about, but accessing
the actual object through the API has proven unreliable (works for some posts but
not others).
v2 of the API introduced app-scoped user IDs, and post IDs generally seem
to be of the form {app-scoped user id}_{unique post id}. Here are the
details of some attempts to find posts in the API with various combinations of
these IDs (global user id, app-scoped user id, and post id).
Starting with a simple example: https://www.facebook.com/evan.prodromou/posts/10153023417510505. Key characteristics are that it's public, it's not a share of another post, and most importantly it has no photo(s), which add extra ids and URLs for the individual photo(s) and photo set. Evan's profile is also public, i.e. https://www.facebook.com/evan.prodromou doesn't show the generic This content is currently unavailable
Trying the bare post id from that URL, /v1.0/10153023417510505 and /v2.2/10153023417510505 both give the Unsupported get request (code 100) error.
Evan's global user id is 525575504. Attaching that as a prefix, /v1.0/525575504_10153023417510505 and /v2.2/525575504_10153023417510505 still both give the same Unsupported get request error.
Same error using his app-scoped user id instead, /v2.2/10152350676805505_10153023417510505.
OK let's try the other direction. We'll page through the user's feed until we find the post in question. It feels like this is more the expected use case for the API...
Both the global /v2.2/525575504/posts and app-scoped /v2.2/10152350676805505/posts return nothing, but /v1.0/525575504/posts returns two recent posts, this like and this post. Not sure why only those two, even though has plenty of other recent public posts. The like is fetchable via its id field in both api versions, i.e. /v1.0/525575504_10153045879215505 and /v2.2/10152350676805505_10153045879215505, but both API versions return the Unsupported get request error when fetching the post via its id field, e.g. /v1.0/525575504_351575675029953 and /v2.2/10152350676805505_351575675029953
Trying another public post, this one with pictures: https://www.facebook.com/andigalpern/posts/678121182314631 . /v1.0/100003502653187_678121182314631, /v2.2/100003502653187_678121182314631, and /v2.2/499657186827699_678121182314631 all error.
/v1.0/100003502653187/posts only includes one post, a like, and /v2.2/100003502653187/posts is empty.
For reference, here is the GitHub issue where we have been tracking this problem.
Basically you would need read_stream for this (which your app will not get granted). And yes, even though the post is public, you still need read_stream to be able to get read access to all kinds of posts.
You can easily play around with this in Graph API Explorer. First give your app read_stream permission to get ids of items in your feed – that will give you ids of the “form app-scoped user id underscore post id”. Then remove read_stream (by clicking “Get Access Token” again and using the “Clear” button), and try several of the user_* permissions – and you will see that for most of your posts, even the public ones, you will still only get “Unsupported get request”, which just means you are not allowed to read that object.
F.e., I have a public post where shared a video post from another page on my timeline, the type is video and status_type is shared_story, but neither user_status nor user_videos allow me to read this post – only when I grant read_stream again, my app can read that post. Same with another public post of type status and status_type mobile_status_update – readable with read_stream, not with any of the user_* permissions.
In short: What you want to achieve is not possible any more with API v2 and the restriction that read_stream will only be granted to apps on platforms where no official FB client exists.
A one proposition is to make api calls to write facebook posts since those return valid post_id that you could use
Second,
When you try https://developers.facebook.com/tools/explorer/256884317673197/?method=GET&path=525575504%2Fposts&version=v2.0&
You can see that his posts ID's are not starting with his public id as you wrote 525575504_*
but they still put unsupported get request
https://developers.facebook.com/tools/explorer/256884317673197/?method=GET&path=10152853212485505_351575675029953&version=v2.0
Third since above doesnt work are those posts public for sure?

Issue when trying to requery on postID using facebook graph

Forgive me I'm new to the Facebook graph concept. I've read through the documentation and am a little lost on something that I want to try and do. I have been able to query posts based on a keyword such as "sailing" like so:
http://graph.facebook.com/search?q=sailing&type=post
I see that it returns a result set containing 25 of the most recent posts with the keyword provided. My issue comes when I try to take a post id and query it directly. What I want to do is to be able to take a post id and query it after a 24hr time frame to see if it has received any comments and to see how many likes it has gained since being posted.
I can take the userID_postID and query like:
http://www.facebook.com/userID/posts/postID
I can see the post with the likes but when I try this in the graph:
http://graph.facebook.com/userID/posts/postID
I get the following error message:
{
"error":
{
"message": "Unknown path components: / postID",
"type": "OAuthException",
"code": 2500
}
}
I've seen where people have commented that if you want to access a post you will need to get an access_token. I'm not sure why you need an access_token to access a post that you originally obtained without one. It doesn't seem to make sense. One thing that I have noticed when trying to do this with different posts is that this seems to be related to accessing posts of an individual rather than a fan page. Whereas a public page such as a fan page seems to return the results.
I also tried querying like:
http://graph.facebook.com/userID_postID/likes
this returns the likes for a public page such as a fan page but doesn't return anything for an individual page. Can anyone help point me in the right direction or maybe give me some explanation on what the proper way to handle this would be? Requesting an access_token from the user is something I do not want to do, this is mainly for a service that we're trying to create that allows us to survey based on a keyword. Any help would be much appreciated, thanks.