From 85bbdacc2804a5102ad44be7edea41ebc18a50b0 Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Tue, 2 Jun 2020 18:26:06 -0700 Subject: [PATCH] feat(query): add functions to wrap api calls with typings (#555) * feat: add function to wrap api calls * feat: add function to wrap api calls with returned type * fix: remove deprecated * fix: rename * test: add unit test * test: add unit tests --- .../packages/superset-ui-query/package.json | 8 +++ .../src/api/legacy/fetchExploreJson.ts | 28 ++++++++++ .../superset-ui-query/src/api/legacy/types.ts | 5 ++ .../src/api/v1/postChartData.ts | 24 +++++++++ .../superset-ui-query/src/api/v1/types.ts | 17 ++++++ .../packages/superset-ui-query/src/index.ts | 7 +++ .../test/api/fixtures/constants.ts | 1 + .../test/api/legacy/fetchExploreJson.test.ts | 54 +++++++++++++++++++ .../test/api/v1/postChartData.test.ts | 42 +++++++++++++++ 9 files changed, 186 insertions(+) create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/fetchExploreJson.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/types.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/postChartData.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/types.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/fixtures/constants.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/legacy/fetchExploreJson.test.ts create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/v1/postChartData.test.ts diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/package.json b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/package.json index b50e2311ac9e..713d7042c988 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/package.json +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/package.json @@ -24,5 +24,13 @@ "homepage": "https://github.com/apache-superset/superset-ui#readme", "publishConfig": { "access": "public" + }, + "devDependencies": { + "@types/fetch-mock": "^6.0.4", + "fetch-mock": "^7.2.5", + "node-fetch": "^2.2.0" + }, + "peerDependencies": { + "@superset-ui/connection": "^0.13.25" } } diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/fetchExploreJson.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/fetchExploreJson.ts new file mode 100644 index 000000000000..16278b2b1f56 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/fetchExploreJson.ts @@ -0,0 +1,28 @@ +import { SupersetClientInterface, SupersetClient, RequestConfig } from '@superset-ui/connection'; +import { QueryFormData } from '../../types/QueryFormData'; +import { LegacyChartDataResponse } from './types'; + +export interface Params { + client?: SupersetClientInterface; + method?: 'GET' | 'POST'; + requestConfig?: Partial; + url?: string; + formData: QueryFormData; +} + +export default function fetchExploreJson({ + client = SupersetClient, + method = 'POST', + requestConfig, + url = '/superset/explore_json/', + formData, +}: Params) { + const fetchFunc = method === 'GET' ? client.get : client.post; + + return fetchFunc({ + ...requestConfig, + // TODO: Have to transform formData as query string for GET + url, + postPayload: { form_data: formData }, + } as RequestConfig).then(({ json }) => json as LegacyChartDataResponse); +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/types.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/types.ts new file mode 100644 index 000000000000..863e6f4b73d7 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/legacy/types.ts @@ -0,0 +1,5 @@ +import { V1ChartDataResponseResult } from '../v1/types'; + +export interface LegacyChartDataResponse extends Omit { + data: Record[] | Record; +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/postChartData.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/postChartData.ts new file mode 100644 index 000000000000..0b55989f7bb4 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/postChartData.ts @@ -0,0 +1,24 @@ +import { SupersetClientInterface, SupersetClient, RequestConfig } from '@superset-ui/connection'; +import { QueryContext } from '../../types/Query'; +import { V1ChartDataResponse } from './types'; + +export interface Params { + client?: SupersetClientInterface; + requestConfig?: Partial; + queryContext: QueryContext; +} + +export default function postChartData({ + client = SupersetClient, + requestConfig, + queryContext, +}: Params) { + return client + .post({ + ...requestConfig, + endpoint: '/api/v1/chart/data', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(queryContext), + } as RequestConfig) + .then(({ json }) => json as V1ChartDataResponse); +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/types.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/types.ts new file mode 100644 index 000000000000..ab802fa5fc8e --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/api/v1/types.ts @@ -0,0 +1,17 @@ +/* eslint-disable camelcase */ +export interface V1ChartDataResponseResult { + cache_key: string | null; + cache_timeout: number | null; + cache_dttm: string | null; + data: Record[]; + error: string | null; + is_cached: boolean; + query: string; + rowcount: number; + stacktrace: string | null; + status: 'stopped' | 'failed' | 'pending' | 'running' | 'scheduled' | 'success' | 'timed_out'; +} + +export interface V1ChartDataResponse { + result: V1ChartDataResponseResult[]; +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/index.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/index.ts index 9357f1dc1dde..44b5ac9c51eb 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/index.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/src/index.ts @@ -9,3 +9,10 @@ export * from './types/Column'; export * from './types/Datasource'; export * from './types/Metric'; export * from './types/Query'; + +// API Calls +export { default as fetchExploreJson } from './api/legacy/fetchExploreJson'; +export { default as postChartData } from './api/v1/postChartData'; + +export * from './api/legacy/types'; +export * from './api/v1/types'; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/fixtures/constants.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/fixtures/constants.ts new file mode 100644 index 000000000000..4457bc011519 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/fixtures/constants.ts @@ -0,0 +1 @@ +export const LOGIN_GLOB = 'glob:*superset/csrf_token/*'; // eslint-disable-line import/prefer-default-export diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/legacy/fetchExploreJson.test.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/legacy/fetchExploreJson.test.ts new file mode 100644 index 000000000000..e7b30bb43449 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/legacy/fetchExploreJson.test.ts @@ -0,0 +1,54 @@ +import fetchMock from 'fetch-mock'; +import { SupersetClient } from '@superset-ui/connection'; +import { LOGIN_GLOB } from '../fixtures/constants'; +import { fetchExploreJson } from '../../../src'; + +describe('fetchExploreJson()', () => { + beforeAll(() => { + fetchMock.get(LOGIN_GLOB, { csrf_token: '1234' }); + SupersetClient.reset(); + SupersetClient.configure().init(); + }); + + afterEach(fetchMock.restore); + + it('returns a promise of LegacyChartDataResponse', () => { + fetchMock.post('glob:*/superset/explore_json/', { + field1: 'abc', + field2: 'def', + }); + + return expect( + fetchExploreJson({ + formData: { + granularity: 'minute', + viz_type: 'word_cloud', + datasource: '1__table', + }, + }), + ).resolves.toEqual({ + field1: 'abc', + field2: 'def', + }); + }); + it('uses GET when specified', () => { + fetchMock.get('glob:*/superset/explore_json/', { + field1: 'abc', + field2: 'def', + }); + + return expect( + fetchExploreJson({ + method: 'GET', + formData: { + granularity: 'minute', + viz_type: 'word_cloud', + datasource: '1__table', + }, + }), + ).resolves.toEqual({ + field1: 'abc', + field2: 'def', + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/v1/postChartData.test.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/v1/postChartData.test.ts new file mode 100644 index 000000000000..e10246eb5260 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-query/test/api/v1/postChartData.test.ts @@ -0,0 +1,42 @@ +import fetchMock from 'fetch-mock'; +import { SupersetClient } from '@superset-ui/connection'; +import { LOGIN_GLOB } from '../fixtures/constants'; +import { postChartData, buildQueryContext } from '../../../src'; + +describe('postChartData()', () => { + beforeAll(() => { + fetchMock.get(LOGIN_GLOB, { csrf_token: '1234' }); + SupersetClient.reset(); + SupersetClient.configure().init(); + }); + + afterEach(fetchMock.restore); + + it('returns a promise of ChartDataResponse', () => { + fetchMock.post('glob:*/api/v1/chart/data', { + result: [ + { + field1: 'abc', + field2: 'def', + }, + ], + }); + + return expect( + postChartData({ + queryContext: buildQueryContext({ + granularity: 'minute', + viz_type: 'word_cloud', + datasource: '1__table', + }), + }), + ).resolves.toEqual({ + result: [ + { + field1: 'abc', + field2: 'def', + }, + ], + }); + }); +});