1

I would like to be able to support those URLs:

// GET:  api/Users              returns a list (all)
// GET:  api/Users/5            returns the user with Id 5
// GET:  api/Users/Active       returns a list (only those not soft-deleted)
// POST: api/Users              creates a user

I have first tried to configure it this way:

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

But then I could not support the api/Users/Active request

So I tried to configure it this way:

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

But then I can not support the api/Users/5 request

Is it possible to support both?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Bruno
  • 4,685
  • 7
  • 54
  • 105

1 Answers1

1

Register multiple routes.

You can also provide constraints, which restrict how a URI segment can match a placeholder:

constraints: new { id = @"\d+" }   // Only matches if "id" is one or more digits.

Example

// GET:  api/Users              returns a list (all)
// GET:  api/Users/5            returns the user with Id 5
// POST: api/Users              creates a user
config.Routes.MapHttpRoute(
    name: "Api",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional },
    constraints: new { id = @"\d+" }
);

// GET:  api/Users/Active       returns a list (only those not soft-deleted)
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Or enable attribute routing.

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

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

Controller

[RoutePrefix("api/users")]
public class UsersController : ApiController {
    // GET:  api/Users              returns a list (all)
    [HttpGet]
    [Route("")] 
    public IHttpActionResult Get() { ... }
    // GET:  api/Users/5            returns the user with Id 5
    [HttpGet]
    [Route("{id:int}")] 
    public IHttpActionResult Get(int id) { ... }
    // GET:  api/Users/Active       returns a list (only those not soft-deleted)
    [HttpGet]
    [Route("Active")] 
    public IHttpActionResult Active() { ... }
    // POST: api/Users              creates a user
    [HttpPost]
    [Route("")] 
    public IHttpActionResult Post(User user) { ... }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Thanks, if I configure 2 routes, it would be this way : `"api/{controller}/{action}"` and `"api/{controller}/{id}"` (with id optional) because I would not have a case with an action and id. But then, how would `api/Users/Active` and `api/Users/5` know which route to use correctly? – Bruno Nov 24 '16 at 03:01
  • you can use a constraint – Nkosi Nov 24 '16 at 03:02
  • Please fix the typo "RoutePrefic" -> "RoutePrefix" – Daniel Nov 24 '16 at 03:59
  • 1
    Thank you for your answer. I also found [this Q/A](http://stackoverflow.com/questions/13596391/web-api-routing-api-controller-action-id-dysfunctions-api-controller) quite useful. – Bruno Nov 24 '16 at 05:06