This is a slight extension on the web API contacts controller from last week.
The first change is to the get that returns all contacts. Getting all contacts is great, but it would be helpful to be able to filter the data down. The following code is all the changes to the get function.
// GET: api/values [HttpGet] public async Task Get(string filter = null) { var contacts = GetContacts(); if (!string.IsNullOrWhiteSpace(filter)) { contacts = contacts .Where(c => c.Name.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 || c.AddressModels.Exists(a => a.Address.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 || a.City.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 || a.Country.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 || a.PostalCode.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 || a.State.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1) || c.EmailAddressModels.Exists(e => e.Address.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1) || c.PhoneModels.Exists(p => p.Number.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1)); } return await contacts.ToListAsync(); }
The get function call now has an optional string for filter. If the filter has a value then a linq statement checks to see if any contact fields matches the filter. In the past I had used the contains function, but during tested I noticed that contains function was dong a case-sensitive matching and I wanted case-insensitive so I switch to the IndexOf function of the string class.
The filter is passed via a query string which seem to the be more restful way of doing filtering type stuff instead of creating a different get function. Keep in mind I am new to web API and rest so if I have any of this wrong please let me know.
The second thing I changed this round was to require authorization to use the API.
[Authorize] [Route("api/[controller]")] public class ContactsController : Controller
As you can see the only thing I did was add the authorize attribute to the controller class. That is all that is required and now the API will require the user be logged in. This is using ASP’s authorization and means that the user must be logged in via the web site and then use that same session to hit the API.
Requiring the user to already be logged may or may not be what you are looking for with your API. If you are using the API for run a SPA that could be fine, but if your API is being used to back another scenario than authorization will need to be fleshed out more.
I hope to address both the SPA and other authorization type in a future blog post so stay tuned.
Nice article! You could also consider exposing odata which has various query options built in
http://www.odata.org/documentation/odata-version-2-0/uri-conventions/#QueryStringOptions
To do so you’d simply return IQueryable and add [EnableQuery] attribute to your controller like first code here
http://janvanderhaegen.com/2015/04/30/supporting-odata-inlinecount-json-verbose-with-web-api-odata/
Thanks for the tip Joshbooker! I will be sure to check out odata.