9

I am trying to use Google Drive API (v3) to make updates to documents in Google Drive.

I have read this migration guide: Google Drive API v3 Migration

And coded it to make a new empty File() with the details I want to update and then calling execute() with that and the file ID. But i am still getting an error. Can anyone point out where I am doing wrong? thanks alot!!

Error:

{
    "code" : 403,
    "errors" : [{
        "domain" : "global",

        "message" : "The resource body includes fields which are not directly writable.",

        "reason" : "fieldNotWritable"
    }],
    "message" : "The resource body includes fields which are not directly writable."
}

Code snippet below:

File newFileDetails = new File();        
FileList result = service2.files().list()
    .setPageSize(10)    
    .setFields("nextPageToken, files(id, name)")
    .execute();

List<File> files = result.getFiles();

if (files == null || files.size() == 0) {

    System.out.println("No files found.");

} else {

   System.out.println("Files:");

   for (File file : files) {

      if (file.getName().equals("first_sheet")) {

         System.out.printf("%s (%s)\n", file.getName(), file.getId());


         newFileDetails.setShared(true);


         service2.files().update(file.getId(), newFileDetails).execute();

      }

   }

}
Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147
Vince Yau
  • 515
  • 1
  • 5
  • 16

5 Answers5

5

I had the same issue and found a solution. The key point is: you must create a new File object without Id and use it in update() method. Here is a piece of my code:

val oldMetadata = service!!.files().get(fileId.id).execute()

val newMetadata = File()
newMetadata.name = oldMetadata.name
newMetadata.parents = oldMetadata.parents
newMetadata.description = idHashPair.toDriveString()

val content = ByteArrayContent("application/octet-stream", fileContent)

val result = service!!.files().update(fileId.id, newMetadata, content).execute()

It works. I hope it'll help you.

Alex Shevelev
  • 681
  • 7
  • 14
3

Referring to https://developers.google.com/drive/v3/reference/files#resource-representations, you can see that shared isn't a writable field. If you think about it, this makes perfect sense. You can share a file by adding a new permission, and you can check if a file has been shared by reading the shared property. But saying a file is shared, other than by actually sharing it, makes no sense.

pinoyyid
  • 21,499
  • 14
  • 64
  • 115
  • Thanks for your reply. I am actually on the way to programmatically sharing a document with a person by email address. Your link is helpful. I will try to add a Permission. – Vince Yau Aug 29 '16 at 19:20
3

in the code it looks like this

Drive service... // your own declared implementation of service
File  file = new File(); //using the com.google.api.services.drive.model package
    // part where you set your data to file like:
file.setName("new name for file");
String fileID = "id of file, which you want to change";
service.files().update(fileID,file).execute();

trying to change the fields from remote files, and rewriting to this file can throw the security exception like exception below. but it is not a solution for your question. If you want to share file to another google account by email, you can do it with reimplementing authorization to authorization with using service account of your app, and the add the needed email, as owner of the file.

Mark Fieldman
  • 74
  • 1
  • 6
0

I was doing the same thing. My goal was to share my file programmatically with my Python code.

And yes, I was getting the same error: "The resource body includes fields which are not directly writable"

I solved this problem by adding the service's email address of my Virtual Machine (I created it on my Compute Engine dashboard) to Editors of the file.

Then I ran this Python code in my VM:

from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials


# Took the json file from my Google Cloud Platform (GCP) → IAM & Admin → Service Accounts:
service_key_file = 'service_key.json'
scope = 'https://www.googleapis.com/auth/drive'

credentials = ServiceAccountCredentials.from_json_keyfile_name(service_key_file, scopes=scope)
driveV3 = build('drive', 'v3', credentials=credentials)

fileId = '1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ'  # A spreadsheet file on my GDrive.

newGmailUser = 'testtest@gmail.com'
permNewBody = {
    'role': 'reader',
    'type': 'user',
    'emailAddress': newGmailUser,
}


driveV3.permissions().create(fileId=fileId, body=permNewBody).execute()
print(f"""The file is now shared with this user:
{newGmailUser}\n
See the file here:
https://docs.google.com/spreadsheets/d/1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ""")
Serge-M
  • 13
  • 1
  • 2
  • 6
  • this does not work for me. I'm already an editor of the file and those are the three values I pass in the requestCode (role, type, emailAddress) and I get the above error. – Michael Apr 11 '22 at 20:36
  • @Michael, in my case the **Service Account** was granted a role **Editor**, not my gmail account. I did that here: Google Cloud Platform (GCP) → IAM & Admin → IAM → Edit principal (the pencil icon). – Serge-M Apr 12 '22 at 11:44
  • that is how i have it set up, although in my case the service account is also the owner of the document as it was created in the API via the service account credentials. I am wondering if the issue could be that the service account is a different (nonsensical) domain than gmail.com. – Michael Apr 12 '22 at 15:36
0

I strongly think the error is directly connected to the permissions. Please check this format!

import com.google.api.services.drive.model.Permission;

FileList result = service2.files().list()
    .setPageSize(10)
    .setFields("nextPageToken, files(id, name)")
    .execute();

List<File> files = result.getFiles();

if (files == null || files.isEmpty()) {
    System.out.println("No files found.");
} else {
  System.out.println("Files:");

for (File file : files) {
    if (file.getName().equals("first_sheet")) {
        System.out.printf("%s (%s)\n", file.getName(), file.getId());

        Permission permission = new Permission();
        permission.setRole("reader"); 
        permission.setType("anyone");

        service2.permissions().create(file.getId(), permission).execute();
    }
  }
}