Web API Action Filter to handle empty sets & 404's

1.8k Views Asked by At

I have a controller method which returns a list of resources like this:

 [HttpGet, Route("events/{id:int}/rosters")]     
 public RosterExternalList List(int id, int page = 1, int pageSize = 50) {
    return Repository.GetRosters(id).ToExternal(page, pageSize);
 }

And the repository method is:

public IQueryable<EventRoster> GetRosters(int id) {
   return EventDBContext.EventRosters.Where(x => x.eventID == id).OrderBy(x => x.EventRosterID).AsQueryable();
}

This is the same pattern for multiple list methods. The problem is that when no items are retrieved from the db, the api sends a 200 with an empty response body even if the id passed in is invalid.

What I want is if id = invalid, send appropriate response (404?). Otherwise, if the id is valid, and there are no records, send the 200 with empty body.

My question is - is this the right way to handle this? Can this be done via an Action Filter so it will be implemented across all the methods like this? How?

1

There are 1 best solutions below

0
On BEST ANSWER

It is possible with an action filter like this:

    public class EventsFilter : ActionFilterAttribute
    {
        public EventDBContext EventDBContext { get; set; }

        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            bool exists = false;
            var routeData = actionContext.Request.GetRouteData();
            object value;
            if (routeData.Values.TryGetValue("id", out value))
            {
                int id;
                if (int.TryParse(value, out id))
                {
                    exists = EventDBContext.EventRosters.Where(x => x.eventID == id).Any();
                }
            }
            if (exists == false)
            {
                var response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "Event not found");
                throw new HttpResponseException(response);       
            }
        }
    }

You would also need to configure a dependency resolver to set EventDBContext property.

Is it the right way?

It depends on your solution design:

  • If your business layer is integrated and depends on the Web API (as it appears from your example), then yes it is the way to go.

  • If Web API (service layer) is not the only one who uses your business layer, then you would want to avoid duplication of event checking in other places and move it to a more generic class than Web API action filter and call this class from your business layer instead of Web API to make sure that regardless of the caller, you would always check if event exists. In that class you would throw something like BusinessLogicNotFoundException with information about event. And on the Web API, you would need to create an ExceptionFilterAttribute that handles BusinessLogicNotFoundException and creates an appropriate 404 response.