Developing with the Astra DB Document API

The Stargate Document API modifies and queries data stored as unstructured JSON documents in collections. Because the Document API uses schemaless data, no data modeling is required!

If the Document API is used with Apache Cassandra, the document indexing is accomplished with secondary indexes. If the Document API is used with DataStax Enterprise, SAI indexing is used. The blog The Stargate Cassandra Documents API describes the underlying structure used to store collections.

Information about namespaces and collections.

To use the Document API, you must define the namespace that will store collections. Collections store unstructured JSON documents. Documents can themselves hold multiple documents. Multiple collections are contained in a namespace, but a collection cannot be contained in multiple namespaces.

Only namespaces need to be specifically created. Collections are specified when a document is inserted.

Prerequisites

If you haven’t already, create a database using Astra DB.

  • Install cURL, a utility for running REST, Document, or GraphQL queries on the command line.

  • [Optional] If you prefer, you can use Postman as a client interface for exploring the APIs

    • You will also find links to downloadable collections and environments in Using Postman

  • [Optional] If you going to use the GraphQL API, you will want to use the GraphQL Playground to deploy schema and execute mutations and queries.

  • [Optional] For the REST and Document APIs, you can use the Swagger UI.

Before you get started, set your environment variables to save time developing on your database. There are four environment variables, three of which you will get from the Astra dashboard (database id, region, and keyspace), and one that you must create (token).

  1. In Astra DB, select the database to which you want to connect.

  2. In your Database Dashboard, select Connect.

  3. Select your API.

    If you have multiple regions, select the region you want to connect to from the dropdown menu for instructions.

  4. Follow the steps to get your application token and set up your environment variables. Or if you have an older Astra Classic database, follow the steps in Authentication for classic databases.

API reference

If you prefer to learn using a QuickStart, try out the Stargate Document QuickStart. To view the API Reference, see Astra DB Document API.

Create namespace

See Adding a new keyspace to add a new namespace, or keyspace as it is known in Astra.

Checking namespace existence

To check if a namespaces exist, execute a Document API query with cURL to find all the namespaces:

  • cURL command (/v2)

  • Result

curl -L -X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com//api/rest/v2/schemas/namespaces' \
-H "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
-H 'Content-Type: application/json'
{"data":[{"name":"system_distributed"},{"name":"system"},
{"name":"data_endpoint_auth"},{"name":"system_schema"},{"name":"myworld"},
{"name":"stargate_system"},{"name":"system_auth"},{"name":"system_traces"}]}

To get a particular namespace, specify the namespace in the URL:

  • cURL command (/v2)

  • Result

curl -X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/schemas/namespaces/namespaces/myworld' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{"data":{"name":"myworld"}}

Writing documents

All data written with the Document API is stored as JSON documents stored in collections.

For more information about the database design of the Document API, see the blog post on the Documents API.

Add document specifying a collection name

First, let’s add a document to a specified collection. Send a POST request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name} to add data to the collection fitness. The data is passed in the JSON body.

  • cURL command (/v2)

  • Result

curl --location \
--request POST 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
  "id": "some-stuff",
  "other": "This is nonsensical stuff."
}'
{"documentId":"{docid}"}

Notice that the document-id returned is a UUID if not specified.

Add document specifying collection name and document-id

Next, let’s add a document to a specified collection, but specify the document-id. Send a PUT request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id} to add data to the collection Janet. The document-id can be any string. The data is passed in the JSON body.

  • cURL command (/v2)

  • Result

curl -L -X PUT 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
  "firstname": "Janet",
  "lastname": "Doe",
  "email": "janet.doe@gmail.com",
  "favorite color": "grey"
}'
{"documentId":"Janet"}

Note the difference between using POST and PUT. The POST request is used to insert new documents when you want the system to auto-generate the documentId. The PUT request is used to insert a new document when you want to specify the documentId.

PUT requests can also be used to update an existing document. Let’s look at those examples, next.

Inserting a sub-document

You can also insert documents that have nested values, or sub-documents. Send a PUT request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id} to add data to the existing collection. The data is passed in the JSON body.

  • cURL command (/v2)

  • Result

