Rest API resource design for many-to-many relation - rest

Post can be in many Categories and Sections.
Category and Section can have many Posts
To list sections/categories using:
GET /posts/categories
GET /posts/sections
seems to be better design than:
GET /categories
GET /sections
But how to ask for Posts from sections/categories ?
This seems to be awkward (or maybe it isn't ?):
GET /posts/sections/{id}/posts
These can be problematic:
GET /posts?section={id}
because I already have couple filters, so I end with:
GET /posts?section={id}&filter1={f1}&filter2={f2}....
Any suggestions ?

I personally would use the query parameter approach to filter the posts collection given that it's a many to many relationship and the resources can be managed independently:
GET /posts?section={id}
And I would probably use the following mapping for categories and sections:
GET /categories
GET /sections
If, for example, a collection of posts belongs to just a single category, I would use:
GET /categories/{id}/posts

Related

RESTful API desgin: retrieve number of items in category

I want to create a REST API with items in categories and list all categories alongside its number of items.
Schemas:
Category {id, name}
Item {id, name, categoryId}
Endpoints:
GET /categories/list
GET /categories/<id>
PUT /categories/<id>
GET /items/list[?category=<categoryId>]
GET /items/<id>
To update a category I take what I get from GET /categories/<id>, modify the JSON object and PUT it back.
So far so good.
My question is if there are one ore more best practices to retrieve the item count?
I can think of a few ways to do this:
Fire a GET /items/list?category=<categoryId> for each category, counting the resulting items.
Taking the count from a X-total-count or content range header or a total_count field returned from the endpoint will avoid having to actually load all items.
Add an item_count field to the resulting category JSON objects.
How should this read only field be handled for PUTs? Make the backend ignore it? Manually unset it?
Create a dedicated endpoint /categories/item_counts that returns a list of categories with each number of items.
I like option number 2 (e.g. the wordpress API does it this way) because it does not need extra requests. But I really dislike the idea of having a different object structure for the GET and PUT requests.
REST is really about representation of objects. Category doesn't have a count as it's a single object. Item doesn't have a count either for the same reason. Count is more like RPC where you tell the service to compute something.
GET /items/list[?category=<categoryId>]
is like RPC, passing the category parameter to the list method. Staying in that idiom, you could "chain" the methods to get the total count of items in the specified category:
GET /items/list/count[?category=<categoryId>]
although I'd use path parameters instead:
GET /items/list/<category_id>/count
but list is implied so you could remove it:
GET /items/<category_id>/count
It's straying a bit from "pure" REST but it keeps your actual REST objects clean, as you say, keeping total_count our of your Category objects.
I'm assuming you sometimes need the count but not all the Items otherwise you wouldn't need to ask the API for the count, you'd just count them yourself in the client. That suggests another option:
GET /categories/<id>/count
{
"total_count": 10
}
which fits better with the use case of finding out how many Items are in a Category.

Rest API: How should the filter params send to API in case query based on nested resource

I have two entities Properties and Bookings.
I need to know the URL structure in case I'm filtering the properties base on query on bookings.
In my case I need to get the properties which are free (not occupied) at specific date.
Can it be
api/properties/free/{date}
Or
api/properties/bookings?bookingDate!='1-1-2017'
Or
api/properties?bookingDate!='1-1-2017'
it seems for me that the last one is the more appropriate but the filter is on the bookings not on the properties which is not obvious.
The Facebook Graph API has a interesting way of doing nested queries by using a strategy of fields filter.
The fields filter it´s a way of filter specific fields or nested fields of a rouserce. They also create a standard way to inform functions for every selected field like: limit or equal.
Your request would be something like this:
GET /api/properties?fields=bookings{bookingDate.notEqual('1-1-2017')}
For more information about Facebook´s GraphAPI:
https://developers.facebook.com/docs/graph-api/overview/

Is there way to create & index N no. of 'fields' dynamically with Sphinx

I am using Sphinx (with Thinking Sphinx v2.0 for RoR plugin),
Lets say I have several indexes on User model, lets say on 'name', 'address' and its one-to-many associations like 'posts' , 'comments' etc.
This means searching by post content would return me the User who made the post, and using :fieldmask 'rank mode' of sphinx, I am able to determine that the user was searched due to matching of 'posts'. But user has 'many' posts. So how to determine which 'post' it matched.
Is there any way, while indexing I can specify the index dynamically.?
For e.g. If I can specify index 'post_1'='< post1content >' , 'post_5'='< post5content >' as different 'fields' for user1; similarly 'post_2', 'post_7' for user2, Thus after searching It would return me user2 matched with matching fields as post_7...
Sphinx can't have different fields for each record, I'm afraid, so what you're hoping to do isn't possible with that approach.
If you need to know which posts match a query, I'd recommend conducting the search on the Post model instead, and then you can refer to a post's user? You could sort by user_id before weight, or group by user_id (so only one post per user is returned)? You'd be able to bring in user data into the Post index definition (and if a post has one user, then that data is kept to single values, instead of many, per record).
Hope this gives you some clarity with your options.
If you know, you want to search for post_5 in one query, and for post_7 in another query, you may use json as {post_1:, post_2:}.
Problem is that you have to know number of post you are searching for.
Maybe look to: https://stackoverflow.com/a/24505347/1444576 -if it is similar to your example.

What are possible values of 'relationship' field returned from Facebook Graph API /me/family query?

Can't seem to find it in the docs or here. Starting to think this list does not exist.
I'm looking for a complete list of (or a way of generating such a list) possible values that can be returned in the 'relationship' field of Facebook Graph API queries like this:
https://graph.facebook.com/me/family?access_token=ACCESS_TOKEN
(You will of course need to supply your own ACCESS_TOKEN to see the results of such a query. The API explorer is good for that kind of thing - https://developers.facebook.com/tools/explorer/).
As described here -
relationship -- A string describing the type of relationship. Can be one of parent, mother, father, sibling, sister, brother, child, son, daughter.
If you look at the FQL family documentation, the relationship field is listed as a string. These usually are not enumerated anywhere.

Best way to give options for starts with or contains in REST query

I have a REST service that allows people to put in a course title as part of the query to get scores, but, sometimes they may want to get a group, such as Calculus% for Calc 1, 2 and 3.
But, what is the best way to give them an option that makes sense?
For example, I have http://localhost/myrest/any/any/Calculus III
where the first two parameters are student id and some grade category.
I don't think having http://localhost/myrest/any/any/contains/Calculus III is a good use as then I will need to force them to use equals if that is what they are looking for.
Another option is http://localhost/myrest/any/any/Calculus% or http://localhost/myrest/any/any/%Calc% is another option, but then you have removed the option to easily use % as an allowed character.
So, to give additional filtering options in a REST URL, what is the best (defined as simplest/most intuitive for the user) way to allow contains or starts with.
In your system, would the following query list all subjects in the grade category?
http://localhost/myrest/any/any/
If yes, then one option you can consider is extracting the non-exact subject name into a GET parameter. Thus without breaking the current logic where having a full name of the subject in the URL provides the score for that subject, you'd also have the ability to filter the list of subjects within the same grade category by means of the GET parameter.
For example:
http://localhost/myrest/any/any/?search=Calculus*
... could provide a result like this:
<subjects>
<subject uri="/myrest/any/any/Calculus%20I">A</subject>
<subject uri="/myrest/any/any/Calculus%20II">B</subject>
<subject uri="/myrest/any/any/Calculus%20III">C</subject>
</subjects>