Get all SharePoint Document Library Files and Folders at a ServerRelativeUrl in One REST Call

Recently, I was building a directory tree view of a Document Library for a client. Yes, you can say this shouldn’t be necessary. We can just tag the documents with metadata and we won’t need folders at all. Unfortunately, that’s not always the way people want to work.

To build this, I started by calling the _api/Web/Lists/getbytitle('Document Library Name')/items endpoint. I figured I’d just get all the documents in the library and sort out the display from the array. I got this working pretty well and in my test environment with a few hundred documents, it worked great.

Then – boom. There was a little requirement I didn’t know about: quite a few of the Document Libraries where we wanted to use this had more than 5000 documents. I stupidly hadn’t thought of that possibility. In my experience, it’s pretty unusual to see Document Libraries with that many documents, though it definitely happens.

Why does 5000 documents matter? Well, as of SharePoint 2010, we went from being able to request as many items as we wanted to an item limit of 5000. I’ll admit it’s not usually a great idea to request that many items from the client, but sometimes we need to.

I had two choices:

  • Add some paging logic to the call. This would mean that if there were more than 5000 items, I’d simply make Math.ceil(documentCount / 5000) calls to get them. In smaller Document Libraries, it would still be one call; as the number of documents went up, it would take more calls.
  • Be smart about it. Just request the objects (files and folders) in the root of the Document Library, and then on-demand, only request what I needed as the user expanded each folder.

The former would have been a little easier, but with larger libraries those calls could get pretty slow. The latter idea was really the “enterprise” way to do it. The problem was that the _api/Web/Lists/getbytitle('Document Library Name')/items endpoint didn’t really give me the right info to do it well.

So I turned to a different endpoint: _api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl'). This is a newer endpoint and is designed for doing stuff like this. We can pass in the relative URL – maybe something like “/sites/SiteA/SubSiteA/LibraryName/TopFolder/SubFolderA/SubFolderB” – and get back just the files and folders for that relative path.

It takes two calls for this, though:

  • _api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl')/Folders
  • _api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl')/Files

That would work, but it seemed a bit inefficient. Wouldn’t it be better to get the files and folders at the same time?

Off I went to Bingle. Luckily, I found a post on SharePoint StackExchange pretty quickly from jkr asking the same thing: Get all Files and Folders in one call. Vadim Gremyachev replied with the trick.

_api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl')?$expand=Folders,Files

With this one call, we can get the info about the file and the folders together in one complex object.

Figure 1: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/$expand=Files,Folders
Figure 1: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/$expand=Files,Folders

As I said, this endpoint is perfect for building something like a directory tree.

There’s not a lot of good documentation for this endpoint (surprise!). You can find some examples of calls on the MSDN page Files and folders REST API reference, but no examples of the results. If you download the SharePoint 2013 REST Syntax (wall posters) you get some more clues.

The Files result provides results like those shown in Figure 2. As far as I can tell, there’s no way to control what fields you get back, as using $select has no effect.

Figure 2: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/Files
Figure 2: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/Files

The Folders result provides results like those shown in Figure 3. As far as I can tell, there’s no way to control what fields you get back here either, as using $select has no effect.

Figure 3: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/Folders
Figure 3: Complex object returned from _api/Web/GetFileByServerRelativeUrl()/Folders

Note that in the Folders results, there are also Files and Folders objects, so the idea of recursion is there, though the objects are deferred. Because each folder has a ServerRelativeUrl value, you can dig as deep as you need to.

If you know you only need to go a few layers deep, you can also do things like:

_api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl')?

$expand=Folders,Folders/Folders,Folders/Folders/Folders

or

_api/Web/GetFolderByServerRelativeUrl('folderRelativeUrl')?

$expand=Files,Folders/Files,Folders/Folders/Files

Both of these calls will get you three folders deep, which may be enough for some things you might want to do. I could also see using a call like these latter ones to get a bit ahead of your user to reduce the “chatter” on the line. That would make your array processing on the client side a little more complex, but could be worth it.

With some spiffy recursion in your framework of choice, you can build some very nice user interfaces with data like this. But that’s for another post…

Similar Posts

28 Comments

  1. Hii Marc,
    I Used $expand=Folders,Folders/Files But in this i was not able to open pdf files because its linkingurl is null.I am able to open only office files so can u please help me out.

  2. Hello Mark, first I’d like to say thank you for the years of time and service you’ve given the community. My question is in reference to expanding the files and folders… Is there a way to expand the deferred author/editor objects returned?

  3. Hi Marc,

    if a folder contains more than 5000 files. I am using the following URL to upload files to that folder

    /_api/Web/GetFolderByServerRelativeUrl(‘folderRelativeUrl’)/Files(overwrite=true, url=’fileName.pdf’)

    SharePoint Online is returning the error “The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator”.

    Is there a way to Fix this issue?

  4. I know this is several years old, but I stumbled upon this article hoping for a way to filter out the system folders (“Forms” in particular). I’ve settled on handling that client-side, but wanted to comment that you CAN use the “$select=…” to specify the fields to return even on the files and folders.

    Here’s an example:

    https://SP_SITE/api/web/GetFolderByServerRelativeUrl(‘_YOUR_DOC_LIB‘)?$expand=Files,Folders&$select=Name,ServerRelativeUrl,Files/Name,Files/ServerRelativeUrl,Folders/Name,Folders/ServerRelativeUrl

    You just have to specify the fields to select prefaced by “Files/” and “Folders/”.

  5. Hi, I am having problem with download file from Document Library SubFolders, I want to do it with jQuery. can you help.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.