CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-superset-ui--core

Core utilities and components for Apache Superset's frontend UI framework providing data visualization, formatting, and chart composition capabilities

Pending
Overview
Eval results
Files

data-connection.mddocs/

Data Connection

This module provides HTTP client functionality and API utilities for communicating with Superset backend services. It includes a comprehensive HTTP client with authentication, error handling, retry logic, and support for both singleton and instance-based usage patterns.

Overview

The data connection module is built around three core components: the SupersetClient singleton for global API communication, the SupersetClientClass for instance-based usage, and the callApi function for direct HTTP requests. It supports CSRF token management, guest authentication, automatic retries, and comprehensive error handling.

SupersetClient (Singleton)

SupersetClient Interface { .api }

The main singleton interface for making API calls throughout your application:

import { SupersetClient } from '@superset-ui/core';

interface SupersetClientInterface {
  // Configuration
  configure(config: ClientConfig): SupersetClientInterface;
  reset(): void;
  
  // HTTP Methods
  get(request: RequestConfig): Promise<Response>;
  post(request: RequestConfig): Promise<Response>;
  put(request: RequestConfig): Promise<Response>;
  delete(request: RequestConfig): Promise<Response>;
  request(request: RequestConfig): Promise<Response>;
  
  // Authentication
  init(force?: boolean): Promise<void>;
  isAuthenticated(): boolean;
  reAuthenticate(): Promise<void>;
}

// Configuration interface
interface ClientConfig {
  baseUrl?: string;
  host?: string;
  protocol?: 'http:' | 'https:';
  headers?: Headers;
  fetchRetryOptions?: FetchRetryOptions;
  mode?: RequestMode;
  timeout?: number;
  credentials?: RequestCredentials;
  csrfToken?: string;
  guestToken?: string;
  guestTokenHeaderName?: string;
  handleUnauthorized?: () => void;
}

SupersetClientClass { .api }

Instance-based HTTP client class for custom configurations:

import { SupersetClientClass } from '@superset-ui/core';

class SupersetClientClass {
  // Configuration properties
  readonly credentials: RequestCredentials;
  readonly baseUrl: string;
  readonly protocol: Protocol;
  readonly host: Host;
  readonly headers: Headers;
  readonly mode: RequestMode;
  readonly timeout: ClientTimeout;
  readonly fetchRetryOptions: FetchRetryOptions;
  readonly guestTokenHeaderName: string;
  readonly handleUnauthorized: () => void;
  
  // Authentication state
  csrfToken?: string;
  guestToken?: string;
  
  constructor(config: ClientConfig);
  
  // HTTP Methods
  get(request: RequestConfig): Promise<Response>;
  post(request: RequestConfig): Promise<Response>;
  put(request: RequestConfig): Promise<Response>;
  delete(request: RequestConfig): Promise<Response>;
  request(request: RequestConfig): Promise<Response>;
  
  // Authentication management
  init(force?: boolean): Promise<void>;
  isAuthenticated(): boolean;
  reAuthenticate(): Promise<void>;
  ensureAuth(): Promise<void>;
  
  // Internal utilities
  getUrl(endpoint: string): string;
  normalizeRequestConfig(request: RequestConfig): RequestConfig;
}

Request Configuration

RequestConfig Interface { .api }

Configuration options for individual API requests:

interface RequestConfig extends RequestBase {
  endpoint: string;
  url?: string;
  host?: string;
  timeout?: ClientTimeout;
  jsonPayload?: Payload;
  postPayload?: Payload;
  parseMethod?: ParseMethod;
  stringify?: boolean;
  fetchRetryOptions?: FetchRetryOptions;
}

interface RequestBase {
  body?: RequestInit['body'];
  credentials?: RequestCredentials;
  headers?: Headers;
  method?: RequestInit['method'];
  mode?: RequestInit['mode'];
  redirect?: RequestInit['redirect'];
  signal?: RequestInit['signal'];
}

// Supported parse methods
type ParseMethod = 'json' | 'text' | 'raw' | null | undefined;

Retry Configuration { .api }

Configuration for automatic request retries:

interface FetchRetryOptions {
  retries?: number;
  retryDelay?: number | ((attempt: number, error: Error, response: Response) => number);
  retryOn?: number[] | ((attempt: number, error: Error, response: Response) => boolean);
}

