4

I'm new to WebApi and I don't quite get it.

I do get that all the verbs are focused on Get, Put, Post and Delete. But Coming from a heavy DDD and MVC background, I need some pointers.

I'm used to expose services/resources/actions whatever you want to call it that does some internal filtering. e.g. for an SalesOrder service I might have operations like GetTodaysOrders , GetUnapprovedOrders etc. Operations that applies some filtering on the "SalesOrder set"

So, In WebApi and rest in general I suppose, I'm not supposed to do this? I'm supposed to expose the entire SalesOrder set?

And filtering could be done with OData but that moves the responisbillity of knowing what to filter to the consumer, the consumer must know what to ask for, e.g. any domain/business rule must be known by the consumer. That part seems totally alien to me.

How do you deal with this sort of things? Can this be handled in some way, and I don't mean in a hacky way like creating a new web api controller for each and every way you can filter some data.

Roger Johansson
  • 22,764
  • 18
  • 97
  • 193

3 Answers3

1

I feel your pain. The first time i was really forced to change my way of thinking is when I started developing on Ruby On Rails.

regarding exposing methods in general, Try doing it in this order:

  1. start by exposing the full set of CRUD operations for the resource (aka make your RESTful resource)
  2. go back and privatize the things that should not be exposed by doing pre- and post- hooks on those methods for authentication / permissions checks and whatnot.

Then, when you've got your resources, a generally good rule of thumb is to show what is necessary before the ? and hide the complexity behind the ?, thus making your resources able to do filtering, but not requiring it. In other words, decorate your methods with filtering.

So, lets say you want to have an /orders endpoint:

Base URL: /orders
REST params: /orders(:/id)
Additional params:
  - dateRange
  - purchaseStatus
  - price
  - etc
Example usage: 
  /orders?dateRange=1y&price=lt:100

Of course, I say all of this because I tend to agree with what APIGEE said about it in their API best practices whitepaper. I think you'll find it helpful.

https://pages.apigee.com/rs/apigee/images/api-design-ebook-2012-03.pdf

Corey Ford
  • 145
  • 1
  • 8
Kristian
  • 21,204
  • 19
  • 101
  • 176
1

It takes a bit of time to get used to but you will find the APIGEE approach referenced by Kristian very useful.

I'm supposed to expose the entire SalesOrder set?

Only if you you want to. The default Index method is just there to help you get started, if it does not make sense in your case, remove it. Or change it to return the sales orders in a paged fashion, or just the most recent.

In your scenario -

GetTodaysOrders would be a GET request like api/orders?period=1

GetUnapprovedOrders would be a GET request like api/orders?approved=false

Both of these calls could be to the same action method - ActionResult Index(int period, bool approved) (I'm not at a dev machine now and can't remember if parameters need to be nullable/optional)

As for OData, it is very powerful, but yes the consumer of the API must know how to call it, and what to filter on. But they should know that anyway. You can set limits with OData on how many records can be pull, which orderby's you support (to protect searching on unindexed columns in your db) and more see here for examples.

tom
  • 1,822
  • 4
  • 25
  • 43
0

In addition to all the great answers above: if there is a certain function/method that really requires some functionality that cannot (easily) be supported by any of the CRUD operations, you can always fall back on OData Actions.

You can manually declare a specific method as an action, and then you actually get the exposed methods like you are used to from MVC. Mike Wasson has written a perfect article on OData Actions, which you can find here: Supporting OData Actions in ASP.NET Web API

Kazu
  • 627
  • 6
  • 17