This is another post in a series on creating performant and scalable web APIs using ASP.NET Core. In this post, we’ll continue to focus on operating on large collections of data - this time allowing the consumers of our API to filter and search on the collection …
The reasons are the same as paging from the last post:
It also means the builder of the client application that consumes our API doesn’t have to do any client side filtering or searching which can have a nice positive impact on the overall performance as well.
Filtering reduces a collection via criteria on filterable fields in the resource. Let’s implement a controller action method for: GET api/contacts?firstname={firstname}&surname={surname}
. We’ll continue to use Dapper as our data access library …
The code is below. In summary, we construct the SQL, including the appropriate WHERE
clause if filter values have been supplied in the URL.
[HttpGet]
public IActionResult GetContacts(UrlQuery urlQuery)
{
IEnumerable<Contact> contacts = null;
using (SqlConnection connection = new SqlConnection(_connectionString))
{
connection.Open();
string sql = @"SELECT ContactId, Title, FirstName, Surname
FROM Contact";
if (urlQuery.HaveFilter)
{
string filterSQL = "";
if (!string.IsNullOrEmpty(urlQuery.FirstName))
{
filterSQL += " FirstName = @FirstName";
}
if (!string.IsNullOrEmpty(urlQuery.Surname))
{
if (!string.IsNullOrEmpty(filterSQL))
{
filterSQL += " AND";
}
filterSQL += " Surname = @Surname";
}
sql += $" WHERE {filterSQL}";
}
contacts = connection.Query<Contact>(sql, urlQuery);
}
return Ok(contacts);
}
Below is the model class for the filtering information that binds to the URL parameters:
public class UrlQuery
{
public string FirstName { get; set; }
public string Surname { get; set; }
public bool HaveFilter => !string.IsNullOrEmpty(FirstName) || !string.IsNullOrEmpty(Surname);
}
Looking at the profiled SQL for GET api/contacts?surname=Kanne
, we see that it is nice and efficient:
Looking at the SQL execution plan, we see that it is using an index on Surname
:
Let’s also load test this endpoint:
Pretty good!
#asp.net #.net core #api #sqlserver