curl -L -X PUT 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
    "firstname": "Joey",
    "lastname": "Doe",
    "weights": {
      "type": "bench press",
      "weight": 150,
      "reps": 15
  }
}'
{"documentId":"Joey"}

Reading documents

Retrieving a specified document

Let’s check that the data was inserted for a particular document. Send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id} to retrieve the document:

  • cURL command (/v2)

  • Result

curl -L \
-X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/{docid}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
	"documentId":"{docid}",
	"data":{
		"id":"some-stuff",
		"other":"This is nonsensical stuff."
	}
}

It is possible to get a value for a particular field in a document using one of two methods, either a where clause or a document-path. These methods can retrieve information from a document or a sub-document.

Retrieving a document using a where clause

Now let’s search for a particular document using a where clause. Send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}?{where-clause} to get the same information:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"firstname":\{"$eq":"Janet"\}\}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
	"data":{
		"Janet":{
			"email":"janet.doe@gmail.com",
			"favorite color":"grey",
			"firstname":"Janet",
			"lastname":"Doe"
		}
	}
}

Note that the where clause must be url encoded, so curly brackets are escaped with \ and spaces must be replaced with %20. Also, the full document is returned, as opposed to the value of the field specified in the {document-path} like the next command.

Read with where

You can also search with a multiple where clause. Send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}?{where-clause} to get the same information:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"firstname":\{"$eq":"Janet"\},"lastname":\{"$eq":"Doe"\}\}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
	"data":{
		"Janet":{
			"email":"janet.doe@gmail.com",
			"favorite color":"grey",
			"firstname":"Janet",
			"lastname":"Doe"
		}
	}
}

Note that the where clause must be url encoded, so curly brackets are escaped with \ and spaces must be replaced with %20. Also, the full document is returned, as opposed to the value of the field specified in the {document-path} like the next command.

You can also retrieve documents using a WHERE clause that searches sub-documents:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'lhttps://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"weights.type":\{"$eq":"bench%20press"\}\}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
	"data":{
		"Joey":{
			"firstname":"Joey",
			"lastname":"Doe",
			"weights":{
				"reps":15,
				"type":"bench press",
				"weight":150
			}
		}
	},
	"pageState":null
}

Multiple where can be used in a variety of cases. Here, a numerical value between to values is sought:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"weights.reps":\{"$gt":12\},"weights.reps":\{"$lt":20\}\}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
  "data": {
    "Joey": {
      "firstname": "Joey",
      "lastname": "Doe",
      "weights": {
        "reps": 15,
        "type": "bench press",
        "weight": 150
      }
    }
  }
}

Retrieving all documents

Let’s check that the document was inserted. Send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name} to retrieve all the documents:

  • cURL command (/v2)

  • Result

curl --location \
--request GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?page-size=3' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
  "data":{
     "Joey":{
	"firstname":"Joey",
	"lastname":"Doe",
	"weights":{
		"reps":15,
		"type":"bench press",
		"weight":150
	}
     },
     "Janet":{
	"email":"janet.doe@gmail.com",
	"favorite color":"grey",
	"firstname":"Janet",
	"lastname":"Doe"
     },
     "{docid}":{
	"id":"some-stuff",
	"other":"This is nonsensical stuff."
     }
  }
}

The page-size parameter is included to get all the documents, rather than the last inserted document.

Retrieving all documents with Paging

For large collections, you can page a subset of the results. In this example, page-size is set to 5. Send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}page-size=5 to retrieve the first five documents (a page) in the collection:

  • cURL command (/v2)

  • Result

curl --location \
--request GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?page-size=5' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
  "pageState":"JGNlYjczMDc5LTE1NTItNGQyNS1hM2ExLWE2MzgxNWVlYTAyMADwf_____B_____",
  "data":{
    "58b12778-0efd-466e-89bf-66a4c99adee1":{"author":"Tom Clancy","title":"Red Rabbit"},
    "77fe8690-f8d4-43b8-b1c9-a328318d4eae":{"author":"Tom Clancy","title":"Every Man a Tiger"},
    "3177f86c-a633-4302-92a5-de4c15ab5840":{"author":"Tom Clancy","title":"Rainbow Six"},
    "cefc7117-fc73-47b8-a965-099cf3a59269":{"author":"Tom Clancy","title":"Clear and Present Danger"},
    "ceb73079-1552-4d25-a3a1-a63815eea020":{"author":"Tom Clancy","title":"The Cardinal of the Kremlin"}
  }
}

