Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't get/patch fields for SharePoint drive item by path #2126

Open
poschi3 opened this issue Aug 20, 2024 · 4 comments
Open

Can't get/patch fields for SharePoint drive item by path #2126

poschi3 opened this issue Aug 20, 2024 · 4 comments
Labels
type:question An issue that's a question

Comments

@poschi3
Copy link

poschi3 commented Aug 20, 2024

Describe the bug

I am trying to get and patch fields for SharePoint drive item by path.

In v5 of SDK I was able to do something like:

graphClient.sites(siteId).lists(libraryId).drive().root().itemWithPath(path)
.listItem().fields().buildRequest().patch(sourceFieldValueSet);

which leads to:
https://graph.microsoft.com/v1.0/sites/<siteId>/lists/<libraryId>/drive/root:/<filename>:/listItem/fields

In v6 of SDK this endpoint is not accessible. I found 2 way to get fields:

graphClient.sites().bySiteId(siteId).lists().byListId(libraryId).items().byListItemId(path).fields().get();
graphClient.drives().byDriveId(driveId).list().items().byListItemId(path).fields().get();

As I've read in #1961 (comment) it should be easy to use root:/folder/file: instead of item-id, but it is not working.

Expected behavior

Easy way to call https://graph.microsoft.com/v1.0/sites/<siteId>/lists/<libraryId>/drive/root:/<filename>:/listItem/fields and other similar endpoints

How to reproduce

I've written some example code:

    public void fileTest() {
        try {
            final String siteId = "<removed>";
            final String libraryId = "<removed>";
            final String filename = "doc.txt";

            final List<String> paths = List.of( //
                    filename, //
                    "/" + filename, //
                    "root:/" + filename, //
                    "root:/" + filename + ":" //
            );

            System.out.println("by sites");
            for (final String path : paths) {
                try {
                    graphServiceClient.sites().bySiteId(siteId).lists().byListId(libraryId).items().byListItemId(path)
                            .fields().get();
                    System.out.println("OK for " + path);
                } catch (final ODataError e) {
                    System.out.println("Error for " + path + " " + e.getMessage());
                }
            }

            System.out.println("\nby drives");
            final Drive drive = graphServiceClient.sites().bySiteId(siteId).lists().byListId(libraryId).drive().get();
            for (final String path : paths) {
                try {
                    graphServiceClient.drives().byDriveId(drive.getId()).list().items().byListItemId(path).fields()
                            .get();
                    System.out.println("OK for " + path);
                } catch (final ODataError e) {
                    System.out.println("Error for " + path + " " + e.getMessage());
                }
            }

            System.out.println("\nProof it's there:");
            final var driveItem = graphServiceClient.drives().byDriveId(drive.getId()).items()
                    .byDriveItemId("root:/" + filename + ":").get();
            System.out.println(driveItem.getId() + " " + driveItem.getName());
        } catch (final Exception e) {
            System.out.println("Other Exception:");
            e.printStackTrace();
        }
    }

which leads to output:

by sites
Error for doc.txt Item not found
Error for /doc.txt Item not found
Error for root:/doc.txt Resource not found for the segment 'getByPath'.
Error for root:/doc.txt: Resource not found for the segment 'getByPath'.

by drives
Error for doc.txt Item not found
Error for /doc.txt Item not found
Error for root:/doc.txt Item not found
Error for root:/doc.txt: Item not found

Proof it's there:
014ICIUEH23MWGBJOMZRF3RFLCCU7KXWAI doc.txt

SDK Version

6.13.0

Latest version known to work for scenario above?

5.73.0 / 5.80.0

Known Workarounds

No response

Debug output

