Filtering determines which records appear in a returned result by applying a condition to their values. In a board-game API, it prevents clients from receiving an unwieldy list when they need only matching games. section 5.4 section 5.4.3
Implement database-driven filtering in the GET endpoint as follows:
- Accept a nullable filterQuery parameter from the client. section 5.4.3
- Start with an IQueryable query and conditionally add Where when filterQuery is not null or empty. section 5.4.3
- Count the filtered query before applying sorting, Skip, and Take so pagination reflects the filter. section 5.4.3
Testing name filters
Requesting /BoardGames?filterQuery=diplomacy returns five matching games within the sorted result, while /BoardGames?filterQuery=war retrieves the first matching page. section 5.4.3
Listing 5.8 BoardGameController.Get() method (with paging, sorting, and filtering)
[HttpGet(Name = "GetBoardGames")]
[ResponseCache(Location = ResponseCacheLocation.Any, Duration = 60)]
public async Task<RestDTO<BoardGame[]>> Get(
int pageIndex = 0,
int pageSize = 10,
string? sortColumn = "Name",
string? sortOrder = "ASC",
string? filterQuery = null) #1
{
var query = _context.BoardGames.AsQueryable(); #2
if (!string.IsNullOrEmpty(filterQuery)) #3
query = query.Where(b => b.Name.Contains(filterQuery));
var recordCount = await query.CountAsync(); #4
query = query
.OrderBy($"{sortColumn} {sortOrder}")
.Skip(pageIndex * pageSize)
.Take(pageSize);
return new RestDTO<BoardGame[]>()
{
Data = await query.ToArrayAsync(),
PageIndex = pageIndex,
PageSize = pageSize,
RecordCount = recordCount,
Links = new List<LinkDTO> {
new LinkDTO(
Url.Action(
null,
"BoardGames",
new { pageIndex, pageSize },
Request.Scheme)!,
"self",
"GET"),
}
};
}
Inspect the complete GET method to see filterQuery, conditional Where, record counting, sorting, and paging composed together. section 5.4.3
