Pay close attention to the pageState value in the results. The pageState is a string representation a location in the result set. It is essentially an encoded shortcut that allows the final result set to be built from a specific point.

In order to get the next five documents, re-run the request with page-state parameter set to the first page’s pageState:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Joey/weights/type' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{"documentId":"Joey","data":"bench press"}

In this case, the sub-document weights is the document-path specified to retrieve that data about the reps, type, and weight.

  • cURL command (/v2)

  • Result

curl --location --request GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Joey/weights' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
	"documentId":"Joey",
	"data":{
		"reps":15,
		"type":"bench press",
		"weight":150
	}
}

Retrieving a specific portion of a document with document-path

Let’s add another record for the next example:

  • cURL command (/v2)

  • Result

curl -L -X PUT 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Martha' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
    "firstname": "Martha",
    "lastname": "Smith",
    "weights": {
      "type": "bench press",
      "weight": 125,
      "reps": 12
  }
}'
{"documentId":"Martha"}

To find particular values, send a GET request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id}/{document-path} to retrieve all the users that have, say, weight reps between 11 and 16:

  • cURL command (/v2)

  • Result

curl -L -X  GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"weights.*":\{"$gt":11\},"weights.*":\{"$lt":16\}\}&page-size=3' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header "Content-Type: application/json"
{
  "data": {
    "Joey": {
      "firstname": "Joey",
      "lastname": "Doe",
      "weights": {
        "reps": 15,
        "type": "bench press",
        "weight": 150
      }
    },
    "Martha": {
      "firstname": "Martha",
      "lastname": "Smith",
      "weights": {
        "reps": 12,
        "type": "bench press",
        "weight": 125
      }
    }
  }
}

Update documents

Data changes, so often it is necessary to update an entire document.

Replace a document

Send a PATCH request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id} to replace data to the existing collection. All fields included will be changed.

  • cURL command (/v2)

  • Result

curl -L \
-X PATCH 'lhttps://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
    "firstname": "JanetLee",
    "lastname": "Doe"
}'
{"documentId":"Janet"}

A GET request will show that the data has been replaced in the document:

  • cURL command (/v2)

  • Result

curl -L -X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet' \
 --header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
 --header 'Content-Type: application/json'
{
	"documentId":"Janet",
	"data":{
		"email":"janet.doe@gmail.com",
		"favorite color":"grey",
		"firstname":"JanetLee",
		"lastname":"Doe"
	}
}
PATCH updates are upserts. If the document doesn’t exist, it will be created. If it does exist, it will be updated with the new document data.

Replace part of of a document or sub-document

It is also possible to update only part of a document. To partially update, send a PATCH request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id}/{document-path}. In this example, we want to change just the firstname of the document:

  • cURL command (/v2)

  • Result

curl -L \
-X PATCH 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
      "firstname": "Joseph"
}'
{"documentId":"Joey"}

and a GET will show that only the weights has been changed.

  • cURL command (/v2)

  • Result

curl -L \
-X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Joey' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
  "documentId":"Joey",
  "data":{
    "firstname":"Joseph",
    "lastname":"Doe",
    "weights":{
      "reps":15,
      "type":"bench press",
      "weight":150
    }
  }
}

To partially update a sub-document, send a PATCH request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id}/{document-path} in the same manner as the last command, but including only sub-document information to change and the document-path of the sub-document. Include all fields that you wish to update.

  • cURL command (/v2)

  • Result

curl -L \
-X PATCH 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Janet/weights' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
    "reps": 10,
    "type": "squat",
    "weight": 350
}'
{"documentId":"Joey"}

and a GET will show that only the weights has been changed.

  • cURL command (/v2)

  • Result

curl -L \
-X GET 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/Joey' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'
{
  "documentId":"Joey",
  "data":{
    "firstname":"Joseph",
    "lastname":"Doe",
    "weights":{
      "reps":10,
      "type":"squat",
      "weight":350
    }
  }
}

