1

I'm looking to convert our current API architecture to a more generic query-able structure that doesn't require us to hard card each possible parameter and build up a custom query. Here is an example of what our current architecture looks like,

[HttpGet]
[Route("Companies/{id:int}/Implementations/Tasks")]
public async Task<IApiResponse<List<CompanyIPTDTO>>> GetCompanyIPTs(int? id = null, 
int? taskId = null, int? completedById = null, DateTime? dateCompletedStart = null, 
DateTime? dateCompletedEnd = null, int page = 1, int? pageSize = null)
{
    // Instantiate generic query
    Expression<Func<CompanyIPT, bool>> query = null;

    // Check parameters and build the lambda query
    // Check if the parameter is given and if the query field is already filled so as to either set or add a query
    if (id != null && query != null) query = query.And(t => t.CompanyID == id);
    else if (id != null && query == null) query = t => t.CompanyID == id;

    if (taskId != null && query != null) query = query.And(t => t.ProcessTaskID == taskId);
    else if (taskId != null && query == null) query = t => t.ProcessTaskID == taskId;

    if (completedById != null && query != null) query = query.And(t => t.CompletedByID == completedById);
    else if (completedById != null && query == null) query = t => t.CompletedByID == completedById;

    if ((dateCompletedStart != null && dateCompletedEnd != null) && query != null) query = query.And(a => a.DateCompleted >= dateCompletedStart && a.DateCompleted <= dateCompletedEnd);
    else if ((dateCompletedStart != null && dateCompletedEnd != null) && query == null) query = a => a.DateCompleted >= dateCompletedStart && a.DateCompleted <= dateCompletedEnd;

    // Execute the GET with the appended query and paging information
    var result = _uow.CompanyIPTRepository.List(filter: query, page: page, pageSize: pageSize);
    int totalPossibleRecords = _uow.CompanyIPTRepository.GetTotalRecords(filter: query);

    return new ApiSuccessResponse<List<CompanyIPTDTO>>(HttpStatusCode.OK, result.Select(x => Mapper.Map<CompanyIPTDTO>(x)).ToList(), result.Count(), Request.RequestUri, totalPossibleRecords, pageSize);
}

And as you can see this gets very cumbersome for a large API on every get request to have to customize the query checks. I assume there must be some way to do this generically based on a query string parameter that comes in. For example in this case I would love to see a request come in that looks like,

https://www.example.com/api/Companies/15/Implementations/Tasks?q=[completedById=5,dateCompletedStart=1/15/18,dateCompletedEnd=1/17/18]

And after coming in like this I assume we could build something that uses Reflection to look at the object and verify these fields exist and build up a generic query to hit our DB?

Anyone know where to point us in the right direction?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
tokyo0709
  • 1,897
  • 4
  • 28
  • 49

0 Answers0