Create a custom visualization using REST APIs

Create a custom visualization using REST APIs

ThoughtSpot REST APIs can be accessed within the browser to retrieve data in a JSON format, which can then be used to render a custom visualization using any front-end library.

Rendering a custom visualization from ThoughtSpot data within a web application involves the following steps:

  1. Sign in via Visual Embed SDK

  2. Call ThoughtSpot REST API to retrieve data

  3. Transform the ThoughtSpot REST API data response to the format of the charting library data objects

  4. Render the chart on the page using the charting library

Sign-in via Visual Embed SDK🔗

Any method of sign-in establishes a ThoughtSpot session in the browser. After a session is established, you can make REST API requests from the browser as the signed-in user as long as credentials are included in the request.

The trusted authentication SSO method issues a REST API sign-in command automatically when the init() function is called, without the need to render any ThoughtSpot embed components:

import {
    init,
    AuthType
} from 'https://cdn.jsdelivr.net/npm/@thoughtspot/visual-embed-sdk/dist/tsembed.es.js';

init({
   thoughtSpotHost: "{thoughtSpotFQDN}",
   authType:  AuthType.TrustedAuthToken,  // Trusted Authentication
   username: tsUsername, // string variable of username to sign-in
   getAuthToken: tokenCallbackFunc // Trusted Auth token retrieval callback function
 });

Call ThoughtSpot REST API to retrieve data🔗

You can request data from the visualizations on an existing Liveboard or make an arbitrary search data API request.

Whether you make the API request using XMLHttpRequest (XHR) or Fetch, ensure that the browser cookies are included when making the request.

The tspublic/v1/pinboarddata endpoint requires a URL with all parameters to be sent (there are no default values that can be left out) in the API request. The two most important parameters are the Liveboard GUID and the optional visualization GUIDs. The Liveboard GUID is visible in the URL when viewing the Liveboard in the ThoughtSpot UI.

To get the visualization GUID of a given visualization on a Liveboard, right-click the More the more options menu menu for that visualization and click Copy embed link. The link will be in this format:

{thoughtSpotServer}/#/embed/viz/{liveboardGuid}/{visualizationGuid}

The following is an example of creating the full REST API URL. Note that vizIds is an array that gets converted to a string representation before being added to the URL.

 let tsURL = "https://{}.thoughtspot.cloud";// Adjust to your instance name
 // IDs to retrieve - you can find these by clicking "Copy Embed Link" in the menu of any item on a Liveboard
 let lbId = 'c10dab93-75fd-4231-8e95-ec40a4999996'; // Change to your Liveboard ID
 let vizIds = ['59f0af45-b3a5-4bad-a6f0-4ee7003ad171']; // Put in your Visualization ID(s) from the Liveboard
 // The URI needs the vizIDs transformed into a text representation before being encoded
 const formattedVizIds = `["${vizIds.join('","')}"]`;

 // Building the URL itself. https://developers.thoughtspot.com/docs/?pageid=liveboard-data-api
 const publicApiUrl = 'callosum/v1/tspublic/v1/';
 let liveboardDataEndpoint = 'pinboarddata';
 let batchsize = '-1';
 let pagenumber = '-1';
 let offset = '-1';
 let formattype = 'COMPACT';
 let lbDataParams = '&batchsize=' + batchsize + '&pagenumber=' + pagenumber + '&offset=' + offset + '&formattype=' + formattype;
 let liveboardDataFullEndpoint = tsURL + publicApiUrl + liveboardDataEndpoint + "?id=" + lbId + "&vizid=" + formattedVizIds + lbDataParams;

Now you can make the API request. The following is an example using XMLHttpRequest, showing all necessary settings for the request to be accepted by the ThoughtSpot instance:

 var xhr = new XMLHttpRequest();
 xhr.open('POST', encodeURI(liveboardDataFullEndpoint), true);
 // .withCredentials = true is important - this is what sends the cookies from the browser session
 // without that, the APIs will reject you as not being signed in
 xhr.withCredentials = true;
 // Must set these request headers for a valid ThoughtSpot API request
 xhr.setRequestHeader("Accept", "application/json");
 xhr.setRequestHeader("X-Requested-By", "ThoughtSpot");
 // Declares a callback function that will run with the response comes back from the server
 xhr.onload = function () {
     // Response comes back as a string, you could put it straight to console
     //console.log(this.responseText);
     // Instead you can parse using JSON object, and then it will go to the console as a nice object
     let lbData = JSON.parse(this.responseText);
     console.log(lbData);
 }