Delete a document

To delete a document, send a DELETE request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id}.

curl -L \
-X DELETE 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness/{docid}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'

To delete a document, based on a document path, send a DELETE request to /api/rest/v2/namespaces/{namespace_name}/collections/{collections_name}/{document-id}/{document-path}.

curl -L -X  DELETE 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness?where=\{"id":\{"$eq":"some%2Dstuff"\}\}' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'

Delete a collection

Send a DELETE request to /api/rest/v2/namespaces/namespaces/{namespace_name}/collections/{collection_name} to delete a collection. All data will be deleted along with the collection schema.

curl -L \
-X DELETE 'https://$ASTRA_CLUSTER_ID-$ASTRA_REGION.apps.astra.datastax.com/api/rest/v2/namespaces/myworld/collections/fitness' \
--header "X-Cassandra-Token: $ASTRA_DB_APPLICATION_TOKEN" \
--header 'Content-Type: application/json'

Document API Software Development Kit (SDK)

Node.js can be used with Astra to programmatically interact with your data using the Document API. An example of a client to work with collections is shown below:

Node.js Document Collection Client

Connect your app to DataStax Astra DB using the Document API in node.js.

The Astra DB Collection Node.js Client connects to the Astra DB Document API.

Set up your environment

  1. Install the Astra DB JS Collection:

npm install @astrajs/collections
  1. Open a browser, navigate to DataStax Astra, and log in.

  2. From your Dashboard page, select your database.

  3. Copy the Cluster ID of your database.

You can also find the Cluster ID in the URL, which is the last UUID in the path: https://astra.datastax.com/org/{org-Id}/database/{databaseid}

  1. Add the Cluster ID as an environment variable with the following command:

export ASTRA_DB_ID={databaseid}

Example:

export ASTRA_DB_ID=b5285f63-8da5-4c6e-afd8-ade371a48795
  1. Copy the Region of your database, the region where your database is located.

  2. Add the Region as an environment variable with the following command:

export ASTRA_DB_REGION={region}

Example:

export ASTRA_DB_REGION=us-east1
  1. Add your username and your password as environment variables with the following command:

export ASTRA_DB_APPLICATION_TOKEN={token}
  1. Use printenv to ensure the environment variables were exported.

Use Client with Nodejs

Document API
const { createClient } = require("@astrajs/collections");

// create an {astra_db} client
const astraClient = await createClient({
    astraDatabaseId: process.env.ASTRA_DB_ID,
    astraDatabaseRegion: process.env.ASTRA_DB_REGION,
    applicationToken: process.env.ASTRA_DB_APPLICATION_TOKEN,
});

// create a shortcut to the users collection in the app namespace/keyspace
// collections are created automatically
const usersCollection = astraClient.namespace("app").collection("users");

// get a single user by document id
const user = await usersCollection.get("cliff@wicklow.com");

// get a subdocument by path
const userBlogComments = await usersCollection.get("cliff@wicklow.com/blog/comments");

// search a collection of documents
const users = await usersCollection.find({ name: { $eq: "Cliff" } });

// find a single user
const user = await usersCollection.findOne({ name: { $eq: "dang" } });

// create a new document (a documentId is generated)
const user = await usersCollection.create({
  name: "New Guy",
});

// create a new user (specifying documentId)
const user = await usersCollection.create("cliff@wicklow.com", {
  name: "cliff",
});

// create a user subdocument
const user = await usersCollection.create("cliff@wicklow.com/blog", {
  title: "new blog",
});

// partially update user
const user = await usersCollection.update("cliff@wicklow.com", {
  name: "cliff",
});

// partially update a user subdocument
const userBlog = await usersCollection.update("cliff@wicklow.com/blog", {
  title: "my spot",
});

// replace a user subdocumet
const userBlog = await usersCollection.replace("cliff@wicklow.com/blog", {
  title: "New Blog",
});

// delete a user
const user = await usersCollection.delete("cliff@wicklow.com");

// delete a user subdocument
const userBlog = await usersCollection.delete("cliff@wicklow.com/blog");