// Default retry configuration
const DEFAULT_FETCH_RETRY_OPTIONS: FetchRetryOptions = {
  retries: 3,
  retryDelay: 1000,
  retryOn: [408, 429, 500, 502, 503, 504]
};

Core API Function

callApi Function { .api }

Direct API calling utility with timeout support:

import { callApi } from '@superset-ui/core';

function callApi(config: {
  url: string;
  method?: RequestInit['method'];
  body?: RequestInit['body'];
  headers?: HeadersInit;
  credentials?: RequestCredentials;
  mode?: RequestInit['mode'];
  timeout?: number;
  signal?: AbortSignal;
  parseMethod?: ParseMethod;
}): Promise<Response>;

Type Definitions

Core Types { .api }

Essential type definitions for the connection module:

// Basic types
type Host = string;
type Endpoint = string;
type Headers = { [key: string]: string };
type Protocol = 'http:' | 'https:';
type ClientTimeout = number | undefined;

// JSON types
type JsonPrimitive = string | number | boolean | null;
type JsonValue = JsonPrimitive | JsonObject | JsonArray;
type JsonArray = JsonValue[];
type JsonObject = { [member: string]: any };

// Strict JSON types for type safety
type StrictJsonValue = JsonPrimitive | StrictJsonObject | StrictJsonArray;
type StrictJsonArray = StrictJsonValue[];
type StrictJsonObject = { [member: string]: StrictJsonValue };

// Request payload types
type Payload = JsonObject | string | null;
type Body = RequestInit['body'];

// Authentication types
type CsrfToken = string;
type CsrfPromise = Promise<CsrfToken>;

Usage Examples

Basic Configuration and Usage

import { SupersetClient } from '@superset-ui/core';

// Configure the global client
SupersetClient.configure({
  host: 'http://localhost:8088',
  headers: {
    'Content-Type': 'application/json'
  },
  fetchRetryOptions: {
    retries: 3,
    retryDelay: 1000
  }
});

// Initialize authentication
await SupersetClient.init();

// Make API calls
const dashboards = await SupersetClient.get({
  endpoint: '/api/v1/dashboard/'
});

const newChart = await SupersetClient.post({
  endpoint: '/api/v1/chart/',
  jsonPayload: {
    slice_name: 'My Chart',
    viz_type: 'table'
  }
});

Error Handling and Retries

import { SupersetClient } from '@superset-ui/core';

// Configure with custom retry logic
SupersetClient.configure({
  host: 'http://localhost:8088',
  fetchRetryOptions: {
    retries: 5,
    retryDelay: (attempt, error, response) => {
      // Exponential backoff
      return Math.pow(2, attempt) * 1000;
    },
    retryOn: (attempt, error, response) => {
      // Retry on network errors or 5xx status codes
      return !response || response.status >= 500;
    }
  },
  handleUnauthorized: () => {
    // Custom unauthorized handler
    window.location.href = '/login';
  }
});

// Make request with error handling
try {
  const response = await SupersetClient.get({
    endpoint: '/api/v1/dataset/',
    timeout: 30000 // 30 second timeout
  });
  
  const data = await response.json();
  console.log('Datasets:', data.result);
} catch (error) {
  console.error('Failed to fetch datasets:', error);
}

Custom Client Instance

import { SupersetClientClass } from '@superset-ui/core';

// Create custom client for specific API
const analyticsClient = new SupersetClientClass({
  baseUrl: 'https://analytics-api.example.com',
  headers: {
    'Authorization': 'Bearer ' + apiToken,
    'X-API-Version': '2.0'
  },
  timeout: 60000,
  fetchRetryOptions: {
    retries: 2,
    retryDelay: 2000
  }
});

// Use custom client
const metrics = await analyticsClient.get({
  endpoint: '/metrics',
  parseMethod: 'json'
});

Direct API Calls

import { callApi } from '@superset-ui/core';

// Direct API call without client configuration
const response = await callApi({
  url: 'http://localhost:8088/api/v1/chart/1',
  method: 'GET',
  headers: {
    'Authorization': 'Bearer token123'
  },
  timeout: 10000,
  parseMethod: 'json'
});

const chartData = await response.json();

Authentication Management

import { SupersetClient } from '@superset-ui/core';

