CosmosDB Rest API Obscure Failure

105 Views Asked by At

As per official doc, Wrote code to make Rest API call to fetch one doc(json) from the CosmosDB collection [Code is in the last]. But it is returning -

{'code': 'BadRequest', 'message': 'One of the input values is invalid.\r\nActivityId: <***>, Windows/10.0.17763 cosmos-netstandard-sdk/3.18.0'}

Tried executing the query directly on the CosmosDB UI and it is working fine. Response is not giving much info. so unable to debug, why is it giving this issue ? Any kind of help is much appreciated.

    def query(self, subscription_id, resource_group_name, name, tenant_id, client_id, client_secret, db_account_name, database_name, collection_name, master_key):

        # Start of the code to generate the auth token from master key.
        decoded_master_key = base64.b64decode(master_key)

        resource_type = 'docs'
        resource_id = f'dbs/{database_name}/colls/{collection_name}'

        verb = 'POST'
        date = format_date_time(mktime(datetime.now().timetuple()))
        pain_digest_body = "{verb}\n{resource_type}\n{resource_id}\n{date}\n{other}\n".format(
            verb=(verb.lower() or ''),
            resource_type=(resource_type.lower() or ""),
            resource_id=(resource_id or ""),
            date=date.lower(),
            other="".lower())

        digest_body = pain_digest_body.encode("utf-8")
        digest = hmac.new(decoded_master_key, digest_body, sha256).digest()
        signature = base64.encodebytes(digest).decode("utf-8")

        key_type = 'master'
        version = '1.0'
        master_key_authorization_signature = quote(f'type={key_type}&ver={version}&sig={signature[:-1]}')
        # End of the code to generate the auth token from master key.

        headers = {'x-ms-documentdb-isquery': 'True',
                   'x-ms-date': date,
                   'authorization': master_key_authorization_signature,
                   'x-ms-max-item-count': '1',
                   'x-ms-query-enable-crosspartition': 'True',
                   'Content-Type': 'application/json',
                   'x-ms-version': '2018-09-17',
                   'Accept': 'application/json',
                   'x-ms-documentdb-query-enable-scan': 'True',
                   'x-ms-documentdb-populatequerymetrics': 'True'
                   }

        data = {
            'query': f'SELECT * FROM c OFFSET 1 LIMIT 1'
        }

        url = 'https://{}.documents.azure.com/dbs/{}/colls/{}/docs'.format(db_account_name,database_name,
                                                                                                 collection_name)

        response = requests.post(url, headers=headers, data=data, timeout=60)

        print(response)

        return response.json()

1

There are 1 best solutions below

2
Balaji On

'x-ms-query-enable-crosspartition': 'True' is passed in your code, but there is no partition key 'x-ms-documentdb-partitionkey'. To solve this, you can provide a partition key, and then the data will be retrieved from the database that matches the partition key value given in x-mx-documentdb-partitionkey.

In 'Content-Type', instead of 'application/json', try 'application/query+json' as you can see in the code below:

def query(self, subscription_id, resource_group_name, name, tenant_id, client_id, client_secret, db_account_name, database_name, collection_name, master_key):

        decoded_master_key = base64.b64decode(master_key)

        resource_type = 'docs'
        resource_id = f'dbs/{database_name}/colls/{collection_name}'

        verb = 'POST'
        date = format_date_time(mktime(datetime.now().timetuple()))
        plain_digest_body = "{verb}\n{resource_type}\n{resource_id}\n{date}\n{other}\n".format(
            verb=(verb.lower() or ''),
            resource_type=(resource_type.lower() or ""),
            resource_id=(resource_id or ""),
            date=date.lower(),
            other="".lower())

        digest_body = plain_digest_body.encode("utf-8")
        digest = hmac.new(decoded_master_key, digest_body, sha256).digest()
        signature = base64.encodebytes(digest).decode("utf-8")

        key_type = 'master'
        version = '1.0'
        master_key_authorization_signature = quote(f'type={key_type}&ver={version}&sig={signature[:-1]}')
        
        headers = {
            'x-ms-documentdb-isquery': 'True',
            'x-ms-date': date,
            'authorization': master_key_authorization_signature,
            'x-ms-max-item-count': '1',
            'x-ms-query-enable-crosspartition': 'True',
            'Content-Type': 'application/query+json',
            'x-ms-version': '2018-09-17',
            'Accept': 'application/json',
            'x-ms-documentdb-query-enable-scan': 'True',
            'x-ms-documentdb-populatequerymetrics': 'True',
            'x-ms-documentdb-partitionkey': "[\"1\"]"
        }

        data = {
            'query': 'SELECT * FROM c'
        }
        url = f'https://{db_account_name}.documents.azure.com/dbs/{database_name}/colls/{collection_name}/docs'
        response = requests.post(url, headers=headers, json=data, timeout=60)
        print(response)
        return response.json()

Output:

<Response [200]>
{'_rid': 'AtQHAIGz3Xc=', 'Documents': [{'id': '1', 'name': 'Balaji', 'Dept': 'IT', '_rid': 'AtQHAIGz3XcBAAAAAAAAAA==', '_self': 'dbs/AtQHAA==/colls/AtQHAIGz3Xc=/docs/AtQHAIGz3XcBAAAAAAAAAA==/', '_etag': '"07000f0d-0000-0700-0000-657015710000"', '_attachments': 'attachments/', '_ts': 1701844337}], '_count': 1}