Click to expand log ```
</details>


### Configuration

- OS: Linux
- architecture x64

### Other information

_No response_
@poschi3 poschi3 added status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Aug 20, 2024
@poschi3 poschi3 changed the title Can't get fields for SharePoint drive item by path Can't get/patch fields for SharePoint drive item by path Aug 20, 2024
@poschi3
Copy link
Author

poschi3 commented Aug 28, 2024

I would appreciate it if someone could help me. I also tried to use the ID I got from driveItem.getId() in my "proof" section (014ICIUEH23MWGBJOMZRF3RFLCCU7KXWAI) to make the request instead of the path:

String driveItemId = "014ICIUEH23MWGBJOMZRF3RFLCCU7KXWAI";
graphServiceClient.sites().bySiteId(siteId).lists().byListId(libraryId).items().byListItemId(driveItemId).fields().get();
graphServiceClient.drives().byDriveId(drive.getId()).list().items().byListItemId(driveItemId).fields().get();

But in both cases I get this error: Provided list item identifer is not in an allowed format

@Ndiritu
Copy link
Contributor

Ndiritu commented Sep 2, 2024

Hi @poschi3.

Sorry for the poor experience here.

Please try the withUrl method as a workaround as I investigate this further:

client.sites().bySiteId("").lists().byListId("").items().byListItemId("").fields().withUrl(
    "https://graph.microsoft.com/v1.0/sites/<siteId>/lists/<libraryId>/drive/root:/<filename>:/listItem/fields"
).get();

withUrl overrides all the values passed into the fluent request builder methods. Trick is to call it on an object who's HTTP method deserializes the response to an object you expect.

Please let me know if this helps.

@Ndiritu Ndiritu added type:question An issue that's a question and removed status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Sep 2, 2024
@poschi3
Copy link
Author

poschi3 commented Sep 2, 2024

Hi @Ndiritu

thank you for your reply. In the meantime I've done something like this:

    private FieldValueSet sendListItemFieldsPatch(final String siteId, final String listId,
            final String unescapedPath, final FieldValueSet body) {
        final HashMap<String, Object> pathParameters = new HashMap<>();
        pathParameters.put("site%2Did", siteId);
        pathParameters.put("list%2Did", listId);
        pathParameters.put("path", "root:/" + unescapedPath + ":");

        final RequestInformation requestInfo = new RequestInformation();
        requestInfo.httpMethod = HttpMethod.PATCH;
        requestInfo.urlTemplate = "{+baseurl}/sites/{site%2Did}/lists/{list%2Did}/drive/{path}/listItem/fields";
        requestInfo.pathParameters = pathParameters;
        requestInfo.headers.tryAdd("Accept", "application/json");
        requestInfo.setContentFromParsable(getGraphClient().getRequestAdapter(), "application/json", body);

        final HashMap<String, ParsableFactory<? extends Parsable>> errorMapping = new HashMap<>();
        errorMapping.put("XXX", ODataError::createFromDiscriminatorValue);

        return getGraphClient().getRequestAdapter().send(requestInfo, errorMapping,
                FieldValueSet::createFromDiscriminatorValue);
    }

But now I'm rewriting it to use .withUrl() but still using RequestInformation with .getUri().toURL().toString() to get urlTemplate with escaping of parameter values.

Please also reconsider to not remove non canonical request path. With the SDK v6 I have to double the number of requests because I have to retrieve the drive to get the drive ID to put it into the next request which was before just one request total.

@poschi3
Copy link
Author

poschi3 commented Sep 3, 2024

Now I'm doing something like this. It's may be helpful for someone.

    private String urlGenerator(final String urlTemplate, final Map<String, Object> pathParameters,
            final Map<String, Object> queryParameters) {

        final RequestInformation requestInfo = new RequestInformation();
        requestInfo.urlTemplate = urlTemplate;

        requestInfo.pathParameters = new HashMap<>(pathParameters);
        final String baseUrl = getGraphClient().getRequestAdapter().getBaseUrl();
        requestInfo.pathParameters.put("baseurl", baseUrl);
        if (queryParameters != null) {
            for (final Entry<String, Object> parameter : queryParameters.entrySet()) {
                requestInfo.addQueryParameter(parameter.getKey(), parameter.getValue());
            }
        }

        try {
            return requestInfo.getUri().toURL().toString();
        } catch (final URISyntaxException | MalformedURLException | IllegalArgumentException
                | IllegalStateException e) {
            throw new RuntimeException("Error building url", e);
        }
    }

    private FieldValueSet sendListItemFieldsPatch(final String siteId, final String listId, final String unescapedPath,
            final FieldValueSet body) {
        final String urlTemplate = "{+baseurl}/sites/{site%2Did}/lists/{list%2Did}/drive/{path}/listItem/fields";

        final Map<String, Object> pathParameters = Map.of( //
                "site%2Did", siteId, //
                "list%2Did", listId, //
                "path", "root:/" + unescapedPath + ":" // root:/doc.txt:
        );

        final String rawUrl = urlGenerator(urlTemplate, pathParameters, Collections.emptyMap());

        return getGraphClient().sites().bySiteId("").lists().byListId("").items().byListItemId("").fields()
                .withUrl(rawUrl).patch(body);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question An issue that's a question
Projects
None yet
Development

No branches or pull requests

2 participants