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

  1. Sign in to your TypeDB Cloud account at https://cloud.typedb.com.

  2. In Team settings - API tokens, create a new API token with Write access.

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:

  1. Generate an API access token

  2. Use this token to launch a single-node TypeDB cluster

  3. 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

  1. Export your credentials:

    export TYPEDB_CLOUD_CLIENT_ID=myClientID
    export TYPEDB_CLOUD_CLIENT_SECRET=mySecret
  2. Run the script:

    • Bash

    • Python

    • Node.js

    ./deploy.sh my-team my-space gcp europe-west2 api-cluster
    python main.py my-team my-space gcp europe-west2 api-cluster
    node 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.

Conclusion

This tutorial has shown you how to set up a script to deploy TypeDB through the Cloud API.

Similar approaches can be used for other common actions, such as pausing or resuming your clusters when not in use.

Next steps

Head back to TypeDB Cloud to keep exploring there.

View the API reference for more detail on what you can do with it.