Paging in MS Graph API

28.5k views Asked by At

Graph API Paging explains that the response would contain a field @odata.nextLink which would contain a skiptoken pointing to the next page of contents.

When I test the API, I'm getting a fully-qualified MS Graph URL which contains the skiptoken as a query param. E.g. Below is the value I got for the field @odata.nextLink in the response JSON. https://graph.microsoft.com/v1.0/users?$top=25&$skiptoken=X%27445370740200001E3A757365723134406F33363561702E6F6E6D6963726F736F66742E636F6D29557365725F31363064343831382D343162382D343961372D383063642D653136636561303437343437001E3A7573657235407368616C696E692D746573742E31626F74322E696E666F29557365725F62666639356437612D333764632D343266652D386335632D373639616534303233396166B900000000000000000000%27

Is it safe to assume we'll always get the full URL and not just the skiptoken? Because if it's true, it helps avoid parsing the skiptoken and then concatenating it to the existing URL to form the full URL ourselves.

EDIT - Compared to MS Graph API, response obtained from Azure AD Graph API differs in that the JSON field @odata.nextLink contains only the skipToken and not the fully-qualified URL.

4

There are 4 answers

3
Dan Kershaw - MSFT On BEST ANSWER

Yes. In Microsoft Graph you can assume that you'll always get the fully qualified URL for the @odata.nextLink. You can simply use the next link to get the next page of results, and clients should treat the nextLink as opaque (which is described in both OData v4 and in the Microsoft REST API guidelines here: https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#98-pagination.
This is different from AAD Graph API (which is not OData v4), which doesn't return the fully qualified next link, and means you need to do some more complicated manipulations to get the next page of results.

Hence Microsoft Graph should make this simpler for you.

Hope this helps,

0
Muflix On

I followed Tracy's answer and I was able to fetch all the messages at one go.

public List<Message> GetMessages()
{
    var messages = new List<Message>();
    
    var pages = Client.Users[_email]
                      .Messages
                      .Request(QueryOptions)
                      // Fetch the emails with attachments directly instead of downloading them later.
                      .Expand("attachments")
                      .GetAsync()
                      .Result;

    messages.AddRange(pages.CurrentPage);

    while (pages.NextPageRequest != null)
    {
        pages = pages.NextPageRequest.GetAsync().Result;
        messages.AddRange(pages.CurrentPage);
    }

    return messages;
}
0
Tracy On

The above code did not work for me without adding a call to 'CurrentPage' on the last line.
Sample taken from here.

        var driveItems = new List<DriveItem>();
        var driveItemsPage = await graphClient.Me.Drive.Root.Children.Request().GetAsync();
        driveItems.AddRange(driveItemsPage.CurrentPage);
        while (driveItemsPage.NextPageRequest != null)
        {
            driveItemsPage = await driveItemsPage.NextPageRequest.GetAsync();
            driveItems.AddRange(driveItemsPage.CurrentPage);
        }
0
Ravi Anand On

if you would like to have all users in single list, you can achieve that using the code that follows:

public static async Task<IEnumerable<User>> GetUsersAsync()
    {
        var graphClient = GetAuthenticatedClient();
        List<User> allUsers = new List<User>();
        var users = await graphClient.Users.Request().Top(998)
           .Select("displayName,mail,givenName,surname,id")
           .GetAsync();

        while (users.Count > 0)
        {
            allUsers.AddRange(users);
            if (users.NextPageRequest != null)
            {
                users = await users.NextPageRequest
                    .GetAsync();
            }
            else
            {
                break;
            }
        }
        return allUsers;
    }

I am using graph client library