quijames
quijames

Reputation: 537

How to do partial responses using ASP.Net Web Api 2

I'm really new to API design and MVC concepts, but as far as I can tell, something like GET /api/products should return a list of products and GET /api/products/1 should return a single product. In terms of speed my feeling is that /api/products should return less information i.e. just id and name, whereas /api/products/1 should return more i.e. id, name, and description.

As far as I can see, the best way to handle this is to make certain fields of the product class not be returned in the /api/products endpoint. This is especially necessary in the case of /api/products?fields=name . I'm using ASP.Net Web Api 2 and have tried the following:

Is there any simple way to do what I'm trying to do?

Otherwise could you suggest a better API design than what I'm doing?

Upvotes: 13

Views: 8965

Answers (3)

Matthias Burger
Matthias Burger

Reputation: 5946

Stumpled over this topic and just want to share my feelings - maybe it helps others :) I recommend to use something like OData. You can implement it so that you can write /api/products?$select=Id,Name,Price

some advantages:

  • with OData you can use further functions, like $filter, $orderby to work with filters and sort it
  • $skip, $top, $count to get a nice paging
  • more $-functions :)
  • you can directly apply it to a IQueryable<T>. Why is this great? You reduce the result not just in the response of your API, but you even reduce the result your database generates, which makes your application much faster. - and you don't even have to change your query

some disadvantages:

  • you can't filter directly on columns that are calculated
  • setting it up will take a little time

hint: sometimes it's better to just use ODataQueryOptions<T> in the parameter instead of complete implementation.

Upvotes: 0

dotarj
dotarj

Reputation: 488

You could also use WebApi.PartialResponse (http://www.nuget.org/packages/WebApi.PartialResponse/). It's a package I wrote which uses LINQ to JSON (Json.NET) to manipulate the returned objects. It uses the fields syntax used by Google in their API's, eg.:

  • fields=items/id,playlistItems/snippet/title,playlistItems/snippet/position
  • fields=items(id,snippet/title,snippet/position)
  • fields=items(id,snippet(title,position))

You can find more information on the GitHub project page: https://github.com/dotarj/PartialResponse.

Upvotes: 8

Martin Booth
Martin Booth

Reputation: 8595

I'd recommend using separate classes to map to when returning a list of entities.

Particularly as the problem is not just what you return to the user, but also what you select from the database.

So, make getting and entity return a Product object, and getting a list of entities return a ProductLink object or something similar.

Edit

As per jtlowe's comment, if you have many different methods returning slight variations of product properties, use anonymous classes (though I'd question whether this is necessarily a good design).

Consider something like this in your action

return from p in this.context.Products
       select new
       {
           p.Id,
           p.Name,
           p.SKU
       };

This:

  • Only selects the columns you need from the database.
  • Needs no additional classes defined for new variations of the product

This doesn't make it easy to pass the result of this statement around to other methods because you can only return it as IEnumerable, object or dynamic. If you are putting this in the controller then it may be good enough. If you are implementing a repository pattern, you'll be unable to return strongly typed lists if you use anonymous types.

Upvotes: 4

Related Questions