user979331
user979331

Reputation: 11871

Check if Graph API folder exists

I am using Microsoft Graph API and I am creating a folder like so:

var driveItem = new DriveItem
{
    Name = Customer_Name.Text + Customer_LName.Text,
    Folder = new Folder
    {
    },
    AdditionalData = new Dictionary<string, object>()
    {
        {"@microsoft.graph.conflictBehavior","rename"}
    }
};

var newFolder = await App.GraphClient
  .Me
  .Drive
  .Items["id-of-folder-I-am-putting-this-into"]
  .Children
  .Request()
  .AddAsync(driveItem);

My question is how do I check if this folder exists and if it does get the id of the folder?

Upvotes: 12

Views: 10392

Answers (7)

Nelson Nyland
Nelson Nyland

Reputation: 555

My implementation uses the application level access to the graph api.

Create a drive item structure with children to represent your file tree and then traverse it alongside the actual graph api responses:

public class DriveItem
{
    public string ItemID { get; set; }
    public string Name { get; set; }
    public string URL { get; set; }

    public List<DriveItem> Children { get; set; }
}
public async Task<bool> DirectoryExists(DriveItemRequest request)
{
    if (!string.IsNullOrEmpty(request.SiteID) &&
        !string.IsNullOrEmpty(request.DriveID) &&
        request.Root != null)
    {
        var currentFolder = await _client.Sites[request.SiteID].Drives[request.DriveID]
            .Root.Children.Request().Filter($"name eq '{request.Root.Name}'").GetAsync();

        if (currentFolder.Count > 0)
        {
            var currentItem = request.Root;
            while (currentFolder.Count > 0 && currentItem.Children != null)
            {
                // navigate to child
                currentItem = currentItem.Children[0];

                // traverse folder structure
                currentFolder = await _client.Sites[request.SiteID].Drives[request.DriveID]
                    .Items[currentFolder[0].Id].Children.Request()
                    .Filter($"name eq '{currentItem.Name}'").GetAsync();
            }

            return currentFolder.Count > 0 ? true : false;
        }
    }
            
    return false;
}

Upvotes: 0

Bharat Jogdand
Bharat Jogdand

Reputation: 438

Few Microsoft Graph useful API's to search for specific folder into drive:

  1. Check folder with name on root level of drive:

    Method: GET

    Required Header:

    Authorization: Bearer <access_token>
    

    API URL:

    https://graph.microsoft.com/v1.0/drives/<your-drive-id>/root:/<folder_name_to_be_search>
    
  2. Check folder with name exist inside any parent folder on root level:

    Method: GET

    Required Header:

    Authorization: Bearer <access_token>
    

    API URL:

    https://graph.microsoft.com/v1.0/drives/<your-drive-id>/items/<parent-folder-id>:/<folder_name_to_be_search>
    
  3. API to get list of all drive childrens:

    Method: GET

    Required Header:

    Authorization: Bearer <access_token>
    

    API URL:

    https://graph.microsoft.com/v1.0/drive/root/children
    
  4. API to get children items inside parent folder in drive:

    Method: GET

    Required Header:

    Authorization: Bearer <access_token>
    

    API URL:

    https://graph.microsoft.com/v1.0/drives/<your-drive-id>/items/<parent-folder-id>/children
    

Upvotes: 0

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59338

A query based approach could be considered in this regard. Since by design DriveItem.name property is unique within a folder, the following query demonstrates how to filter driveItem by name in order to determine if drive item exist:

https://graph.microsoft.com/v1.0/me/drive/items/{parent-item-id}/children?$filter=name eq '{folder-name}'

which could be represented in C# like this:

var items = await graphClient
            .Me
            .Drive
            .Items[parentFolderId]
            .Children
            .Request()
            .Filter($"name eq '{folderName}'")
            .GetAsync();

Given the provided endpoint the flow could consist of the following steps:

  • submit a request to determine whether a folder with a given name already exist
  • submit a second one if folder was not found (or return an an existing folder)

Example

Here is a updated example

//1.ensure drive item already exists (filtering by name) 
var items = await graphClient
            .Me
            .Drive
            .Items[parentFolderId]
            .Children
            .Request()
            .Filter($"name eq '{folderName}'")
            .GetAsync();



