Search code examples
microsoft-graph-apimicrosoft-graph-plannertasks

Microsoft Graph API - Schema validation fails for PlanID when creating bucket, and update task doesn't work


First problem:

I am unable to create buckets in Microsoft Planner through the Graph API. I keep getting the following error even though I already specified the correct plan ID:


    {"error": {"code": "", "message": "Schema validation has failed. Validation for field 'PlanId', on entity 'Bucket' has failed: A non-null value must be specified for this field.", "innerError": {"date": "2021-04-13T08:21:23", "request-id": "7f73320f-c273-4c8f-aedf-e4c413343d99", "client-request-id": "7f73320f-c273-4c8f-aedf-e4c413343d99"}}}

Second problem:

I am unable to update tasks in Microsoft Planner through the Graph API. I get a 200 response status code, but the actual task on Planner doesn't actually reflect the changes.

import requests_oauthlib
import config
import os
import json

MSGRAPH = requests_oauthlib.OAuth2Session(config.CLIENT_ID,
                                          scope=config.SCOPES,
                                          redirect_uri=config.REDIRECT_URI)

# Enable non-HTTPS redirect URI for development/testing.
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
# Allow token scope to not match requested scope. (Other auth libraries allow
# this, but Requests-OAuthlib raises exception on scope mismatch by default.)
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
os.environ['OAUTHLIB_IGNORE_SCOPE_CHANGE'] = '1'

def call_endpoint(do, **kwargs):
    BASE_URL = "https://graph.microsoft.com"
    RESOURCE = "v1.0/planner"
    headers = {'Authorization': f'Bearer {config.ACCESS_TOKEN}'}
    
    ENDPOINTS = {
        "Create Plan": {"URL": f"{BASE_URL}/{RESOURCE}/plans", "data": {'owner': config.GROUP_ID, 'title': kwargs.get('title', "")}},
        "Create Bucket": {"URL": f"{BASE_URL}/{RESOURCE}/buckets", "data": {"planId": kwargs.get("planId", ""), "name": kwargs.get("name", ""), 'orderHint': " !"}},
        "Create Task": {"URL": f"{BASE_URL}/{RESOURCE}/tasks", "data": {'planId': kwargs.get('planId', ""), 'bucketId': kwargs.get('bucketId', ""), 'title': kwargs.get('title', ""), 'assignments': {}}},
        "Get Plans": {"URL": f"{BASE_URL}/v1.0/groups/{config.GROUP_ID}/planner/plans", "data": {}},
        "Get Buckets": {"URL": f"{BASE_URL}/v1.0/planner/plans/{kwargs.get('planId', '')}/buckets", 'data': {}},
        "Get Tasks": {"URL": f"{BASE_URL}/{RESOURCE}/plans/{kwargs.get('planId', '')}/tasks", "data": {}},
        "Get Task": {'URL': f"{BASE_URL}/{RESOURCE}/tasks/{kwargs.get('taskId', '')}/details", "data": {}},
        "Get Bucket": {"URL": f"{BASE_URL}/{RESOURCE}/buckets/{kwargs.get('bucketId', '')}", "data": {}},
        "Update Task": {'URL': f"{BASE_URL}/{RESOURCE}/tasks/{kwargs.get('taskId', '')}/details", "data": {'title': kwargs.get('title', ''), 'description': kwargs.get('description', ''), 'previewType': 'description'}},
    }
    
    endpoint = ENDPOINTS[do]['URL']
    data = ENDPOINTS[do]['data']

    print(f'{do} at {endpoint} with {data}')

    if 'Create' in do:
        response = MSGRAPH.post(endpoint, headers=headers, data=data).json()
    
    elif 'Get' in do:
        response = MSGRAPH.get(endpoint, headers=headers).json()

    elif 'Update' in do:
        response = MSGRAPH.get(ENDPOINTS['Get Task']['URL'], headers=headers, data=ENDPOINTS['Get Task']['data']).json()
        print(response)
        eTag = response['@odata.etag']
        headers['If-Match'] = eTag
        headers['Prefer'] = "return=representation"
        response = MSGRAPH.patch(endpoint, headers=headers, data=data)
        print(response)
        response = MSGRAPH.get(ENDPOINTS['Get Task']['URL'], headers=headers, data=ENDPOINTS['Get Task']['data']).json()

    if 'error' not in response:
        print(f"Successful API call: {do}")

    else:
        print(f"API call {do} failed due to {response['error']}")

    return response

response = call_endpoint("Create Bucket", name='wtf', planId='qHfOXBxd5UGoPCaiNOKWBskAE2rj')
response = call_endpoint("Update Task", taskId='IEUy7GJAd0WNTcfLhqXbKMkAIvYH', title="title created by API", description="description created by API")

Any suggestions would be deeply appreciated.


Solution

    • Just to isolate the issue we tried the same API call and its working with Microsoft Graph Explorer.
    • You found that you need to json.dumps(data) and add the "Content-Type": "application/json" into the header for it work.