Working with the Microsoft Graph API can be frustrating, as the documentation can be sparse at times. If you’ve found yourself needing to update columns (fields) in SharePoint for files inside the Document Library, this guide should help. I’ll assume:
- You have basic knowledge of REST and the Graph API
- You’re authenticated to the Graph API or have a means of authentication (such as an Entra app registration)
- You have
Sites.ReadWrite.AllandLists.ReadWrite.Allpermissions for your tenant in which the Sharepoint site resides - You already have the
siteIdanddriveIdvalues for your SharePoint site: Find site and drive IDs
Accessing columns from driveItem directly doesn’t work
You might assume you can update columns with a direct endpoint like the following:
PATCH https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/root:/{path_to_file}/fields
Unfortunately, this does not work. As per the official documentation, the endpoint we should use to access item fields/columns is the following:
PATCH /sites/{site-id}/lists/{list-id}/items/{item-id}/fields
Microsoft Docs – Update listItem
Understanding itemId vs listItemId
Even though files in a Document Library aren’t in a traditional List, SharePoint treats Drives identically to Lists under the hood. This means that each file in the Sharepoint Drive has both an 1) itemId and 2) a listItemId. Whenever list occurs in the endpoint, we need to use the latter in our API calls to access the listItem endpoints. Often, the only way to understand the difference between these ID’s is to look at their format:
itemId: looks something like01ADHJ88ULDNK9(base64-style string)listItemId: looks something like22890(integer)
Both refer to the same file, but are used in different parts of the API.
Patching columns based on itemId
Obtaining itemId recursively can be done by travelling through the following endpoint:
GET https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/root:/{folder_name}:/children
where the resulting JSON response can be unpacked for ItemId through collecting the ['value']['file']['id'] values in the nested output. Or, alternatively, one can access itemId from the file path for a single file and use the following three Graph API calls to update the columns of a single file in a Sharepoint drive based on its location in the drive:
- Obtaining
itemIdfrom the file path through a GET request - Obtaining
ListItemIdfrom theItemIdthrough another GET request. - Patching the fields/columns based on the
ListItemId.
To begin with, you’ll need the ListId of the Sharepoint drive. This can be retrieved by navigating to the Sharepoint drive, in top right ‘Settings’ > ‘Library’ > ‘More library settings’. The page you’ll be transported to, will contain the ListId inside the browser URL. The ListId is formatted similarly to SiteId and DriveId but will be different from those two. You’ll need the following headers for each request. For the PATCH-request, an additional header is required:
{
'Authorization': 'Bearer {access_token}'
}
1. GET the itemId from the file path
If you already have a way of getting itemId for your files, then you can skip this call.
GET https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/root:/{path_to_file}
The response contains the key ['id'] → which is the itemId. —
2. GET the listItemId through the itemId
GET https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/{item_id}/listItem
The following endpoint will give a response body as JSON where listItemId can be unpacked through keys ['fields']['id']. Then, use this as input, together with a content body in the following endpoint to finally update the columns.
3. PATCH the Fields
In addition to the Authorization header, you should also specify the Content-Type header:
{
'Authorization': 'Bearer {access_token}',
'Content-Type': 'application/json'
}
and give the body as:
{
"ColumnName1": "New value",
"ColumnName2": "Another value"
}
where the column names are case sensitive. The current suggested payload assumes the column data types are Single line of text but the following link explains how to update different data types. Send the header and body to the endpoint below. Keep in mind that there are limitations in some of the column sizes. For instance, Single line of text can only accomodate 255 characters. The Graph API will not truncate this for you, and you need to catch these errors yourself. The right endpoint is:
PATCH https://graph.microsoft.com/v1.0/sites/{site_id}/lists/{list_id}/items/{list_item_id}/fields
You can investigate what the datatype of columns in your Document drive is, by performing a GET request on the endpoint:
GET https://graph.microsoft.com/v1.0/sites/{site_id}/lists/{list_id}/columns
where the output should be self-explanatory. Alternatively, here are a couple basic Python functions as potential building blocks for programmable changes to Sharepoint columns:
import requests
import json
def get_access_token(tenant_id, client_id, client_secret):
resource = "https://graph.microsoft.com/"
base_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
body = {
'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret,
'scope': resource + '.default'
}
response = requests.post(base_url, headers=headers, data=body)
return response.json().get('access_token')
def get_item_id(site_id, drive_id, path_to_file, access_token):
endpoint = f'https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/root:/{path_to_file}'
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
response = requests.get(endpoint, headers=headers)
if response.status_code not in [200, 201]:
return None
return json.loads(response.content)['id']
def get_list_item_id(site_id, item_id, access_token):
endpoint = f'https://graph.microsoft.com/v1.0/sites/{site_id}/drive/items/{item_id}/listItem'
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
response = requests.get(endpoint, headers=headers)
if response.status_code not in [200, 201]:
return None
return json.loads(response.content)['fields']['id']
def patch_columns(site_id, list_id, list_item_id, access_token, columns_data=None):
if columns_data is None:
columns_data = {
"ColumnName1": "New value",
"ColumnName2": "Another value"
}
endpoint = f'https://graph.microsoft.com/v1.0/sites/{site_id}/lists/{list_id}/items/{list_item_id}/fields'
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
response = requests.patch(endpoint, headers=headers, json=columns_data)
return response.status_code in [200, 201]