if (items.Count > 0) //found existing item (folder facet)
{
     Console.WriteLine(items[0].Id);  //<- gives an existing DriveItem Id (folder facet)  
}
else
{
     //2. create a folder facet
     var driveItem = new DriveItem
     {
         Name = folderName,
         Folder = new Folder
         {
         },
         AdditionalData = new Dictionary<string, object>()
         {
                    {"@microsoft.graph.conflictBehavior","rename"}
         }
     };

     var newFolder = await graphClient
                .Me
                .Drive
                .Items[parentFolderId]
                .Children
                .Request()
                .AddAsync(driveItem);

  }

Upvotes: 4

Matt.G
Matt.G

Reputation: 3609

To get the folder with the folder name:

call graph api Reference1 Reference2: /me/drive/items/{item-id}:/path/to/file

i.e. /drive/items/id-of-folder-I-am-putting-this-into:/{folderName}

  • If the folder exists it returns a driveItem Response, which has the id

  • If the folder doesn't exist, it returns a 404 (NotFound)

Now, while creating a folder, if the folder already exists, in order to fail the call, try setting additional data as follows Reference:

    AdditionalData = new Dictionary<string, object>
    {
        { "@microsoft.graph.conflictBehavior", "fail" }
    }
  • This will return a 409 Conflict, if the folder exists

Upvotes: 6

timur
timur

Reputation: 14577

Graph API provides a search facility, that you could utilise to find out if an item exists. You have either an option of running the search first and then creating an item if nothing was found, or you could do as @Matt.G suggests and play around nameAlreadyExists exception:

        var driveItem = new DriveItem
        {
            Name = Customer_Name.Text + Customer_LName.Text,
            Folder = new Folder
            {
            },
            AdditionalData = new Dictionary<string, object>()
            {
                {"@microsoft.graph.conflictBehavior","fail"}
            }
        };

        try
        {
            driveItem = await graphserviceClient
                .Me
                .Drive.Root.Children
                .Items["id-of-folder-I-am-putting-this-into"]
                .Children
                .Request()
                .AddAsync(driveItem);
        }
        catch (ServiceException exception)
        {
            if (exception.StatusCode == HttpStatusCode.Conflict && exception.Error.Code == "nameAlreadyExists")
            {
                var newFolder = await graphserviceClient
                    .Me
                    .Drive.Root.Children
                    .Items["id-of-folder-I-am-putting-this-into"]
                    .Search(driveItem.Name) // the API lets us run searches https://learn.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=csharp
                    .Request()
                    .GetAsync();
                // since the search is likely to return more results we should filter it further
                driveItem = newFolder.FirstOrDefault(f => f.Folder != null && f.Name == driveItem.Name); // Just to ensure we're finding a folder, not a file with this name
                Console.WriteLine(driveItem?.Id); // your ID here
            }
            else
            {
                Console.WriteLine("Other ServiceException");
                throw;// handle this
            }
        }

The query text used to search for items. Values may be matched across several fields including filename, metadata, and file content.

you can play with search query and do things like filename=<yourName> or potentially examine file types (which i guess is not going to help in your particular case, but I'd mention it for completeness sake)

Upvotes: 5

Paul Schaeflein
Paul Schaeflein

Reputation: 627

Issue a search request on the container.

var existingItems = await graphServiceClient.Me.Drive
                          .Items["id-of-folder-I-am-putting-this-into"]
                          .Search("search")
                          .Request().GetAsync();

You must then iterate the existingItems collection (possible including multiple pages) to determine if the item exists.

You don't specify the criteria for determining if an item exists. Assuming you mean by name, you could:

var exists = existingItems.CurrentPage
               .Any(i => i.Name.Equals(Customer_Name.Text + Customer_LName.Text);

Upvotes: 1

Kevin Kulla
Kevin Kulla

Reputation: 49

You can get the ID of the folder by calling this: https://graph.microsoft.com/v1.0/me/drive/root/children. It'll give you all of the items in the drive. You can use the name or another property to filter your results to get the folder ID if you don't already have it

public static bool isPropertyExist (dynamic d)
{
  try {
       string check = d.folder.childCount;
       return true;
  } catch {
       return false;
  }
}
var newFolder = await {https://graph.microsoft.com/v1.0/me/drive/items/{itemID}}


if (isPropertyExist(newFolder))
{
  //Your code goes here.
}

If the type of item in the drive is a folder it will get a folder property. You can check if this property exists and if it does run your code to add the item.

Upvotes: 0

Related Questions