Diego Mijelshon
Diego Mijelshon

Reputation: 52725

Multiple GET actions

I'm creating the following controller:

public FoosController : ApiController
{
    public IQueryable Get()
    {
        return AnODataQueryableListOfFoos();
    }

    public void Delete(Guid id)
    {
        DeleteTheFooWithId(id);
    }

    public IQueryable<Bar> GetBars(Guid id)
    {
        var foo = GetFooById(id);
        return AnODataQueryableListOfBarsForThisFoo(foo);
    }

    public IEnumerable ProjectedBars(Guid id)
    {
        var foo = GetFooById(id);
        return foo.Qux
            ? OneProjectionOfBars(foo)
            : AnotherProjectionOfBars(foo);
    }
}

(a list of Bars can be thought of as the "content" of Foo...)

It was my intention to use the following URLs:

GET /api/Foos                         -> Get
GET /api/Foos/SOME_GUID/Bars          -> GetBars
GET /api/Foos/SOME_GUID/ProjectedBars -> GetProjectedBars
DELETE /api/Foos/SOME_GUID            -> Delete

I tried with a couple of combinations of [ActionName] and custom routes, but there was always either a conflict or a 404.

What is the easiest way to get this working? I'd like to keep my routes generic (i.e. no controller-specific stuff) if possible. Other controllers use a more standard /Stuff - Stuff/id approach.

I'm also open to someone pointing out I'm completely misusing URLs. Improvements welcome.

Upvotes: 3

Views: 62

Answers (2)

Jon Susiak
Jon Susiak

Reputation: 4978

I agree that Attribute Routing would be the best way to go, however you could try the following:

public FoosController : ApiController
{
    [HttpGet]
    public IQueryable Get()
    {
        return AnODataQueryableListOfFoos();
    }

    [HttpGet]
    [ActionName("Bars")]
    public IQueryable<Bar> GetBars(Guid id)
    {
        var foo = GetFooById(id);
        return AnODataQueryableListOfBarsForThisFoo(foo);
    }

    [HttpGet]
    [ActionName("ProjectedBars")]
    public IEnumerable GetProjectedBars(Guid id)
    {
        var foo = GetFooById(id);
        return foo.Qux
            ? OneProjectionOfBars(foo)
            : AnotherProjectionOfBars(foo);
    }
}

and then use the following routes:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );

config.Routes.MapHttpRoute(
    name: "DefaultApi2",
    routeTemplate: "api/{controller}/{id}/{action}"
    );

Upvotes: 2

Teoman Soygul
Teoman Soygul

Reputation: 25732

What you're asking for is n-depth sub-resources and the only real solution to this is the attribute routing provided in v2 of the Web API. Until it is released (which I believe will be soon), you can use RPC like approach:

routes.MapHttpRoute("RPC", "rpc/{controller}/{id}/{action}");

You'll need to register this as the very first HTTP route, and use a prefix other than 'api' so it won't clash with the actual api/ routes.

Upvotes: 0

Related Questions