Core utilities and components for Apache Superset's frontend UI framework providing data visualization, formatting, and chart composition capabilities
—
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.
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.
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;
}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;
}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;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]
};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>;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>;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'
}
});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);
}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'
});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();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'
});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: {}
});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`
});
};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();
}
};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'
});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);Install with Tessl CLI
npx tessl i tessl/npm-superset-ui--core@0.18.1