Skip to content

Instantly share code, notes, and snippets.

@antimatter15
Created January 15, 2025 08:23
Show Gist options
  • Save antimatter15/ff88089a39c329624d4eb1ae7f358735 to your computer and use it in GitHub Desktop.
Save antimatter15/ff88089a39c329624d4eb1ae7f358735 to your computer and use it in GitHub Desktop.
Minimal NodeJS/Typescript Implementation of Azure CosmosDB REST API
const COSMOS_ENDPOINT = 'https://cosmos-demo.documents.azure.com'
async function cosmosFetch(
method: 'GET' | 'POST' | 'PUT' | 'PATCH',
path: string,
headers?: any,
body?: any
) {
const dateUtc = new Date().toUTCString()
const parts = path.match(
/(.*\/)?(dbs|colls|sprocs|udfs|triggers|users|permissions|docs)(\/.*)?$/
)
const resourceType = parts[2]
const resourceId = parts[3]
? (parts[1] || '') + parts[2] + (parts[3] || '')
: (parts[1] || '').slice(0, -1)
const stringToSign = `${method.toLowerCase()}\n${resourceType.toLowerCase()}\n${resourceId}\n${dateUtc.toLowerCase()}\n\n`
const hmac = await crypto.subtle.importKey(
'raw',
Buffer.from(process.env.AZURE_COSMOS_KEY, 'base64'),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
)
const signature = await crypto.subtle.sign('HMAC', hmac, new TextEncoder().encode(stringToSign))
const response = await fetch(`${COSMOS_ENDPOINT}/${path}`, {
method,
headers: {
Authorization: encodeURIComponent(
`type=master&ver=1.0&sig=${Buffer.from(signature).toString('base64')}`
),
'x-ms-version': '2020-07-15',
'x-ms-date': dateUtc,
Accept: 'application/json',
...(headers || {}),
},
body: JSON.stringify(body),
})
let data
try {
data = await response.json()
} catch (err) {}
if (!response.ok)
throw new Error(`CosmosDB Error ${response.status}: ${data?.message?.split('\n')[0]}`)
return data
}
async function main() {
console.log(await cosmosFetch('GET', 'dbs'))
console.log(await cosmosFetch('GET', 'dbs/Test'))
console.log(await cosmosFetch('GET', 'dbs/Test/colls'))
console.log(await cosmosFetch('GET', 'dbs/Test/colls/test'))
console.log(await cosmosFetch('GET', 'dbs/Test/colls/test/docs'))
console.log(
await cosmosFetch(
'POST',
'dbs/Test/colls/test/docs',
{
'x-ms-documentdb-isquery': 'True',
'x-ms-documentdb-query-enablecrosspartition': 'True',
'Content-Type': 'application/query+json',
},
{
query: 'SELECT c.id FROM c',
}
)
)
console.log(
await cosmosFetch('GET', 'dbs/Test/colls/test/docs/wumbology3', {
'x-ms-documentdb-partitionkey': '["wumbology3"]',
})
)
console.log(
await cosmosFetch(
'PATCH',
'dbs/Test/colls/test/docs/wumbology3',
{
'Content-Type': 'application/json',
'x-ms-documentdb-partitionkey': '["wumbology3"]',
},
{
operations: [
{
op: 'set',
path: '/FamilyName',
value: 'Bob',
},
],
}
)
)
console.log(await cosmosFetch('GET', 'dbs/Test/colls/test/sprocs'))
console.log(await cosmosFetch('GET', 'dbs/Test/colls/test/triggers'))
console.log(
await cosmosFetch(
'POST',
'dbs/Test/colls/test/docs',
{
'x-ms-documentdb-isquery': 'True',
'x-ms-documentdb-query-enablecrosspartition': 'True',
// 'x-ms-documentdb-populatequerymetrics': 'True',
'Content-Type': 'application/query+json',
},
{
query: 'SELECT c.id FROM c',
}
)
)
console.log(await cosmosFetch('GET', 'dbs/Test/users'))
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment