diff --git a/docs/development/core/public/kibana-plugin-public.httpbody.md b/docs/development/core/public/kibana-plugin-public.httpbody.md deleted file mode 100644 index ab31f28b8dc38..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpbody.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpBody](./kibana-plugin-public.httpbody.md) - -## HttpBody type - - -Signature: - -```typescript -export declare type HttpBody = BodyInit | null | any; -``` diff --git a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md index aa669df796a09..5b1ee898a444d 100644 --- a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md +++ b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface HttpErrorResponse extends HttpResponse +export interface HttpErrorResponse extends IHttpResponse ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md new file mode 100644 index 0000000000000..250cf83309b3c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) > [asResponse](./kibana-plugin-public.httpfetchoptions.asresponse.md) + +## HttpFetchOptions.asResponse property + +When `true` the return type of [HttpHandler](./kibana-plugin-public.httphandler.md) will be an [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) with detailed request and response information. When `false`, the return type will just be the parsed response body. Defaults to `false`. + +Signature: + +```typescript +asResponse?: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md index eca29b37425e9..6a0c4a8a7f137 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md @@ -16,6 +16,7 @@ export interface HttpFetchOptions extends HttpRequestInit | Property | Type | Description | | --- | --- | --- | +| [asResponse](./kibana-plugin-public.httpfetchoptions.asresponse.md) | boolean | When true the return type of [HttpHandler](./kibana-plugin-public.httphandler.md) will be an [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) with detailed request and response information. When false, the return type will just be the parsed response body. Defaults to false. | | [headers](./kibana-plugin-public.httpfetchoptions.headers.md) | HttpHeadersInit | Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md). | | [prependBasePath](./kibana-plugin-public.httpfetchoptions.prependbasepath.md) | boolean | Whether or not the request should automatically prepend the basePath. Defaults to true. | | [query](./kibana-plugin-public.httpfetchoptions.query.md) | HttpFetchQuery | The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md). | diff --git a/docs/development/core/public/kibana-plugin-public.httphandler.md b/docs/development/core/public/kibana-plugin-public.httphandler.md index 80fd1ea2e5761..89458c4743cd6 100644 --- a/docs/development/core/public/kibana-plugin-public.httphandler.md +++ b/docs/development/core/public/kibana-plugin-public.httphandler.md @@ -2,12 +2,12 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpHandler](./kibana-plugin-public.httphandler.md) -## HttpHandler type +## HttpHandler interface -A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. +A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) for the response. Signature: ```typescript -export declare type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; +export interface HttpHandler ``` diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md index ca43ea31f0e2e..3a67dcbad3119 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md @@ -9,17 +9,17 @@ Define an interceptor to be executed after a response is received. Signature: ```typescript -response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; +response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| httpResponse | HttpResponse | | +| httpResponse | IHttpResponse | | | controller | IHttpInterceptController | | Returns: -`Promise | InterceptedHttpResponse | void` +`Promise | IHttpResponseInterceptorOverrides | void` diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md index b8abd50e45461..476ceba649d40 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md @@ -9,7 +9,7 @@ Define an interceptor to be executed if a response interceptor throws an error o Signature: ```typescript -responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; +responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; ``` ## Parameters @@ -21,5 +21,5 @@ responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptC Returns: -`Promise | InterceptedHttpResponse | void` +`Promise | IHttpResponseInterceptorOverrides | void` diff --git a/docs/development/core/public/kibana-plugin-public.httpresponse.md b/docs/development/core/public/kibana-plugin-public.httpresponse.md deleted file mode 100644 index e44515cc8a1e0..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpresponse.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpResponse](./kibana-plugin-public.httpresponse.md) - -## HttpResponse interface - - -Signature: - -```typescript -export interface HttpResponse extends InterceptedHttpResponse -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [request](./kibana-plugin-public.httpresponse.request.md) | Readonly<Request> | | - diff --git a/docs/development/core/public/kibana-plugin-public.httpresponse.request.md b/docs/development/core/public/kibana-plugin-public.httpresponse.request.md deleted file mode 100644 index 84ab1bc7af853..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpresponse.request.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpResponse](./kibana-plugin-public.httpresponse.md) > [request](./kibana-plugin-public.httpresponse.request.md) - -## HttpResponse.request property - -Signature: - -```typescript -request: Readonly; -``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md new file mode 100644 index 0000000000000..2f8710ccdc60e --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [body](./kibana-plugin-public.ihttpresponse.body.md) + +## IHttpResponse.body property + +Parsed body received, may be undefined if there was an error. + +Signature: + +```typescript +readonly body?: TResponseBody; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.md new file mode 100644 index 0000000000000..5ddce0ba2d0f1 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) + +## IHttpResponse interface + + +Signature: + +```typescript +export interface IHttpResponse +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [body](./kibana-plugin-public.ihttpresponse.body.md) | TResponseBody | Parsed body received, may be undefined if there was an error. | +| [request](./kibana-plugin-public.ihttpresponse.request.md) | Readonly<Request> | Raw request sent to Kibana server. | +| [response](./kibana-plugin-public.ihttpresponse.response.md) | Readonly<Response> | Raw response received, may be undefined if there was an error. | + diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md new file mode 100644 index 0000000000000..12e5405eb5ed4 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [request](./kibana-plugin-public.ihttpresponse.request.md) + +## IHttpResponse.request property + +Raw request sent to Kibana server. + +Signature: + +```typescript +readonly request: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md new file mode 100644 index 0000000000000..9d0b4b59a638d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [response](./kibana-plugin-public.ihttpresponse.response.md) + +## IHttpResponse.response property + +Raw response received, may be undefined if there was an error. + +Signature: + +```typescript +readonly response?: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md new file mode 100644 index 0000000000000..36fcfb390617c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) > [body](./kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md) + +## IHttpResponseInterceptorOverrides.body property + +Parsed body received, may be undefined if there was an error. + +Signature: + +```typescript +readonly body?: TResponseBody; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md new file mode 100644 index 0000000000000..44f067c429e98 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) + +## IHttpResponseInterceptorOverrides interface + +Properties that can be returned by HttpInterceptor.request to override the response. + +Signature: + +```typescript +export interface IHttpResponseInterceptorOverrides +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [body](./kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md) | TResponseBody | Parsed body received, may be undefined if there was an error. | +| [response](./kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md) | Readonly<Response> | Raw response received, may be undefined if there was an error. | + diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md new file mode 100644 index 0000000000000..bcba996645ba6 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) > [response](./kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md) + +## IHttpResponseInterceptorOverrides.response property + +Raw response received, may be undefined if there was an error. + +Signature: + +```typescript +readonly response?: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md deleted file mode 100644 index fc6d34c0b74f2..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) > [body](./kibana-plugin-public.interceptedhttpresponse.body.md) - -## InterceptedHttpResponse.body property - -Signature: - -```typescript -body?: HttpBody; -``` diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md deleted file mode 100644 index c4a7f4d6b2afa..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) - -## InterceptedHttpResponse interface - - -Signature: - -```typescript -export interface InterceptedHttpResponse -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [body](./kibana-plugin-public.interceptedhttpresponse.body.md) | HttpBody | | -| [response](./kibana-plugin-public.interceptedhttpresponse.response.md) | Response | | - diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md deleted file mode 100644 index dceb55113ee78..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) > [response](./kibana-plugin-public.interceptedhttpresponse.response.md) - -## InterceptedHttpResponse.response property - -Signature: - -```typescript -response?: Response; -``` diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md index f527c92d070de..22b6f7faf2daa 100644 --- a/docs/development/core/public/kibana-plugin-public.md +++ b/docs/development/core/public/kibana-plugin-public.md @@ -52,10 +52,10 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HttpErrorResponse](./kibana-plugin-public.httperrorresponse.md) | | | [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) | All options that may be used with a [HttpHandler](./kibana-plugin-public.httphandler.md). | | [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md) | | +| [HttpHandler](./kibana-plugin-public.httphandler.md) | A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) for the response. | | [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) | | | [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) | An object that may define global interceptor functions for different parts of the request and response lifecycle. See [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md). | | [HttpRequestInit](./kibana-plugin-public.httprequestinit.md) | Fetch API options available to [HttpHandler](./kibana-plugin-public.httphandler.md)s. | -| [HttpResponse](./kibana-plugin-public.httpresponse.md) | | | [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | | [I18nStart](./kibana-plugin-public.i18nstart.md) | I18nStart.Context is required by any localizable React component from @kbn/i18n and @elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. | | [IAnonymousPaths](./kibana-plugin-public.ianonymouspaths.md) | APIs for denoting paths as not requiring authentication | @@ -63,7 +63,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | An object that handles registration of context providers and configuring handlers with context. | | [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) | | | [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) | Used to halt a request Promise chain in a [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md). | -| [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) | | +| [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) | | +| [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) | Properties that can be returned by HttpInterceptor.request to override the response. | | [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) | Client-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) | | [LegacyCoreSetup](./kibana-plugin-public.legacycoresetup.md) | Setup interface exposed to the legacy platform via the ui/new_platform module. | | [LegacyCoreStart](./kibana-plugin-public.legacycorestart.md) | Start interface exposed to the legacy platform via the ui/new_platform module. | @@ -108,8 +109,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HandlerContextType](./kibana-plugin-public.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md) to represent the type of the context. | | [HandlerFunction](./kibana-plugin-public.handlerfunction.md) | A function that accepts a context object and an optional number of additional arguments. Used for the generic types in [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | | [HandlerParameters](./kibana-plugin-public.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md), excluding the [HandlerContextType](./kibana-plugin-public.handlercontexttype.md). | -| [HttpBody](./kibana-plugin-public.httpbody.md) | | -| [HttpHandler](./kibana-plugin-public.httphandler.md) | A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. | | [HttpSetup](./kibana-plugin-public.httpsetup.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | [HttpStart](./kibana-plugin-public.httpstart.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | [IContextProvider](./kibana-plugin-public.icontextprovider.md) | A function that returns a context value for a specific key of given context type. | diff --git a/src/core/public/application/capabilities/capabilities_service.tsx b/src/core/public/application/capabilities/capabilities_service.tsx index e330a4b0326ae..24d9765953c44 100644 --- a/src/core/public/application/capabilities/capabilities_service.tsx +++ b/src/core/public/application/capabilities/capabilities_service.tsx @@ -74,7 +74,7 @@ export class CapabilitiesService { const url = http.anonymousPaths.isAnonymous(window.location.pathname) ? '/api/core/capabilities/defaults' : '/api/core/capabilities'; - const capabilities = await http.post(url, { + const capabilities = await http.post(url, { body: payload, }); return deepFreeze(capabilities); diff --git a/src/core/public/http/fetch.ts b/src/core/public/http/fetch.ts new file mode 100644 index 0000000000000..472b617cacd7f --- /dev/null +++ b/src/core/public/http/fetch.ts @@ -0,0 +1,155 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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 { merge } from 'lodash'; +import { format } from 'url'; + +import { IBasePath, HttpInterceptor, HttpHandler, HttpFetchOptions, IHttpResponse } from './types'; +import { HttpFetchError } from './http_fetch_error'; +import { HttpInterceptController } from './http_intercept_controller'; +import { HttpResponse } from './response'; +import { interceptRequest, interceptResponse } from './intercept'; +import { HttpInterceptHaltError } from './http_intercept_halt_error'; + +interface Params { + basePath: IBasePath; + kibanaVersion: string; +} + +const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/; +const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/; + +export class FetchService { + private readonly interceptors = new Set(); + + constructor(private readonly params: Params) {} + + public intercept(interceptor: HttpInterceptor) { + this.interceptors.add(interceptor); + return () => this.interceptors.delete(interceptor); + } + + public removeAllInterceptors() { + this.interceptors.clear(); + } + + public fetch: HttpHandler = async ( + path: string, + options: HttpFetchOptions = {} + ) => { + const initialRequest = this.createRequest(path, options); + const controller = new HttpInterceptController(); + + // We wrap the interception in a separate promise to ensure that when + // a halt is called we do not resolve or reject, halting handling of the promise. + return new Promise>(async (resolve, reject) => { + try { + const interceptedRequest = await interceptRequest( + initialRequest, + this.interceptors, + controller + ); + const initialResponse = this.fetchResponse(interceptedRequest); + const interceptedResponse = await interceptResponse( + initialResponse, + this.interceptors, + controller + ); + + if (options.asResponse) { + resolve(interceptedResponse); + } else { + resolve(interceptedResponse.body); + } + } catch (error) { + if (!(error instanceof HttpInterceptHaltError)) { + reject(error); + } + } + }); + }; + + private createRequest(path: string, options?: HttpFetchOptions): Request { + // Merge and destructure options out that are not applicable to the Fetch API. + const { query, prependBasePath: shouldPrependBasePath, asResponse, ...fetchOptions } = merge( + { + method: 'GET', + credentials: 'same-origin', + prependBasePath: true, + headers: { + 'kbn-version': this.params.kibanaVersion, + 'Content-Type': 'application/json', + }, + }, + options || {} + ); + const url = format({ + pathname: shouldPrependBasePath ? this.params.basePath.prepend(path) : path, + query, + }); + + if ( + options && + options.headers && + 'Content-Type' in options.headers && + options.headers['Content-Type'] === undefined + ) { + delete fetchOptions.headers['Content-Type']; + } + + return new Request(url, fetchOptions); + } + + private async fetchResponse(request: Request) { + let response: Response; + let body = null; + + try { + response = await window.fetch(request); + } catch (err) { + throw new HttpFetchError(err.message, request); + } + + const contentType = response.headers.get('Content-Type') || ''; + + try { + if (NDJSON_CONTENT.test(contentType)) { + body = await response.blob(); + } else if (JSON_CONTENT.test(contentType)) { + body = await response.json(); + } else { + const text = await response.text(); + + try { + body = JSON.parse(text); + } catch (err) { + body = text; + } + } + } catch (err) { + throw new HttpFetchError(err.message, request, response, body); + } + + if (!response.ok) { + throw new HttpFetchError(response.statusText, request, response, body); + } + + return new HttpResponse({ request, response, body }); + } +} diff --git a/src/core/public/http/http_service.test.ts b/src/core/public/http/http_service.test.ts index 13906b91ed8df..09f3cca419e4d 100644 --- a/src/core/public/http/http_service.test.ts +++ b/src/core/public/http/http_service.test.ts @@ -24,7 +24,7 @@ import fetchMock from 'fetch-mock/es5/client'; import { readFileSync } from 'fs'; import { join } from 'path'; import { setup, SetupTap } from '../../../test_utils/public/http_test_setup'; -import { HttpResponse } from './types'; +import { IHttpResponse } from './types'; function delay(duration: number) { return new Promise(r => setTimeout(r, duration)); @@ -101,32 +101,32 @@ describe('http requests', () => { it('should return response', async () => { const { http } = setup(); - fetchMock.get('*', { foo: 'bar' }); - const json = await http.fetch('/my/path'); - expect(json).toEqual({ foo: 'bar' }); }); it('should prepend url with basepath by default', async () => { const { http } = setup(); - fetchMock.get('*', {}); await http.fetch('/my/path'); - expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path'); }); it('should not prepend url with basepath when disabled', async () => { const { http } = setup(); - fetchMock.get('*', {}); await http.fetch('my/path', { prependBasePath: false }); - expect(fetchMock.lastUrl()).toBe('/my/path'); }); + it('should not include undefined query params', async () => { + const { http } = setup(); + fetchMock.get('*', {}); + await http.fetch('/my/path', { query: { a: undefined } }); + expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path'); + }); + it('should make request with defaults', async () => { const { http } = setup(); @@ -145,6 +145,18 @@ describe('http requests', () => { }); }); + it('should expose detailed response object when asResponse = true', async () => { + const { http } = setup(); + + fetchMock.get('*', { foo: 'bar' }); + + const response = await http.fetch('/my/path', { asResponse: true }); + + expect(response.request).toBeInstanceOf(Request); + expect(response.response).toBeInstanceOf(Response); + expect(response.body).toEqual({ foo: 'bar' }); + }); + it('should reject on network error', async () => { const { http } = setup(); @@ -496,7 +508,7 @@ describe('interception', () => { it('should accumulate response information', async () => { const bodies = ['alpha', 'beta', 'gamma']; - const createResponse = jest.fn((httpResponse: HttpResponse) => ({ + const createResponse = jest.fn((httpResponse: IHttpResponse) => ({ body: bodies.shift(), })); diff --git a/src/core/public/http/http_setup.ts b/src/core/public/http/http_setup.ts index 602382e3a5a60..c63750849f13a 100644 --- a/src/core/public/http/http_setup.ts +++ b/src/core/public/http/http_setup.ts @@ -27,21 +27,16 @@ import { takeUntil, tap, } from 'rxjs/operators'; -import { merge } from 'lodash'; -import { format } from 'url'; import { InjectedMetadataSetup } from '../injected_metadata'; import { FatalErrorsSetup } from '../fatal_errors'; -import { HttpFetchOptions, HttpServiceBase, HttpInterceptor, HttpResponse } from './types'; +import { HttpFetchOptions, HttpServiceBase } from './types'; import { HttpInterceptController } from './http_intercept_controller'; -import { HttpFetchError } from './http_fetch_error'; import { HttpInterceptHaltError } from './http_intercept_halt_error'; import { BasePath } from './base_path_service'; import { AnonymousPaths } from './anonymous_paths'; +import { FetchService } from './fetch'; -const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/; -const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/; - -function checkHalt(controller: HttpInterceptController, error?: Error) { +export function checkHalt(controller: HttpInterceptController, error?: Error) { if (error instanceof HttpInterceptHaltError) { throw error; } else if (controller.halted) { @@ -55,224 +50,15 @@ export const setup = ( ): HttpServiceBase => { const loadingCount$ = new BehaviorSubject(0); const stop$ = new Subject(); - const interceptors = new Set(); const kibanaVersion = injectedMetadata.getKibanaVersion(); const basePath = new BasePath(injectedMetadata.getBasePath()); const anonymousPaths = new AnonymousPaths(basePath); - function intercept(interceptor: HttpInterceptor) { - interceptors.add(interceptor); - - return () => interceptors.delete(interceptor); - } - - function removeAllInterceptors() { - interceptors.clear(); - } - - function createRequest(path: string, options?: HttpFetchOptions) { - const { query, prependBasePath: shouldPrependBasePath, ...fetchOptions } = merge( - { - method: 'GET', - credentials: 'same-origin', - prependBasePath: true, - headers: { - 'kbn-version': kibanaVersion, - 'Content-Type': 'application/json', - }, - }, - options || {} - ); - const url = format({ - pathname: shouldPrependBasePath ? basePath.prepend(path) : path, - query, - }); - - if ( - options && - options.headers && - 'Content-Type' in options.headers && - options.headers['Content-Type'] === undefined - ) { - delete fetchOptions.headers['Content-Type']; - } - - return new Request(url, fetchOptions); - } - - // Request/response interceptors are called in opposite orders. - // Request hooks start from the newest interceptor and end with the oldest. - function interceptRequest( - request: Request, - controller: HttpInterceptController - ): Promise { - let next = request; - - return [...interceptors].reduceRight( - (promise, interceptor) => - promise.then( - async (current: Request) => { - next = current; - checkHalt(controller); - - if (!interceptor.request) { - return current; - } - - return (await interceptor.request(current, controller)) || current; - }, - async error => { - checkHalt(controller, error); - - if (!interceptor.requestError) { - throw error; - } - - const nextRequest = await interceptor.requestError( - { error, request: next }, - controller - ); - - if (!nextRequest) { - throw error; - } - - next = nextRequest; - return next; - } - ), - Promise.resolve(request) - ); - } - - // Response hooks start from the oldest interceptor and end with the newest. - async function interceptResponse( - responsePromise: Promise, - controller: HttpInterceptController - ) { - let current: HttpResponse | undefined; - - const finalHttpResponse = await [...interceptors].reduce( - (promise, interceptor) => - promise.then( - async httpResponse => { - current = httpResponse; - checkHalt(controller); - - if (!interceptor.response) { - return httpResponse; - } - - return { - ...httpResponse, - ...((await interceptor.response(httpResponse, controller)) || {}), - }; - }, - async error => { - const request = error.request || (current && current.request); - - checkHalt(controller, error); - - if (!interceptor.responseError) { - throw error; - } - - try { - const next = await interceptor.responseError( - { - error, - request, - response: error.response || (current && current.response), - body: error.body || (current && current.body), - }, - controller - ); - - checkHalt(controller, error); - - if (!next) { - throw error; - } - - return { ...next, request }; - } catch (err) { - checkHalt(controller, err); - throw err; - } - } - ), - responsePromise - ); - - return finalHttpResponse.body; - } - - async function fetcher(request: Request): Promise { - let response; - let body = null; - - try { - response = await window.fetch(request); - } catch (err) { - throw new HttpFetchError(err.message, request); - } - - const contentType = response.headers.get('Content-Type') || ''; - - try { - if (NDJSON_CONTENT.test(contentType)) { - body = await response.blob(); - } else if (JSON_CONTENT.test(contentType)) { - body = await response.json(); - } else { - const text = await response.text(); - - try { - body = JSON.parse(text); - } catch (err) { - body = text; - } - } - } catch (err) { - throw new HttpFetchError(err.message, request, response, body); - } - - if (!response.ok) { - throw new HttpFetchError(response.statusText, request, response, body); - } - - return { response, body, request }; - } - - async function fetch(path: string, options: HttpFetchOptions = {}) { - const controller = new HttpInterceptController(); - const initialRequest = createRequest(path, options); - - // We wrap the interception in a separate promise to ensure that when - // a halt is called we do not resolve or reject, halting handling of the promise. - return new Promise(async (resolve, reject) => { - function rejectIfNotHalted(err: any) { - if (!(err instanceof HttpInterceptHaltError)) { - reject(err); - } - } - - try { - const request = await interceptRequest(initialRequest, controller); - - try { - resolve(await interceptResponse(fetcher(request), controller)); - } catch (err) { - rejectIfNotHalted(err); - } - } catch (err) { - rejectIfNotHalted(err); - } - }); - } + const fetchService = new FetchService({ basePath, kibanaVersion }); function shorthand(method: string) { - return (path: string, options: HttpFetchOptions = {}) => fetch(path, { ...options, method }); + return (path: string, options: HttpFetchOptions = {}) => + fetchService.fetch(path, { ...options, method }); } function stop() { @@ -321,9 +107,9 @@ export const setup = ( stop, basePath, anonymousPaths, - intercept, - removeAllInterceptors, - fetch, + intercept: fetchService.intercept.bind(fetchService), + removeAllInterceptors: fetchService.removeAllInterceptors.bind(fetchService), + fetch: fetchService.fetch.bind(fetchService), delete: shorthand('DELETE'), get: shorthand('GET'), head: shorthand('HEAD'), diff --git a/src/core/public/http/intercept.ts b/src/core/public/http/intercept.ts new file mode 100644 index 0000000000000..e2a16565c61c4 --- /dev/null +++ b/src/core/public/http/intercept.ts @@ -0,0 +1,134 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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 { HttpInterceptController } from './http_intercept_controller'; +import { HttpInterceptHaltError } from './http_intercept_halt_error'; +import { HttpInterceptor, IHttpResponse } from './types'; +import { HttpResponse } from './response'; + +export async function interceptRequest( + request: Request, + interceptors: ReadonlySet, + controller: HttpInterceptController +): Promise { + let next = request; + + return [...interceptors].reduceRight( + (promise, interceptor) => + promise.then( + async (current: Request) => { + next = current; + checkHalt(controller); + + if (!interceptor.request) { + return current; + } + + return (await interceptor.request(current, controller)) || current; + }, + async error => { + checkHalt(controller, error); + + if (!interceptor.requestError) { + throw error; + } + + const nextRequest = await interceptor.requestError({ error, request: next }, controller); + + if (!nextRequest) { + throw error; + } + + next = nextRequest; + return next; + } + ), + Promise.resolve(request) + ); +} + +export async function interceptResponse( + responsePromise: Promise, + interceptors: ReadonlySet, + controller: HttpInterceptController +): Promise { + let current: IHttpResponse; + + return await [...interceptors].reduce( + (promise, interceptor) => + promise.then( + async httpResponse => { + current = httpResponse; + checkHalt(controller); + + if (!interceptor.response) { + return httpResponse; + } + + const interceptorOverrides = (await interceptor.response(httpResponse, controller)) || {}; + + return new HttpResponse({ + ...httpResponse, + ...interceptorOverrides, + }); + }, + async error => { + const request = error.request || (current && current.request); + + checkHalt(controller, error); + + if (!interceptor.responseError) { + throw error; + } + + try { + const next = await interceptor.responseError( + { + error, + request, + response: error.response || (current && current.response), + body: error.body || (current && current.body), + }, + controller + ); + + checkHalt(controller, error); + + if (!next) { + throw error; + } + + return new HttpResponse({ ...next, request }); + } catch (err) { + checkHalt(controller, err); + throw err; + } + } + ), + responsePromise + ); +} + +function checkHalt(controller: HttpInterceptController, error?: Error) { + if (error instanceof HttpInterceptHaltError) { + throw error; + } else if (controller.halted) { + throw new HttpInterceptHaltError(); + } +} diff --git a/src/core/public/http/response.ts b/src/core/public/http/response.ts new file mode 100644 index 0000000000000..706e7caaca976 --- /dev/null +++ b/src/core/public/http/response.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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 { IHttpResponse } from './types'; + +export class HttpResponse implements IHttpResponse { + public readonly request: Request; + public readonly response?: Response; + public readonly body?: TResponseBody; + + constructor({ + request, + response, + body, + }: { + request: Request; + response?: Response; + body?: TResponseBody; + }) { + this.request = request; + this.response = response; + this.body = body; + } +} diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index 870d4af8f9e86..48385a72325db 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -229,31 +229,49 @@ export interface HttpFetchOptions extends HttpRequestInit { * Headers to send with the request. See {@link HttpHeadersInit}. */ headers?: HttpHeadersInit; + + /** + * When `true` the return type of {@link HttpHandler} will be an {@link IHttpResponse} with detailed request and + * response information. When `false`, the return type will just be the parsed response body. Defaults to `false`. + */ + asResponse?: boolean; } /** * A function for making an HTTP requests to Kibana's backend. See {@link HttpFetchOptions} for options and - * {@link HttpBody} for the response. + * {@link IHttpResponse} for the response. * * @param path the path on the Kibana server to send the request to. Should not include the basePath. * @param options {@link HttpFetchOptions} - * @returns a Promise that resolves to a {@link HttpBody} + * @returns a Promise that resolves to a {@link IHttpResponse} * @public */ -export type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; - -/** @public */ -export type HttpBody = BodyInit | null | any; +export interface HttpHandler { + (path: string, options: HttpFetchOptions & { asResponse: true }): Promise< + IHttpResponse + >; + (path: string, options?: HttpFetchOptions): Promise; +} /** @public */ -export interface InterceptedHttpResponse { - response?: Response; - body?: HttpBody; +export interface IHttpResponse { + /** Raw request sent to Kibana server. */ + readonly request: Readonly; + /** Raw response received, may be undefined if there was an error. */ + readonly response?: Readonly; + /** Parsed body received, may be undefined if there was an error. */ + readonly body?: TResponseBody; } -/** @public */ -export interface HttpResponse extends InterceptedHttpResponse { - request: Readonly; +/** + * Properties that can be returned by HttpInterceptor.request to override the response. + * @public + */ +export interface IHttpResponseInterceptorOverrides { + /** Raw response received, may be undefined if there was an error. */ + readonly response?: Readonly; + /** Parsed body received, may be undefined if there was an error. */ + readonly body?: TResponseBody; } /** @public */ @@ -272,7 +290,7 @@ export interface IHttpFetchError extends Error { } /** @public */ -export interface HttpErrorResponse extends HttpResponse { +export interface HttpErrorResponse extends IHttpResponse { error: Error | IHttpFetchError; } /** @public */ @@ -310,13 +328,13 @@ export interface HttpInterceptor { /** * Define an interceptor to be executed after a response is received. - * @param httpResponse {@link HttpResponse} + * @param httpResponse {@link IHttpResponse} * @param controller {@link IHttpInterceptController} */ response?( - httpResponse: HttpResponse, + httpResponse: IHttpResponse, controller: IHttpInterceptController - ): Promise | InterceptedHttpResponse | void; + ): Promise | IHttpResponseInterceptorOverrides | void; /** * Define an interceptor to be executed if a response interceptor throws an error or returns a rejected Promise. @@ -326,7 +344,7 @@ export interface HttpInterceptor { responseError?( httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController - ): Promise | InterceptedHttpResponse | void; + ): Promise | IHttpResponseInterceptorOverrides | void; } /** diff --git a/src/core/public/index.ts b/src/core/public/index.ts index cfec03427f3e7..035cbcca86ac7 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -112,14 +112,13 @@ export { HttpErrorResponse, HttpErrorRequest, HttpInterceptor, - HttpResponse, + IHttpResponse, HttpHandler, - HttpBody, IBasePath, IAnonymousPaths, IHttpInterceptController, IHttpFetchError, - InterceptedHttpResponse, + IHttpResponseInterceptorOverrides, } from './http'; export { OverlayStart, OverlayBannersStart, OverlayRef } from './overlays'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 6fbc7324ce393..157f0bab466b0 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -464,9 +464,6 @@ export type HandlerFunction = (context: T, ...args: any[]) => // @public export type HandlerParameters> = T extends (context: any, ...args: infer U) => any ? U : never; -// @public (undocumented) -export type HttpBody = BodyInit | null | any; - // @public (undocumented) export interface HttpErrorRequest { // (undocumented) @@ -476,13 +473,14 @@ export interface HttpErrorRequest { } // @public (undocumented) -export interface HttpErrorResponse extends HttpResponse { +export interface HttpErrorResponse extends IHttpResponse { // (undocumented) error: Error | IHttpFetchError; } // @public export interface HttpFetchOptions extends HttpRequestInit { + asResponse?: boolean; headers?: HttpHeadersInit; prependBasePath?: boolean; query?: HttpFetchQuery; @@ -495,7 +493,14 @@ export interface HttpFetchQuery { } // @public -export type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; +export interface HttpHandler { + // (undocumented) + (path: string, options: HttpFetchOptions & { + asResponse: true; + }): Promise>; + // (undocumented) + (path: string, options?: HttpFetchOptions): Promise; +} // @public (undocumented) export interface HttpHeadersInit { @@ -507,8 +512,8 @@ export interface HttpHeadersInit { export interface HttpInterceptor { request?(request: Request, controller: IHttpInterceptController): Promise | Request | void; requestError?(httpErrorRequest: HttpErrorRequest, controller: IHttpInterceptController): Promise | Request | void; - response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; - responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; + response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; + responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; } // @public @@ -529,12 +534,6 @@ export interface HttpRequestInit { window?: null; } -// @public (undocumented) -export interface HttpResponse extends InterceptedHttpResponse { - // (undocumented) - request: Readonly; -} - // @public (undocumented) export interface HttpServiceBase { addLoadingCount(countSource$: Observable): void; @@ -613,11 +612,16 @@ export interface IHttpInterceptController { } // @public (undocumented) -export interface InterceptedHttpResponse { - // (undocumented) - body?: HttpBody; - // (undocumented) - response?: Response; +export interface IHttpResponse { + readonly body?: TResponseBody; + readonly request: Readonly; + readonly response?: Readonly; +} + +// @public +export interface IHttpResponseInterceptorOverrides { + readonly body?: TResponseBody; + readonly response?: Readonly; } // @public diff --git a/src/plugins/share/public/components/share_context_menu.test.tsx b/src/plugins/share/public/components/share_context_menu.test.tsx index 7fb0449ead502..1f2242ae4c515 100644 --- a/src/plugins/share/public/components/share_context_menu.test.tsx +++ b/src/plugins/share/public/components/share_context_menu.test.tsx @@ -34,7 +34,7 @@ const defaultProps = { isDirty: false, onClose: () => {}, basePath: '', - post: () => Promise.resolve(), + post: () => Promise.resolve({} as any), objectType: 'dashboard', }; diff --git a/src/plugins/share/public/components/url_panel_content.test.tsx b/src/plugins/share/public/components/url_panel_content.test.tsx index 9da1a23641ab8..9db8d1ccf2efa 100644 --- a/src/plugins/share/public/components/url_panel_content.test.tsx +++ b/src/plugins/share/public/components/url_panel_content.test.tsx @@ -28,7 +28,7 @@ const defaultProps = { allowShortUrl: true, objectType: 'dashboard', basePath: '', - post: () => Promise.resolve(), + post: () => Promise.resolve({} as any), }; test('render', () => { diff --git a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts index 0a0fc8cae5d26..3bfc868fcb06e 100644 --- a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts +++ b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts @@ -12,7 +12,7 @@ const icon = getSuitableIcon(''); describe('fetch_top_nodes', () => { it('should build terms agg', async () => { const postMock = jest.fn(() => Promise.resolve({ resp: {} })); - await fetchTopNodes(postMock, 'test', [ + await fetchTopNodes(postMock as any, 'test', [ { color: '', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' }, { color: '', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' }, ]); @@ -64,7 +64,7 @@ describe('fetch_top_nodes', () => { }, }) ); - const result = await fetchTopNodes(postMock, 'test', [ + const result = await fetchTopNodes(postMock as any, 'test', [ { color: 'red', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' }, { color: 'blue', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' }, ]); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx index dc23df250ebd4..52f00a7cd4e9d 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx @@ -278,7 +278,7 @@ describe('IndexPattern Data Panel', () => { function testProps() { const setState = jest.fn(); - core.http.get = jest.fn(async (url: string) => { + core.http.get.mockImplementation(async (url: string) => { const parts = url.split('/'); const indexPatternTitle = parts[parts.length - 1]; return { @@ -484,7 +484,7 @@ describe('IndexPattern Data Panel', () => { let overlapCount = 0; const props = testProps(); - core.http.get = jest.fn((url: string) => { + core.http.get.mockImplementation((url: string) => { if (queryCount) { ++overlapCount; } @@ -533,11 +533,9 @@ describe('IndexPattern Data Panel', () => { it('shows all fields if empty state button is clicked', async () => { const props = testProps(); - core.http.get = jest.fn((url: string) => { - return Promise.resolve({ - indexPatternTitle: props.currentIndexPatternId, - existingFieldNames: [], - }); + core.http.get.mockResolvedValue({ + indexPatternTitle: props.currentIndexPatternId, + existingFieldNames: [], }); const inst = mountWithIntl(); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts index 72cbd1b861a05..2fb678aed5a54 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts @@ -528,7 +528,8 @@ describe('loader', () => { await syncExistingFields({ dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fetchJson: fetchJson as any, indexPatterns: [{ title: 'a' }, { title: 'b' }, { title: 'c' }], setState, }); diff --git a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts index 81625e1753b27..8a2251f3f7f7c 100644 --- a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts +++ b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts @@ -4,7 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpInterceptor, HttpErrorResponse, HttpResponse, IAnonymousPaths } from 'src/core/public'; +import { + HttpInterceptor, + HttpErrorResponse, + IHttpResponse, + IAnonymousPaths, +} from 'src/core/public'; import { ISessionTimeout } from './session_timeout'; @@ -15,7 +20,7 @@ const isSystemAPIRequest = (request: Request) => { export class SessionTimeoutHttpInterceptor implements HttpInterceptor { constructor(private sessionTimeout: ISessionTimeout, private anonymousPaths: IAnonymousPaths) {} - response(httpResponse: HttpResponse) { + response(httpResponse: IHttpResponse) { if (this.anonymousPaths.isAnonymous(window.location.pathname)) { return; }