Deploy TypeDB via the Cloud API
This tutorial will walk you through the creation of a script to automate deployment of a TypeDB cluster on TypeDB Cloud.
We’re going to build a script that authenticates with the API, deploys a TypeDB cluster, and retrieves its status in a polling loop until it’s ready to receive incoming connections.
Before you start
-
Sign in to your TypeDB Cloud account at https://cloud.typedb.com.
-
In Team settings - API tokens, create a new API token with
Writeaccess.
|
Make sure to save the client secret somewhere safe - you will only see it when you first generate the token, and will be unable to use the token without it. |
Overview
We will write a script to deploy TypeDB, which will:
-
Generate an API access token
-
Use this token to launch a single-node TypeDB cluster
-
Wait for the cluster to become ready to receive incoming connections
Here’s the full script. In the following sections we’ll break down what each part of the script does.
-
Bash
-
Python
-
Node.js
#!/usr/bin/env bash
set -e
# Check if the required environment variables are set
if [ -z "$TYPEDB_CLOUD_CLIENT_ID" ] || [ -z "$TYPEDB_CLOUD_CLIENT_SECRET" ]; then
echo "Error: TYPEDB_CLOUD_CLIENT_ID and TYPEDB_CLOUD_CLIENT_SECRET environment variables must be set"
exit 1
fi
# Check if the required arguments are provided
if [[ "$#" -ne 5 ]]; then
echo "Usage: $0 <team_id> <space_id> <provider> <region> <cluster_id>"
exit 1
fi
TEAM_ID=$1
SPACE_ID=$2
PROVIDER=$3
REGION=$4
CLUSTER_ID=$5
# Get a short-lived access token
TYPEDB_CLOUD_ACCESS_TOKEN=$(
curl --request POST \
--url https://cloud.typedb.com/api/v1/auth \
--header "Authorization: Basic $TYPEDB_CLOUD_CLIENT_ID:$TYPEDB_CLOUD_CLIENT_SECRET"
)
CLUSTER_CONFIG="{
\"id\":\"$CLUSTER_ID\",
\"serverCount\":1,
\"storageSizeGB\":10,
\"provider\":\"$PROVIDER\",
\"region\":\"$REGION\",
\"isFree\":true,
\"machineType\":\"c2d-highcpu-2\",
\"storageType\":\"standard-rwo\",
\"version\":\"latest\"
}"
# Deploy the cluster
CLUSTER_RES=$(curl --request POST \
--url "https://cloud.typedb.com/api/team/$TEAM_ID/spaces/$SPACE_ID/clusters/deploy" \
--header "Authorization: Bearer $TYPEDB_CLOUD_ACCESS_TOKEN" \
--json "$CLUSTER_CONFIG")
# Wait for the cluster to be up and running
while [[ $(echo $CLUSTER_RES | jq -r '.status') != 'running' ]]; do
if [[ $(echo $CLUSTER_RES | jq -r '.message') != null ]]; then
echo "Error: $(echo $CLUSTER_RES | jq -r '.message')"
exit 1
fi
echo
echo "Sleeping..."
echo
sleep 15
CLUSTER_RES=$(curl --request GET \
--url https://cloud.typedb.com/api/team/$TEAM_ID/spaces/$SPACE_ID/clusters/$CLUSTER_ID \
--header "Authorization: Bearer $TYPEDB_CLOUD_ACCESS_TOKEN")
done
import requests
import os
import sys
import time
def main():
client_id = os.getenv("TYPEDB_CLOUD_CLIENT_ID")
client_secret = os.getenv("TYPEDB_CLOUD_CLIENT_SECRET")
if client_id is None or client_secret is None:
print("TYPEDB_CLOUD_CLIENT_ID and TYPEDB_CLOUD_CLIENT_SECRET environment variables must be set")
sys.exit(1)
if len(sys.argv) != 5:
print("Usage: python main.py <team_id> <space_id> <region> <cluster_id>")
sys.exit(1)
team_id = sys.argv[1]
space_id = sys.argv[2]
region = sys.argv[3]
cluster_id = sys.argv[4]
access_token = get_access_token(client_id, client_secret)
cluster_config = {
"id": cluster_id,
"serverCount": 1,
"storageSizeGB": 10,
"provider": "gcp",
"region": region,
"isFree": True,
"machineType": "c2d-highcpu-2",
"storageType": "standard-rwo",
"version": "latest"
}
response = deploy_cluster(access_token, team_id, space_id, cluster_config)
while response["status"] != "running":
print("\nSleeping...\n")
time.sleep(15)
response = get_cluster(access_token, team_id, space_id, cluster_id)
def get_access_token(client_id, client_secret):
url = "https://cloud.typedb.com/api/auth"
headers = {
"Authorization": f"Basic {client_id}:{client_secret}"
}
response = requests.post(url, headers=headers)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.text
def deploy_cluster(access_token, team_id, space_id, cluster_config):
url = f"https://cloud.typedb.com/api/team/{team_id}/spaces/{space_id}/clusters/deploy"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.post(url, headers=headers, json=cluster_config)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.json()
def get_cluster(access_token, team_id, space_id, cluster_id):
url = f"https://cloud.typedb.com/api/team/{team_id}/spaces/{space_id}/clusters/{cluster_id}"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get(url, headers=headers)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
main()
main();
async function main() {
const clientId = process.env.TYPEDB_CLOUD_CLIENT_ID;
const clientSecret = process.env.TYPEDB_CLOUD_CLIENT_SECRET;
if (!clientId || !clientSecret) {
console.error("TYPEDB_CLOUD_CLIENT_ID or TYPEDB_CLOUD_CLIENT_SECRET not found");
process.exit(1);
}
if (process.argv.length != 6) {
console.error("Usage: node deploy.ts <team_id> <space_id> <region> <cluster_id>");
process.exit(1);
}
const teamId = process.argv[2];
const spaceId = process.argv[3];
const region = process.argv[4];
const clusterId = process.argv[5];
const accessToken = await getAccessToken(clientId, clientSecret);
const clusterConfig = {
id: clusterId,
serverCount: 1,
storageSizeGB: 10,
provider: "gcp",
region: region,
isFree: true,
machineType: "c2d-highcpu-2",
storageType: "standard-rwo",
version: "latest"
};
let response = await deployCluster(accessToken, teamId, spaceId, clusterConfig);
while (response.status != "running") {
console.log("\nSleeping...\n");
await new Promise((resolve) => { setTimeout(resolve, 15_000); });
response = await getCluster(accessToken, teamId, spaceId, clusterId);
}
}
async function getAccessToken(clientId, clientSecret) {
const url = "https://cloud.typedb.com/api/v1/auth";
const request = new Request(
url, {
method: "POST",
headers: {Authorization: `Basic ${clientId}:${clientSecret}`}
}
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.text();
});
}
async function deployCluster(accessToken, teamId, spaceId, clusterConfig) {
const url = `https://cloud.typedb.com/api/v1/team/${teamId}/spaces/${spaceId}/clusters/deploy`;
const request = new Request(
url, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(clusterConfig),
},
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.json();
});
}
async function getCluster(accessToken, teamId, spaceId, clusterId) {
const url = `https://cloud.typedb.com/api/v1/team/${teamId}/spaces/${spaceId}/clusters/${clusterId}`;
const request = new Request(
url, {
method: "GET",
headers: {Authorization: `Bearer ${accessToken}`},
},
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.json();
});
}
Script breakdown
1. Arguments
-
Bash
-
Python
-
Node.js
if [ -z "$TYPEDB_CLOUD_CLIENT_ID" ] || [ -z "$TYPEDB_CLOUD_CLIENT_SECRET" ]; then
echo "Error: TYPEDB_CLOUD_CLIENT_ID and TYPEDB_CLOUD_CLIENT_SECRET environment variables must be set"
exit 1
fi
if [[ "$#" -ne 4 ]]; then
echo "Usage: $0 <team_id> <space_id> <region> <cluster_id>"
exit 1
fi
TEAM_ID=$1
SPACE_ID=$2
REGION=$3
CLUSTER_ID=$4
client_id = os.getenv("TYPEDB_CLOUD_CLIENT_ID")
client_secret = os.getenv("TYPEDB_CLOUD_CLIENT_SECRET")
if client_id is None or client_secret is None:
print("TYPEDB_CLOUD_CLIENT_ID and TYPEDB_CLOUD_CLIENT_SECRET environment variables must be set")
sys.exit(1)
if len(sys.argv) != 5:
print("Usage: python main.py <team_id> <space_id> <region> <cluster_id>")
sys.exit(1)
team_id = sys.argv[1]
space_id = sys.argv[2]
region = sys.argv[3]
cluster_id = sys.argv[4]
const clientId = process.env.TYPEDB_CLOUD_CLIENT_ID;
const clientSecret = process.env.TYPEDB_CLOUD_CLIENT_SECRET;
if (!clientId || !clientSecret) {
console.error("TYPEDB_CLOUD_CLIENT_ID or TYPEDB_CLOUD_CLIENT_SECRET not found");
process.exit(1);
}
if (process.argv.length != 6) {
console.error("Usage: node deploy.ts <team_id> <space_id> <region> <cluster_id>");
process.exit(1);
}
const teamId = process.argv[2];
const spaceId = process.argv[3];
const region = process.argv[4];
const clusterId = process.argv[5];
We use environment variables for the Client ID and Client Secret of the API token, and take our other configurable options as command-line arguments.
2. Token exchange
-
Bash
-
Python
-
Node.js
TYPEDB_CLOUD_ACCESS_TOKEN=$(
curl --request POST \
--url https://cloud.typedb.com/api/v1/auth \
--header "Authorization: Basic $TYPEDB_CLOUD_CLIENT_ID:$TYPEDB_CLOUD_CLIENT_SECRET"
)
def get_access_token(client_id, client_secret):
url = "https://cloud.typedb.com/api/v1/auth"
headers = {
"Authorization": f"Basic {client_id}:{client_secret}"
}
response = requests.post(url, headers=headers)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.text
async function getAccessToken(clientId, clientSecret) {
const url = "https://cloud.typedb.com/api/v1/auth";
const request = new Request(
url, {
method: "POST",
headers: {Authorization: `Basic ${clientId}:${clientSecret}`}
}
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.text();
});
}
We’ll need an access token.
To get it we post to https://cloud.typedb.com/api/v1/auth
with the long-lived client ID and secret.
3. Cluster configuration
-
Bash
-
Python
-
Node.js
CLUSTER_CONFIG="{
\"id\":\"$CLUSTER_ID\",
\"serverCount\":1,
\"storageSizeGB\":10,
\"provider\":\"gcp\",
\"region\":\"$REGION\",
\"isFree\":true,
\"machineType\":\"c2d-highcpu-2\",
\"storageType\":\"standard-rwo\",
\"version\":\"latest\"
}"
cluster_config = {
"id": cluster_id,
"serverCount": 1,
"storageSizeGB": 10,
"provider": "gcp",
"region": region,
"isFree": True,
"machineType": "c2d-highcpu-2",
"storageType": "standard-rwo",
"version": "latest"
}
const clusterConfig = {
id: clusterId,
serverCount: 1,
storageSizeGB: 10,
provider: "gcp",
region: region,
isFree: true,
machineType: "c2d-highcpu-2",
storageType: "standard-rwo",
version: "latest"
};
This JSON object defines how your cluster will be deployed. The parameters could be redefined in the script, or adjusted to be arguments to suit your needs. In this case, we’ve provided preset values for all parameters except ID and region.
See the API reference for more details on cluster configuration.
4. Deploying TypeDB
-
Bash
-
Python
-
Node.js
CLUSTER_RES=$(
curl --request POST \
--url "https://cloud.typedb.com/api/v1/team/$TEAM_ID/spaces/$SPACE_ID/clusters/deploy" \
--header "Authorization: Bearer $TYPEDB_CLOUD_ACCESS_TOKEN" \
--json "$CLUSTER_CONFIG"
)
def deploy_cluster(access_token, team_id, space_id, cluster_config):
url = f"https://cloud.typedb.com/api/v1/team/{team_id}/spaces/{space_id}/clusters/deploy"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.post(url, headers=headers, json=cluster_config)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.json()
async function deployCluster(accessToken, teamId, spaceId, clusterConfig) {
const url = `https://cloud.typedb.com/api/v1/team/${teamId}/spaces/${spaceId}/clusters/deploy`;
const request = new Request(
url, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(clusterConfig),
},
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.json();
});
}
We use the cluster config and the access token we acquired previously to actually deploy the cluster. We store the response for use in the next step.
5. Waiting for the cluster to be ready
-
Bash
-
Python
-
Node.js
while [[ $(echo $CLUSTER_RES | jq -r '.status') != 'running' ]]; do
if [[ $(echo $CLUSTER_RES | jq -r '.message') != null ]]; then
echo "Error: $(echo $CLUSTER_RES | jq -r '.message')"
exit 1
fi
echo
echo "Sleeping..."
echo
sleep 15
CLUSTER_RES=$(curl --request GET \
--url https://cloud.typedb.com/api/v1/team/$TEAM_ID/spaces/$SPACE_ID/clusters/$CLUSTER_ID \
--header "Authorization: Bearer $TYPEDB_CLOUD_ACCESS_TOKEN")
done
while response["status"] != "running":
print("\nSleeping...\n")
time.sleep(15)
response = get_cluster(access_token, team_id, space_id, cluster_id)
def get_cluster(access_token, team_id, space_id, cluster_id):
url = f"https://cloud.typedb.com/api/v1/team/{team_id}/spaces/{space_id}/clusters/{cluster_id}"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get(url, headers=headers)
if response.status_code >= 400: print(response.text)
response.raise_for_status()
return response.json()
while (response.status != "running") {
console.log("\nSleeping...\n");
await new Promise((resolve) => { setTimeout(resolve, 15_000); });
response = await getCluster(accessToken, teamId, spaceId, clusterId);
}
async function getCluster(accessToken, teamId, spaceId, clusterId) {
const url = `https://cloud.typedb.com/api/v1/team/${teamId}/spaces/${spaceId}/clusters/${clusterId}`;
const request = new Request(
url, {
method: "GET",
headers: {Authorization: `Bearer ${accessToken}`},
},
);
return fetch(request).then(async res => {
if (!res.ok) throw Error(await res.text());
return res.json();
});
}
We wait for the cluster to be ready to receive incoming connections by polling the cluster’s status until it’s running. If we encounter an error at any point (either during the initial deployment, or when subsequently getting the cluster to check its status) we print the error and exit.
Example usage
-
Export your credentials:
export TYPEDB_CLOUD_CLIENT_ID=myClientID export TYPEDB_CLOUD_CLIENT_SECRET=mySecret -
Run the script:
-
Bash
-
Python
-
Node.js
./deploy.sh my-team my-space gcp europe-west2 api-clusterpython main.py my-team my-space gcp europe-west2 api-clusternode deploy.js my-team my-space gcp europe-west2 api-cluster -
If successful, TypeDB Cloud will deploy your cluster, and the script will poll it until it’s ready to receive incoming connections.