// Check authentication status
if (!SupersetClient.isAuthenticated()) {
  // Force re-authentication
  await SupersetClient.reAuthenticate();
}

// Manual CSRF token handling
SupersetClient.configure({
  csrfToken: 'manual-csrf-token',
  guestToken: 'guest-session-token',
  guestTokenHeaderName: 'X-GuestToken'
});

File Upload with FormData

import { SupersetClient } from '@superset-ui/core';

// Upload CSV file
const formData = new FormData();
formData.append('csv_file', file);
formData.append('table_name', 'my_dataset');

const uploadResponse = await SupersetClient.post({
  endpoint: '/api/v1/dataset/upload',
  body: formData,
  // Don't set Content-Type header for FormData - let browser set it
  headers: {}
});

Query Execution

import { SupersetClient } from '@superset-ui/core';

// Execute SQL query
const queryResult = await SupersetClient.post({
  endpoint: '/api/v1/sqllab/',
  jsonPayload: {
    sql: 'SELECT * FROM my_table LIMIT 100',
    database_id: 1,
    schema: 'public',
    runAsync: false
  }
});

// Long-running query with polling
const asyncQuery = await SupersetClient.post({
  endpoint: '/api/v1/sqllab/',
  jsonPayload: {
    sql: 'SELECT COUNT(*) FROM large_table',
    database_id: 1,
    runAsync: true
  }
});

// Poll for results
const pollResults = async (queryId: string) => {
  let status = 'running';
  while (status === 'running') {
    const statusResponse = await SupersetClient.get({
      endpoint: `/api/v1/sqllab/${queryId}/status`
    });
    
    const statusData = await statusResponse.json();
    status = statusData.status;
    
    if (status === 'running') {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
  
  return SupersetClient.get({
    endpoint: `/api/v1/sqllab/${queryId}/results`
  });
};

Advanced Usage

Custom Response Processing

import { SupersetClient } from '@superset-ui/core';

// Custom response processor
const processApiResponse = async (endpoint: string) => {
  const response = await SupersetClient.get({
    endpoint,
    parseMethod: 'raw' // Get raw Response object
  });
  
  // Custom processing based on content type
  const contentType = response.headers.get('content-type');
  
  if (contentType?.includes('application/json')) {
    const json = await response.json();
    return json.result || json;
  } else if (contentType?.includes('text/csv')) {
    const text = await response.text();
    return text.split('\n').map(row => row.split(','));
  } else {
    return response.blob();
  }
};

Request Interceptors Pattern

import { SupersetClientClass } from '@superset-ui/core';

class InterceptedClient extends SupersetClientClass {
  async request(config: RequestConfig): Promise<Response> {
    // Pre-request processing
    console.log(`Making request to: ${config.endpoint}`);
    
    // Add timing
    const startTime = Date.now();
    
    try {
      const response = await super.request(config);
      
      // Post-request processing
      const duration = Date.now() - startTime;
      console.log(`Request completed in ${duration}ms`);
      
      return response;
    } catch (error) {
      console.error(`Request failed after ${Date.now() - startTime}ms:`, error);
      throw error;
    }
  }
}

const client = new InterceptedClient({
  host: 'http://localhost:8088'
});

Bulk Operations

import { SupersetClient } from '@superset-ui/core';

// Batch API calls with concurrency control
const batchApiCalls = async <T>(
  requests: RequestConfig[],
  concurrency: number = 5
): Promise<T[]> => {
  const results: T[] = [];
  
  for (let i = 0; i < requests.length; i += concurrency) {
    const batch = requests.slice(i, i + concurrency);
    const batchResults = await Promise.all(
      batch.map(async (request) => {
        const response = await SupersetClient.request(request);
        return response.json();
      })
    );
    results.push(...batchResults);
  }
  
  return results;
};

// Usage
const chartRequests = chartIds.map(id => ({
  endpoint: `/api/v1/chart/${id}`
}));

const charts = await batchApiCalls(chartRequests, 3);

Related Documentation

  • Core Models & Utilities - Registry system and utilities
  • Dashboard Components - Dashboard API integration

Install with Tessl CLI

npx tessl i tessl/npm-superset-ui--core

docs

core-models.md

dashboard.md

data-connection.md

data-formatting.md

index.md

plugin-system.md

translation.md

ui-styling.md

validation-math.md

tile.json