0
# Data Connection
1
2
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.
3
4
## Overview
5
6
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.
7
8
## SupersetClient (Singleton)
9
10
### SupersetClient Interface { .api }
11
12
The main singleton interface for making API calls throughout your application:
13
14
```typescript
15
import { SupersetClient } from '@superset-ui/core';
16
17
interface SupersetClientInterface {
18
// Configuration
19
configure(config: ClientConfig): SupersetClientInterface;
20
reset(): void;
21
22
// HTTP Methods
23
get(request: RequestConfig): Promise<Response>;
24
post(request: RequestConfig): Promise<Response>;
25
put(request: RequestConfig): Promise<Response>;
26
delete(request: RequestConfig): Promise<Response>;
27
request(request: RequestConfig): Promise<Response>;
28
29
// Authentication
30
init(force?: boolean): Promise<void>;
31
isAuthenticated(): boolean;
32
reAuthenticate(): Promise<void>;
33
}
34
35
// Configuration interface
36
interface ClientConfig {
37
baseUrl?: string;
38
host?: string;
39
protocol?: 'http:' | 'https:';
40
headers?: Headers;
41
fetchRetryOptions?: FetchRetryOptions;
42
mode?: RequestMode;
43
timeout?: number;
44
credentials?: RequestCredentials;
45
csrfToken?: string;
46
guestToken?: string;
47
guestTokenHeaderName?: string;
48
handleUnauthorized?: () => void;
49
}
50
```
51
52
### SupersetClientClass { .api }
53
54
Instance-based HTTP client class for custom configurations:
55
56
```typescript
57
import { SupersetClientClass } from '@superset-ui/core';
58
59
class SupersetClientClass {
60
// Configuration properties
61
readonly credentials: RequestCredentials;
62
readonly baseUrl: string;
63
readonly protocol: Protocol;
64
readonly host: Host;
65
readonly headers: Headers;
66
readonly mode: RequestMode;
67
readonly timeout: ClientTimeout;
68
readonly fetchRetryOptions: FetchRetryOptions;
69
readonly guestTokenHeaderName: string;
70
readonly handleUnauthorized: () => void;
71
72
// Authentication state
73
csrfToken?: string;
74
guestToken?: string;
75
76
constructor(config: ClientConfig);
77
78
// HTTP Methods
79
get(request: RequestConfig): Promise<Response>;
80
post(request: RequestConfig): Promise<Response>;
81
put(request: RequestConfig): Promise<Response>;
82
delete(request: RequestConfig): Promise<Response>;
83
request(request: RequestConfig): Promise<Response>;
84
85
// Authentication management
86
init(force?: boolean): Promise<void>;
87
isAuthenticated(): boolean;
88
reAuthenticate(): Promise<void>;
89
ensureAuth(): Promise<void>;
90
91
// Internal utilities
92
getUrl(endpoint: string): string;
93
normalizeRequestConfig(request: RequestConfig): RequestConfig;
94
}
95
```
96
97
## Request Configuration
98
99
### RequestConfig Interface { .api }
100
101
Configuration options for individual API requests:
102
103
```typescript
104
interface RequestConfig extends RequestBase {
105
endpoint: string;
106
url?: string;
107
host?: string;
108
timeout?: ClientTimeout;
109
jsonPayload?: Payload;
110
postPayload?: Payload;
111
parseMethod?: ParseMethod;
112
stringify?: boolean;
113
fetchRetryOptions?: FetchRetryOptions;
114
}
115
116
interface RequestBase {
117
body?: RequestInit['body'];
118
credentials?: RequestCredentials;
119
headers?: Headers;
120
method?: RequestInit['method'];
121
mode?: RequestInit['mode'];
122
redirect?: RequestInit['redirect'];
123
signal?: RequestInit['signal'];
124
}
125
126
// Supported parse methods
127
type ParseMethod = 'json' | 'text' | 'raw' | null | undefined;
128
```
129
130
### Retry Configuration { .api }
131
132
Configuration for automatic request retries:
133
134
```typescript
135
interface FetchRetryOptions {
136
retries?: number;
137
retryDelay?: number | ((attempt: number, error: Error, response: Response) => number);
138
retryOn?: number[] | ((attempt: number, error: Error, response: Response) => boolean);
139
}
140
141
// Default retry configuration
142
const DEFAULT_FETCH_RETRY_OPTIONS: FetchRetryOptions = {
143
retries: 3,
144
retryDelay: 1000,
145
retryOn: [408, 429, 500, 502, 503, 504]
146
};
147
```
148
149
## Core API Function
150
151
### callApi Function { .api }
152
153
Direct API calling utility with timeout support:
154
155
```typescript
156
import { callApi } from '@superset-ui/core';
157
158
function callApi(config: {
159
url: string;
160
method?: RequestInit['method'];
161
body?: RequestInit['body'];
162
headers?: HeadersInit;
163
credentials?: RequestCredentials;
164
mode?: RequestInit['mode'];
165
timeout?: number;
166
signal?: AbortSignal;
167
parseMethod?: ParseMethod;
168
}): Promise<Response>;
169
```
170
171
## Type Definitions
172
173
### Core Types { .api }
174
175
Essential type definitions for the connection module:
176
177
```typescript
178
// Basic types
179
type Host = string;
180
type Endpoint = string;
181
type Headers = { [key: string]: string };
182
type Protocol = 'http:' | 'https:';
183
type ClientTimeout = number | undefined;
184
185
// JSON types
186
type JsonPrimitive = string | number | boolean | null;
187
type JsonValue = JsonPrimitive | JsonObject | JsonArray;
188
type JsonArray = JsonValue[];
189
type JsonObject = { [member: string]: any };
190
191
// Strict JSON types for type safety
192
type StrictJsonValue = JsonPrimitive | StrictJsonObject | StrictJsonArray;
193
type StrictJsonArray = StrictJsonValue[];
194
type StrictJsonObject = { [member: string]: StrictJsonValue };
195
196
// Request payload types
197
type Payload = JsonObject | string | null;
198
type Body = RequestInit['body'];
199
200
// Authentication types
201
type CsrfToken = string;
202
type CsrfPromise = Promise<CsrfToken>;
203
```
204
205
## Usage Examples
206
207
### Basic Configuration and Usage
208
209
```typescript
210
import { SupersetClient } from '@superset-ui/core';
211
212
// Configure the global client
213
SupersetClient.configure({
214
host: 'http://localhost:8088',
215
headers: {
216
'Content-Type': 'application/json'
217
},
218
fetchRetryOptions: {
219
retries: 3,
220
retryDelay: 1000
221
}
222
});
223
224
// Initialize authentication
225
await SupersetClient.init();
226
227
// Make API calls
228
const dashboards = await SupersetClient.get({
229
endpoint: '/api/v1/dashboard/'
230
});
231
232
const newChart = await SupersetClient.post({
233
endpoint: '/api/v1/chart/',
234
jsonPayload: {
235
slice_name: 'My Chart',
236
viz_type: 'table'
237
}
238
});
239
```
240
241
### Error Handling and Retries
242
243
```typescript
244
import { SupersetClient } from '@superset-ui/core';
245
246
// Configure with custom retry logic
247
SupersetClient.configure({
248
host: 'http://localhost:8088',
249
fetchRetryOptions: {
250
retries: 5,
251
retryDelay: (attempt, error, response) => {
252
// Exponential backoff
253
return Math.pow(2, attempt) * 1000;
254
},
255
retryOn: (attempt, error, response) => {
256
// Retry on network errors or 5xx status codes
257
return !response || response.status >= 500;
258
}
259
},
260
handleUnauthorized: () => {
261
// Custom unauthorized handler
262
window.location.href = '/login';
263
}
264
});
265
266
// Make request with error handling
267
try {
268
const response = await SupersetClient.get({
269
endpoint: '/api/v1/dataset/',
270
timeout: 30000 // 30 second timeout
271
});
272
273
const data = await response.json();
274
console.log('Datasets:', data.result);
275
} catch (error) {
276
console.error('Failed to fetch datasets:', error);
277
}
278
```
279
280
### Custom Client Instance
281
282
```typescript
283
import { SupersetClientClass } from '@superset-ui/core';
284
285
// Create custom client for specific API
286
const analyticsClient = new SupersetClientClass({
287
baseUrl: 'https://analytics-api.example.com',
288
headers: {
289
'Authorization': 'Bearer ' + apiToken,
290
'X-API-Version': '2.0'
291
},
292
timeout: 60000,
293
fetchRetryOptions: {
294
retries: 2,
295
retryDelay: 2000
296
}
297
});
298
299
// Use custom client
300
const metrics = await analyticsClient.get({
301
endpoint: '/metrics',
302
parseMethod: 'json'
303
});
304
```
305
306
### Direct API Calls
307
308
```typescript
309
import { callApi } from '@superset-ui/core';
310
311
// Direct API call without client configuration
312
const response = await callApi({
313
url: 'http://localhost:8088/api/v1/chart/1',
314
method: 'GET',
315
headers: {
316
'Authorization': 'Bearer token123'
317
},
318
timeout: 10000,
319
parseMethod: 'json'
320
});
321
322
const chartData = await response.json();
323
```
324
325
### Authentication Management
326
327
```typescript
328
import { SupersetClient } from '@superset-ui/core';
329
330
// Check authentication status
331
if (!SupersetClient.isAuthenticated()) {
332
// Force re-authentication
333
await SupersetClient.reAuthenticate();
334
}
335
336
// Manual CSRF token handling
337
SupersetClient.configure({
338
csrfToken: 'manual-csrf-token',
339
guestToken: 'guest-session-token',
340
guestTokenHeaderName: 'X-GuestToken'
341
});
342
```
343
344
### File Upload with FormData
345
346
```typescript
347
import { SupersetClient } from '@superset-ui/core';
348
349
// Upload CSV file
350
const formData = new FormData();
351
formData.append('csv_file', file);
352
formData.append('table_name', 'my_dataset');
353
354
const uploadResponse = await SupersetClient.post({
355
endpoint: '/api/v1/dataset/upload',
356
body: formData,
357
// Don't set Content-Type header for FormData - let browser set it
358
headers: {}
359
});
360
```
361
362
### Query Execution
363
364
```typescript
365
import { SupersetClient } from '@superset-ui/core';
366
367
// Execute SQL query
368
const queryResult = await SupersetClient.post({
369
endpoint: '/api/v1/sqllab/',
370
jsonPayload: {
371
sql: 'SELECT * FROM my_table LIMIT 100',
372
database_id: 1,
373
schema: 'public',
374
runAsync: false
375
}
376
});
377
378
// Long-running query with polling
379
const asyncQuery = await SupersetClient.post({
380
endpoint: '/api/v1/sqllab/',
381
jsonPayload: {
382
sql: 'SELECT COUNT(*) FROM large_table',
383
database_id: 1,
384
runAsync: true
385
}
386
});
387
388
// Poll for results
389
const pollResults = async (queryId: string) => {
390
let status = 'running';
391
while (status === 'running') {
392
const statusResponse = await SupersetClient.get({
393
endpoint: `/api/v1/sqllab/${queryId}/status`
394
});
395
396
const statusData = await statusResponse.json();
397
status = statusData.status;
398
399
if (status === 'running') {
400
await new Promise(resolve => setTimeout(resolve, 1000));
401
}
402
}
403
404
return SupersetClient.get({
405
endpoint: `/api/v1/sqllab/${queryId}/results`
406
});
407
};
408
```
409
410
## Advanced Usage
411
412
### Custom Response Processing
413
414
```typescript
415
import { SupersetClient } from '@superset-ui/core';
416
417
// Custom response processor
418
const processApiResponse = async (endpoint: string) => {
419
const response = await SupersetClient.get({
420
endpoint,
421
parseMethod: 'raw' // Get raw Response object
422
});
423
424
// Custom processing based on content type
425
const contentType = response.headers.get('content-type');
426
427
if (contentType?.includes('application/json')) {
428
const json = await response.json();
429
return json.result || json;
430
} else if (contentType?.includes('text/csv')) {
431
const text = await response.text();
432
return text.split('\n').map(row => row.split(','));
433
} else {
434
return response.blob();
435
}
436
};
437
```
438
439
### Request Interceptors Pattern
440
441
```typescript
442
import { SupersetClientClass } from '@superset-ui/core';
443
444
class InterceptedClient extends SupersetClientClass {
445
async request(config: RequestConfig): Promise<Response> {
446
// Pre-request processing
447
console.log(`Making request to: ${config.endpoint}`);
448
449
// Add timing
450
const startTime = Date.now();
451
452
try {
453
const response = await super.request(config);
454
455
// Post-request processing
456
const duration = Date.now() - startTime;
457
console.log(`Request completed in ${duration}ms`);
458
459
return response;
460
} catch (error) {
461
console.error(`Request failed after ${Date.now() - startTime}ms:`, error);
462
throw error;
463
}
464
}
465
}
466
467
const client = new InterceptedClient({
468
host: 'http://localhost:8088'
469
});
470
```
471
472
### Bulk Operations
473
474
```typescript
475
import { SupersetClient } from '@superset-ui/core';
476
477
// Batch API calls with concurrency control
478
const batchApiCalls = async <T>(
479
requests: RequestConfig[],
480
concurrency: number = 5
481
): Promise<T[]> => {
482
const results: T[] = [];
483
484
for (let i = 0; i < requests.length; i += concurrency) {
485
const batch = requests.slice(i, i + concurrency);
486
const batchResults = await Promise.all(
487
batch.map(async (request) => {
488
const response = await SupersetClient.request(request);
489
return response.json();
490
})
491
);
492
results.push(...batchResults);
493
}
494
495
return results;
496
};
497
498
// Usage
499
const chartRequests = chartIds.map(id => ({
500
endpoint: `/api/v1/chart/${id}`
501
}));
502
503
const charts = await batchApiCalls(chartRequests, 3);
504
```
505
506
## Related Documentation
507
508
- [Query System](./query.md) - Query building and processing
509
- [Core Models & Utilities](./core-models.md) - Registry system and utilities
510
- [Dashboard Components](./dashboard.md) - Dashboard API integration