| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| import rison from 'rison'; |
| import { |
| SupersetClient, |
| Payload as SupersetPayload, |
| JsonObject, |
| JsonValue, |
| ParseMethod, |
| Endpoint, |
| Method, |
| RequestBase, |
| } from '../../../connection'; |
| import handleError, { ErrorInput } from './handleError'; |
| import { SupersetApiRequestOptions, SupersetApiErrorPayload, ParsedResponseType } from './types'; |
| |
| const validRequestTypes = new Set(['form', 'json', 'search', 'rison']); |
| |
| interface SupersetApiFactoryOptions extends Omit<RequestBase, 'url'> { |
| /** |
| * API endpoint, must be relative. |
| */ |
| endpoint: Endpoint; |
| /** |
| * Request method: 'GET' | 'POST' | 'DELETE' | 'PUT' | ... |
| */ |
| method: Method; |
| /** |
| * How to send the payload: |
| * - form: set request.body as FormData |
| * - json: as JSON string with request Content-Type header set to application/json |
| * - search: add to search params |
| */ |
| requestType?: 'form' | 'json' | 'search' | 'rison'; |
| } |
| |
| function isPayloadless(method?: Method) { |
| return !method || method === 'GET' || method === 'DELETE' || method === 'HEAD'; |
| } |
| |
| /** |
| * Generate an API caller with predefined configs/typing and consistent |
| * return values. |
| */ |
| export default function makeApi< |
| Payload = SupersetPayload, |
| Result = JsonObject, |
| T extends ParseMethod = ParseMethod |
| >({ |
| endpoint, |
| method, |
| requestType: requestType_, |
| responseType, |
| processResponse, |
| ...requestOptions |
| }: SupersetApiFactoryOptions & { |
| /** |
| * How to parse response, choose from: 'json' | 'text' | 'raw'. |
| */ |
| responseType?: T; |
| /** |
| * Further process parsed response |
| */ |
| processResponse?(result: ParsedResponseType<T>): Result; |
| }) { |
| // use `search` payload (searchParams) when it's a GET request |
| const requestType = requestType_ || (isPayloadless(method) ? 'search' : 'json'); |
| if (!validRequestTypes.has(requestType)) { |
| throw new Error( |
| `Invalid request payload type, choose from: ${[...validRequestTypes].join(' | ')}`, |
| ); |
| } |
| |
| async function request( |
| payload: Payload, |
| { client = SupersetClient }: SupersetApiRequestOptions = { client: SupersetClient }, |
| ): Promise<Result> { |
| try { |
| const requestConfig = { |
| ...requestOptions, |
| method, |
| endpoint, |
| }; |
| if (requestType === 'search') { |
| requestConfig.searchParams = payload; |
| } else if (requestType === 'rison') { |
| requestConfig.endpoint = `${endpoint}?q=${rison.encode(payload)}`; |
| } else if (requestType === 'form') { |
| requestConfig.postPayload = payload; |
| } else { |
| requestConfig.jsonPayload = payload; |
| } |
| |
| let result: JsonValue | Response; |
| const response = await client.request({ ...requestConfig, parseMethod: 'raw' }); |
| |
| if (responseType === 'text') { |
| result = await response.text(); |
| } else if (responseType === 'raw' || responseType === null) { |
| result = response; |
| } else { |
| result = await response.json(); |
| // if response json has an "error" field |
| if (result && typeof result === 'object' && 'error' in result) { |
| return handleError(result as SupersetApiErrorPayload); |
| } |
| } |
| const typedResult = result as ParsedResponseType<T>; |
| return (processResponse ? processResponse(typedResult) : typedResult) as Result; |
| } catch (error) { |
| return handleError(error as ErrorInput); |
| } |
| } |
| |
| request.method = method; |
| request.endpoint = endpoint; |
| request.requestType = requestType; |
| |
| return request; |
| } |