A more modern form, using Fetch and Promises, would look like:

fetch(
    liveboardDataFullEndpoint, {
       method: 'GET',
       headers: {
           "Accept": "application/json",
           "X-Requested-By": "ThoughtSpot"
    },
    credentials: "include"
    })
.then(response =>  response.text())
.catch(error => {
    console.error("Unable to get the response: " + error)
});

The JSON object created by this code matches the format in the Liveboard data API.

Transform the REST API response🔗

In almost every case, you are required to transform the data format returned from ThoughtSpot to match the expected input for your charting library.

The dataclasses.js file provides classes for each ThoughtSpot data response type with standardized methods for retrieving the data in various formats.

The LiveboardData class matches the Liveboard data API. The LiveboardData.vizData[{vizId}] object brings back all of the data for the given visualization. You can retrieve all of the data for a given column using the .data[{columnName}] object of the return from .vizData:

 // Using the LiveboardData class from dataclasses.js to make operations on the data easier
 let lbDataObj = LiveboardData.createFromJSON(JSON.parse(this.responseText));
 console.log(lbDataObj);
  // Just one viz in this case, API Liveboard can return data from ALL or specified few
 let vizData = lbDataObj.vizData[vizIds[0]];
 // Array of column names
 let colNames = vizData.columnNames;
 // Column data
 let colName = 'Column A';
 let colData = vizData.data[colName];

There are additional methods such as getDataAsTable available in the dataclasses.js classes for doing other useful transformations.

Render the chart🔗

After you have transformed the data into the input format, you can render the chart into the page. Your overall steps will look like the following:

function transformVizData(responseFromApi){
   // Using the LiveboardData class from dataclasses.js to make operations on the data easier
   let lbDataObj = LiveboardData.createFromJSON(JSON.parse(responseFromApi));
   console.log(lbDataObj);
    // Just one viz in this case, API Liveboard can return data from ALL or a specified few
   let vizData = lbDataObj.vizData[vizIds[0]];
   // Array of column names
   let colNames = vizData.columnNames;
   // Column data
   let colName = 'Column A';
   let colData = vizData.data[colName];

   // Any other transformations to get data in the right format for your charting library
   // Return the data in the format necessary for the charting library to go to the rendering function
   return finalChartingData;
}

function renderCustomChart(dataInChartingLibraryFormat){
    let chartDiv = document.getElementById('chartingDivSpace');
    // Use your charting library to render the data in place on the page
}

// Using Fetch and Promises to call API, send to data transform function, then to the charting rendering function
fetch(
    liveboardDataFullEndpoint, {
       method: 'GET',
       headers: {
           "Accept": "application/json",
           "X-Requested-By": "ThoughtSpot"
    },
    credentials: "include"
    })
.then(response =>  response.text())
.then(transformVizData)
.then(renderCustomChart)
.catch(error => {
    console.error("Unable to get the response: " + error)
});


// Using XMLHttpRequest
var xhr = new XMLHttpRequest();
 xhr.open('POST', encodeURI(liveboardDataFullEndpoint), true);
 // .withCredentials = true is important - this is what sends the cookies from the browser session
 // without that, the APIs will reject you as not being signed in
 xhr.withCredentials = true;
 // Must set these request headers for a valid ThoughtSpot API request
 xhr.setRequestHeader("Accept", "application/json");
 xhr.setRequestHeader("X-Requested-By", "ThoughtSpot");
 // Declares a callback function that will run with the response comes back from the server
 xhr.onload = function () {
     // Response comes back as a string, you could put it straight to console
     console.log(this.responseText);
     // Instead you can parse using JSON object, and then it will go to the console as a nice object
     let lbData = JSON.parse(this.responseText);
     console.log(lbData);
     let lbDataObj = LiveboardData.createFromJSON(JSON.parse(this.responseText));
     // Just one viz in this case, API Liveboard can return data from ALL or specified few
     let vizData = lbDataObj.vizData[vizIds[0]];
     let finalChartingData;
     // ... do transformations to get finalChartingData
     renderCustomChart(finalChartingData);
 }
 console.log("Sending REST API request to " + liveboardDataFullEndpoint);
 xhr.send();