Obviously you want to explore the opportunities of Attribute Routing in ASP.NET Web API 2 to support certain URI patterns that are common in RESTful APIs.
Your specific use case to enable API clients to query the event resource collection based on latitude, longitude and radius is even supported by what is nowadays called convention-based routing.
https://{base_uri}/MyApi/v1/Events?Longitude=4.4777&Latitude=51.9244
public EventsController : ApiController { public IEnumerable<EventDto> GetEvents([FromUri] double? latitude, [FromUri] double? longitude) { //code validating method parameters return EventService.ReadEvent(Latitude.Value, Longitude.Value).ToDto() } }
Using [FromUri] attributes on action parameters is called "Parameter binding". Parameter binding can be useful if you want to force ASP.NET Web API to read a complex type from the URI. Your application is about Events and geospatial concerns and encapsulating these concerns into complex types as you already did with events helps documenting any interface constraints. What would be the meaning of a query for events when only a value for longitude is provided? Given that omitting nullable parameters helps in your specific use case.
The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.
public class GeoPoint { public double Latitude { get; set; } public double Longitude { get; set; } } public EventsController : ApiController { //action is only selected when URI contains required parameters to bind a GeoPoint instance public IEnumerable<EventDto> GetEvents([FromUri] GeoPoint geoPoint) { //how about passing a complex type to the EventService? return EventService.ReadEvent(geoPoint).ToDto() } }
A URI returning a collection of events within a given distance/radius could be like
https://{base_uri}/MyApi/v1/Events?Longitude=4.4777&Latitude=51.9244&Radius=10.000
public class GeoPoint { public double Latitude { get; set; } public double Longitude { get; set; } } public class GeoPointQuery { public double Latitude { get; set; } public double Longitude { get; set; } public double Radius {get; set; } } public EventsController : ApiController { public IEnumerable<EventDto> GetEvents([FromUri] GeoPoint geoPoint) { //how about passing a complex type to the EventService? return EventService.GetEventAtPoint(geoPoint).ToDto() } public IEnumerable<EventDto> GetEventsQuery([FromUri] GeoPointQuery geoPointQuery) { //how about passing a complex type to the EventService? return EventService.GetEventsWithinDistance(geoPointQuery).ToDto() } }
Applying Attribute routing will help you addressing more hierarchical URI patterns and has a powerful language to define route constraints.
/a/b/creturns a list of something, then/a/b/c?foo=blahshould also return a list of something, filtered to entities that satisfy the query string.