Invoicing - calling multiple pages of Api and concatinating the results I have the following code: It works completely as expected, but I feel there is a better way to refactor it out.

The flow is as follows:


Call the end point with 1 page 
Get the total number of results.
If total count of items more than itemsPerPage.     
Call the API more times till results from all pages are returned, join them together as single invoice list
Append with initial request and send back.


Do I need GetAllInvoices function? Reason it is kept there is because I believe the responsibility of calling each pages of API does not belong to main function.

public async Task&lt;IEnumerable&lt;Invoice&gt;&gt; GetAllInvoicesAsync()
{
    const string endPoint = @"foo/{0}/invoices?pageNum={1}&amp;itemsPerPage={2}";
    const int itemsPerPage = xxx;
    InvoiceCollection response = await _apiClient
        .GetAsync&lt;InvoiceCollection&gt;(string.Format(endPoint, _apiClient.OrgId, 1, itemsPerPage));

    if (response?.TotalCount &gt; itemsPerPage)
    {
        var allInvoices = (await GetAllInvoices(endPoint,response.TotalCount, itemsPerPage))
            .SelectMany(i =&gt; i.Invoices?? Enumerable.Empty&lt;Invoice&gt;());
        response.Invoices = (response.Invoices ?? Enumerable.Empty&lt;Invoice&gt;()).Concat(allInvoices);
    }

    return response?.Invoices; 
}

private async Task&lt;List&lt;InvoiceCollection&gt;&gt; GetAllInvoices(string endPoint,int totalCount, int itemsPerPage)
{
    var totalPages = (int)Math.Ceiling(totalCount / (double)itemsPerPage);
    var tasks = new List&lt;Task&lt;InvoiceCollection&gt;&gt;();

    for (int currentPage = 2; currentPage&lt;=totalPages;currentPage++)
    {
        tasks.Add(_apiClient
            .GetAsync&lt;InvoiceCollection&gt;(string.Format(endPoint, _apiClient.OrgId, currentPage, itemsPerPage)));
    }
    var response = new List&lt;InvoiceCollection&gt;(await Task.WhenAll(tasks));
    return response;
}

public class InvoiceCollection
 {
     [JsonProperty("foo")]
     public IEnumerable&lt;Invoice&gt; Invoices { get; set; }
     public int TotalCount { get; set; }
 }
When you have an assumption of getting a mix of return one or more values. You need to favor collection over single value return; because treating it as a collection would make things easier to deal with. 

So, you can get rid of GetAllInvoices and adjust GetAllInvoicesAsync to something like this : 

public async Task&lt;IEnumerable&lt;Invoice&gt;&gt; GetAllInvoicesAsync()
{
    const string endPoint = @"foo/{0}/invoices?pageNum={1}&amp;itemsPerPage={2}";
    const int itemsPerPage = xxx;
    int pageNumber = 1; 
    int iterationCount = 0;

    var tasks = new List&lt;Task&lt;InvoiceCollection&gt;&gt;();

    var isFirstRound = true;

    do
    {   
        var response = await _apiClient.GetAsync&lt;InvoiceCollection&gt;(string.Format(endPoint, _apiClient.OrgId, pageNumber, itemsPerPage));

        if(isFirstRound) 
        { 
            iterationCount = response?.TotalCount &lt;= itemsPerPage ? response?.TotalCount : (int) Math.Ceiling(totalPageItems / (double)itemsPerPage);
            isFirstRound = false;
        }

        tasks.Add(response);

        pageNumber++;
    } 
    while(pageNumber &lt;= iterationCount)

    var invoiceResponseList = new List&lt;InvoiceCollection&gt;(await Task.WhenAll(tasks));

    var invoiceCollection = invoiceResponseList.SelectMany(i =&gt; i.Invoices ?? Enumerable.Empty&lt;Invoice&gt;());

    return invoiceCollection?.Invoices; 
}