Azure Cosmos DB client for Cloudflare Workers and web. Tiny package, minimal dependencies, streaming optimized.
import { CosmosClient } from '@cfworker/cosmos';
// 🚨️ Do not commit your Cosmos DB master key to source control!
// Use a bundler like Rollup, Parcel, or Webpack to interpolate your master key at build-time.
const accountKey = '...top secret master key copied from the azure portal...';
const endpoint = 'https://xxxxxxxxxxxx.documents.azure.com';
const client = new CosmosClient({ endpoint, accountKey });
// or
const client = new CosmosClient({ connectionString });
By default the CosmosClient uses the "Session" consistency level. You may override the default value when constructing the CosmosClient.
const consistencyLevel = 'Eventual';
const client = new CosmosClient({ endpoint, accountKey, consistencyLevel });
Most methods on CosmosClient accept a consistencyLevel
argument to enable overriding the client's consistency level on a case-by-case basis.
const res = client.getDocuments({ consistencyLevel: 'Bounded' });
Most methods on CosmosClient require dbId and collId arguments. You may specify default values for these arguments when constructing the CosmosClient.
const dbId = 'my-db';
const collId = 'my-coll';
const client = new CosmosClient({ endpoint, accountKey, dbId, collId });
Your Cosmos DB master key should never be sent to the browser. Use resource tokens, which are scoped and time limited when accessing Cosmos DB from the front-end.
not-implemented, coming soon...
const res = await client.getDatabases();
const dbs = await res.json();
With max-items / continuation:
let res = await client.getDatabases({ maxItems: 10 });
console.log(await res.json()); // print first 10 dbs
while (res.hasNext) {
res = await res.next();
console.log(await res.json()); // print next page of dbs until res.hasNext is false.
}
const res = client.getDatabase({ dbId: 'my-db' });
const db = res.json();
If you specified dbId when instantiating the CosmosClient, then the dbId argument isn't required:
const res = client.getDatabase();
const db = res.json();
const res = await client.getCollections({ dbId: 'my-db' });
const colls = await res.json();
const res = await client.getCollection({
dbId: 'my-db',
collId: 'my-coll'
});
const coll = await res.json();
If you specified dbId when instantiating the CosmosClient, then the dbId argument isn't required:
const res = await client.getCollection({ collId: 'my-coll' });
const coll = await res.json();
If you specified both dbId and collId when instantiating the CosmosClient, then the dbId and collId arguments are not required:
const res = await client.getCollection();
const coll = await res.json();
const dbId = 'my-db';
const collId = 'my-coll';
const partitionKey: PartitionKeyDefinition = {
paths: ['/_partitionKey'],
kind: 'Hash'
};
const res = await client.createCollection({ dbId, collId, partitionKey });
if (res.status === 201) {
// created!
} else if (res.status === 409) {
// conflict! collection already exists.
}
const dbId = 'my-db';
const collId = 'my-coll';
const partitionKey: PartitionKeyDefinition = {
paths: ['/_partitionKey'],
kind: 'Hash'
};
// create collection
const res = await client.createCollection({ dbId, collId, partitionKey });
const etag = res.etag;
// disable indexing
const indexingPolicy: IndexingPolicy = {
indexingMode: 'none',
automatic: false
};
const res = await client.replaceCollection({
dbId,
collId,
ifMatch: etag,
indexingPolicy,
partitionKey
});
const res = await client.deleteCollection({ dbId, collId });
interface Person {
id: string;
name: string;
age: number;
}
let res = await client.getDocuments<Person>({ maxItems: 100 });
console.log(await res.json()); // print first 100 results
while (res.hasNext) {
res = await res.next();
console.log(await res.json()); // continue printing results until hasNext is false
}
const res = await client.getDocument<Person>({ docId: 'xyz' });
const document: MessageDoc = {
id: docId,
message: 'a',
_partitionKey: 'test' // container is configured with partition key "/_partitionKey"
};
const res = await client.createDocument({
document,
partitionKey: 'test'
});
const etag = res.etag; // capture etag value for use with updates
const res = await client.createDocument<MessageDoc>({
document,
partitionKey: 'test',
isUpsert: true
});
const res = await client.replaceDocument<MessageDoc>({
docId,
document,
partitionKey: 'test',
ifMatch: etag // optimistic concurrency
});
const res = await client.deleteDocument({ docId });
const query = `SELECT * FROM ROOT`;
const res = await client.queryDocuments<Person>({ query });
const results = await res.json();
const query = `SELECT * FROM ROOT x WHERE x.id = @id`;
const parameters: QueryParameter[] = [{ name: '@id', value: 'xyz' }];
const res = await client.queryDocuments({ query, parameters });
const results = await res.json();
const query = `SELECT * FROM ROOT`;
const res = await client.queryDocuments({ query, enableCrossPartition: true });
const results = await res.json();
const query = `SELECT * FROM ROOT`;
const res = await client.queryDocuments({ query, populateMetrics: true });
const metrics = res.headers.get('x-ms-documentdb-query-metrics');
git clone https://github.com/cfworker/cfworker
cd cfworker
npm install
npm run start-cosmos --workspace=@cfworker/examples
-
Clone and install deps.
git clone https://github.com/cfworker/cfworker npm install
-
Open with VSCode
code cfworker
-
Optional: to run tests locally, go to the Azure portal, create a Cosmos DB account for integration testing. Then create a
.env
file inpackages/cosmos
file with following valuesCOSMOS_DB_ORIGIN=https://xxxxxxxxxxx.documents.azure.com COSMOS_DB_MASTER_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx COSMOS_DB_DATABASE=xxxxxxxxx