WebAPI how to deal with nested resources?

2019-07-24 12:50发布

问题:

i am looking for advice and suggestions on best practices when working with WebAPI 2:

Lets say i have two controllers(users and books), and that would like to accept these routes:

/users/{user_id}/books <= books owned by user_id

/books <= all books
/books/{book_id} <= book from id

What would be the best practice on dealing with the /users/{user_id}/books specifically? I am dealing with a lot of custom routes in a REST API, so i use [RoutePrefix] and [Verb, Route] on methods.

Thanks a lot in advance! I am always trying to find better solutions and practices to common situations.

回答1:

I like to put all my routes for the returned entity on the same controller. So a BooksController would look like this:

public sealed class BooksController : ApiController
{
    //Ideally this Repository would be a dependency injected object
    private readonly IRepository<Book> _repo = new BooksRepo(); 

    [Route("books")]
    [HttpGet]
    public IQueryable<Book> GetAll()
    {
        return _repo.GetAll();
    }

    [Route("books/{bookId:int}")]
    [HttpGet]
    public Book GetById(int bookId)
    {
        return _repo.GetById(bookId);
    }

    [Route("users/{userId:int}/books")]
    [HttpGet]
    public IQueryable<Book> GetBooksByUser(int userId)
    {
        return _repo.GetByUser(userId);
    }

    [Route("users/{userId:int}/books/{bookId:int}")]
    [HttpGet]
    public Book GetUsersBook(int userId, int bookId)
    {
        return _repo.GetByUser(userId).FirstOrDefault(book => book.Id == bookId);
    }
}

Now any route that returns Books should be on this controller. Any route that returns Users would be placed on the UsersController. This has helped us keep things organized and simplified since a Route attribute can be placed on any controller, you can very easily have any route defined on any controller that makes it difficult track down all the possible routes.