Search code examples
restasp.net-mvc-4asp.net-web-apidomain-driven-designodata

WebApi and OData


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.


Solution

  • 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