2

I am creating a REST API and I have, for example, Authors and Posts.

So I can get the posts published by an author with:

/authors/123/posts

Or

/posts?authorId=123

I think building a flexible API might be a better option. To get posts by author I would do:

/posts?authorId=123&published=true&sort=created&expand=tags,category

So in this case I am getting all posts from authorId=123 that are published sort them by created date and also get the tags and category of each post.

Basically, I create a query language that kind of maps to each database table.

Then for common queries I create specific endpoints:

/posts/recent

Would return recent posts independently of the author ...

I think /authors/123/posts might become complex when using many levels.

What do you think?

UPDATE

After a few answers my idea is the following:

When Posts and Authors are two resources I would have (example for posts):

GET /posts?authorId=123&published=true
POST /posts
PUT /posts
DELETE /posts/123

If there is hierarchical dependency between Posts and Authors and I often need posts by author I would also add the following:

GET /authors/123/posts&published=true

If posts would not exist outside of resource Author then the 2 previous options would be replaced by:

GET /authors/123/posts?published=true
POST /authors/123/posts
PUT /authors/123/posts
DELETE /authors/123/posts/123

What do you think?

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • You can your make your Web API flexible using attribute routing refer this http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2 and http://www.asp.net/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing – Vivek Singh Apr 01 '16 at 11:38
  • Yes, I am using AttributeRouting. The question is which approach is better? Or maybe a mix of the two? – Miguel Moura Apr 01 '16 at 11:42
  • go for attribute routing because it gives you to define more routes with a single controller method which makes it flexible. – Vivek Singh Apr 01 '16 at 11:46
  • URIs are supposed to be opaque, but from a semantic point of view `/authors/123/posts` would mean that an author resource is responsible for keeping track of its posts and that you can't refer to a post by id. I don't think that's what you want. – a better oliver Apr 01 '16 at 12:41
  • 1
    "I think /authors/123/posts might become complex when using many levels." << What do you mean with "many levels"? `/authors/123/posts` is a unique identifier for one resource (thats being a list of all posts of a certain author), you don't need more level. If you want filter the results further, you'd use query parameters, i.e. `/authors/123/posts?tags=cat,dog` to show only posts from that user. ``/authors/123/posts/tag/cat` doesn't make much sense in this context, because tag is not a resource of authors, so it won't get any "bigger, deeper" etc. – Tseng Apr 01 '16 at 13:13
  • 1
    As for using `/authors/123/posts` vs `/posts?authorId=12` that depends on the usage. If you are creating a post search service (i.e. search box on the blog), then `/posts?authorId=12` makes sense as your intent is to query through all of the posts (with or without user constraint). But if you have a list of users (profiles) and want to create a link which displays all of this uses post, you use `/authors/123/posts` because it's more expressive about it's usage. You can use both in your rest service, one for searching one for usage as links in their profile or user information – Tseng Apr 01 '16 at 13:18
  • Some JS frameworks offer rest clients (angularjs and backbone iirc) and there it's created/initialized by defining an entry point, i.e. `/posts` or `author/123/posts` or with wildcards `authors/{id}/posts`, but this makes it a pain if you want to search across all authors posts so `/posts` is more natural for this type of request – Tseng Apr 01 '16 at 13:24
  • @Tseng When I said many levels I meant that the format /authors/123/posts can lead to many levels in other examples not in that particular one. – Miguel Moura Apr 01 '16 at 13:59
  • @Tseng I added an update to my question. What do you think? – Miguel Moura Apr 01 '16 at 14:12

2 Answers2

2

There is a myth that each resource must have only one path. Both of your examples are correct.

With your first example:

/authors/123/posts.

It makes sense when there is a hierarchical relationship between the two, if your current context is an author, it's no problem accessing posts of that author.

With your second example:

/posts?authorId=123&published=true&sort=created&expand=tags,category.

It makes sense to query the entire repository of posts distributed in many facets. For example, on your application, you may have a search page to search posts, it's the perfect use case for that.

Speaking in terms of model-view. Our resource is like model, our urls are like views. Nothing stops us from using many views for the same model. You just need to ensure you use the same backing code to access your stored data. There are different ways (views) to look at your data.

Summary: You can use both urls in your project. For example, use the /authors/123/posts on your author page to list posts of an author and use the /posts?authorId=123&published=true&sort=created&expand=tags,category on your post search page.

You could also have a look at this post for a similar opinion: What are best practices for REST nested resources

Community
  • 1
  • 1
Khanh TO
  • 48,509
  • 13
  • 99
  • 115
0

The rule of thumb we use on our projects: use a url path, e.g. /authors/123/posts if there is a clear hierarchical relationship between the two, and the resource you're visiting cannot live outside the context of the other one. For example, when retrieving order lines, it is straightforward to use /orders/123/lines, because an orderline has no meaning outside the context of the order itself.

In your case, posts can clearly 'live' outside the context of their author. If you can search posts by author, date, subject,... it makes sense to pass these values as a query string. So in my opinion, /posts?authorId=123 is the way to go here.

fikkatra
  • 5,605
  • 4
  • 40
  • 66
  • What you do when posting something that has a clear hierarchical relationship. For example: POST /employees/123/degrees or you would do POST /degrees ... I think for GET what you say makes sense for for POST I would go the second. – Miguel Moura Apr 01 '16 at 12:09
  • 2
    Following the standard, I always do GET /employees/123/degrees to get the degrees collection, and POST /employees/123/degrees to add a new degree. To keep things easy to understand, the urls should be the same. – fikkatra Apr 01 '16 at 12:12