mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add asResponse option to HttpService methods (#52434)
This commit is contained in:
parent
ab1fe3f14e
commit
a91e53f18f
35 changed files with 571 additions and 383 deletions
|
@ -1,12 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpBody](./kibana-plugin-public.httpbody.md)
|
||||
|
||||
## HttpBody type
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpBody = BodyInit | null | any;
|
||||
```
|
|
@ -8,7 +8,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface HttpErrorResponse extends HttpResponse
|
||||
export interface HttpErrorResponse extends IHttpResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
asResponse?: boolean;
|
||||
```
|
|
@ -16,6 +16,7 @@ export interface HttpFetchOptions extends HttpRequestInit
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [asResponse](./kibana-plugin-public.httpfetchoptions.asresponse.md) | <code>boolean</code> | When <code>true</code> 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 <code>false</code>, the return type will just be the parsed response body. Defaults to <code>false</code>. |
|
||||
| [headers](./kibana-plugin-public.httpfetchoptions.headers.md) | <code>HttpHeadersInit</code> | Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md)<!-- -->. |
|
||||
| [prependBasePath](./kibana-plugin-public.httpfetchoptions.prependbasepath.md) | <code>boolean</code> | Whether or not the request should automatically prepend the basePath. Defaults to <code>true</code>. |
|
||||
| [query](./kibana-plugin-public.httpfetchoptions.query.md) | <code>HttpFetchQuery</code> | The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise<HttpBody>;
|
||||
export interface HttpHandler
|
||||
```
|
||||
|
|
|
@ -9,17 +9,17 @@ Define an interceptor to be executed after a response is received.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void;
|
||||
response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| httpResponse | <code>HttpResponse</code> | |
|
||||
| httpResponse | <code>IHttpResponse</code> | |
|
||||
| controller | <code>IHttpInterceptController</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void`
|
||||
`Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void`
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Define an interceptor to be executed if a response interceptor throws an error o
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void;
|
||||
responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -21,5 +21,5 @@ responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptC
|
|||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void`
|
||||
`Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void`
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpResponse](./kibana-plugin-public.httpresponse.md)
|
||||
|
||||
## HttpResponse interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface HttpResponse extends InterceptedHttpResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [request](./kibana-plugin-public.httpresponse.request.md) | <code>Readonly<Request></code> | |
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
request: Readonly<Request>;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly body?: TResponseBody;
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md)
|
||||
|
||||
## IHttpResponse interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IHttpResponse<TResponseBody = any>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [body](./kibana-plugin-public.ihttpresponse.body.md) | <code>TResponseBody</code> | Parsed body received, may be undefined if there was an error. |
|
||||
| [request](./kibana-plugin-public.ihttpresponse.request.md) | <code>Readonly<Request></code> | Raw request sent to Kibana server. |
|
||||
| [response](./kibana-plugin-public.ihttpresponse.response.md) | <code>Readonly<Response></code> | Raw response received, may be undefined if there was an error. |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly request: Readonly<Request>;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly response?: Readonly<Response>;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly body?: TResponseBody;
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IHttpResponseInterceptorOverrides<TResponseBody = any>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [body](./kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md) | <code>TResponseBody</code> | Parsed body received, may be undefined if there was an error. |
|
||||
| [response](./kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md) | <code>Readonly<Response></code> | Raw response received, may be undefined if there was an error. |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly response?: Readonly<Response>;
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
body?: HttpBody;
|
||||
```
|
|
@ -1,20 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md)
|
||||
|
||||
## InterceptedHttpResponse interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface InterceptedHttpResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [body](./kibana-plugin-public.interceptedhttpresponse.body.md) | <code>HttpBody</code> | |
|
||||
| [response](./kibana-plugin-public.interceptedhttpresponse.response.md) | <code>Response</code> | |
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
response?: Response;
|
||||
```
|
|
@ -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 <code>ui/new_platform</code> module. |
|
||||
| [LegacyCoreStart](./kibana-plugin-public.legacycorestart.md) | Start interface exposed to the legacy platform via the <code>ui/new_platform</code> 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. |
|
||||
|
|
|
@ -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<Capabilities>(url, {
|
||||
body: payload,
|
||||
});
|
||||
return deepFreeze(capabilities);
|
||||
|
|
155
src/core/public/http/fetch.ts
Normal file
155
src/core/public/http/fetch.ts
Normal file
|
@ -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<HttpInterceptor>();
|
||||
|
||||
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 <TResponseBody>(
|
||||
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<TResponseBody | IHttpResponse<TResponseBody>>(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 });
|
||||
}
|
||||
}
|
|
@ -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<T>(duration: number) {
|
||||
return new Promise<T>(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(),
|
||||
}));
|
||||
|
||||
|
|
|
@ -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<HttpInterceptor>();
|
||||
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<Request> {
|
||||
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<HttpResponse>,
|
||||
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<HttpResponse> {
|
||||
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'),
|
||||
|
|
134
src/core/public/http/intercept.ts
Normal file
134
src/core/public/http/intercept.ts
Normal file
|
@ -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<HttpInterceptor>,
|
||||
controller: HttpInterceptController
|
||||
): Promise<Request> {
|
||||
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<IHttpResponse>,
|
||||
interceptors: ReadonlySet<HttpInterceptor>,
|
||||
controller: HttpInterceptController
|
||||
): Promise<IHttpResponse> {
|
||||
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();
|
||||
}
|
||||
}
|
40
src/core/public/http/response.ts
Normal file
40
src/core/public/http/response.ts
Normal file
|
@ -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<TResponseBody = any> implements IHttpResponse<TResponseBody> {
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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<HttpBody>;
|
||||
|
||||
/** @public */
|
||||
export type HttpBody = BodyInit | null | any;
|
||||
|
||||
/** @public */
|
||||
export interface InterceptedHttpResponse {
|
||||
response?: Response;
|
||||
body?: HttpBody;
|
||||
export interface HttpHandler {
|
||||
<TResponseBody = any>(path: string, options: HttpFetchOptions & { asResponse: true }): Promise<
|
||||
IHttpResponse<TResponseBody>
|
||||
>;
|
||||
<TResponseBody = any>(path: string, options?: HttpFetchOptions): Promise<TResponseBody>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface HttpResponse extends InterceptedHttpResponse {
|
||||
request: Readonly<Request>;
|
||||
export interface IHttpResponse<TResponseBody = any> {
|
||||
/** Raw request sent to Kibana server. */
|
||||
readonly request: Readonly<Request>;
|
||||
/** Raw response received, may be undefined if there was an error. */
|
||||
readonly response?: Readonly<Response>;
|
||||
/** Parsed body received, may be undefined if there was an error. */
|
||||
readonly body?: TResponseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties that can be returned by HttpInterceptor.request to override the response.
|
||||
* @public
|
||||
*/
|
||||
export interface IHttpResponseInterceptorOverrides<TResponseBody = any> {
|
||||
/** Raw response received, may be undefined if there was an error. */
|
||||
readonly response?: Readonly<Response>;
|
||||
/** 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> | InterceptedHttpResponse | void;
|
||||
): Promise<IHttpResponseInterceptorOverrides> | 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> | InterceptedHttpResponse | void;
|
||||
): Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -464,9 +464,6 @@ export type HandlerFunction<T extends object> = (context: T, ...args: any[]) =>
|
|||
// @public
|
||||
export type HandlerParameters<T extends HandlerFunction<any>> = 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<HttpBody>;
|
||||
export interface HttpHandler {
|
||||
// (undocumented)
|
||||
<TResponseBody = any>(path: string, options: HttpFetchOptions & {
|
||||
asResponse: true;
|
||||
}): Promise<IHttpResponse<TResponseBody>>;
|
||||
// (undocumented)
|
||||
<TResponseBody = any>(path: string, options?: HttpFetchOptions): Promise<TResponseBody>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpHeadersInit {
|
||||
|
@ -507,8 +512,8 @@ export interface HttpHeadersInit {
|
|||
export interface HttpInterceptor {
|
||||
request?(request: Request, controller: IHttpInterceptController): Promise<Request> | Request | void;
|
||||
requestError?(httpErrorRequest: HttpErrorRequest, controller: IHttpInterceptController): Promise<Request> | Request | void;
|
||||
response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void;
|
||||
responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise<InterceptedHttpResponse> | InterceptedHttpResponse | void;
|
||||
response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void;
|
||||
responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise<IHttpResponseInterceptorOverrides> | IHttpResponseInterceptorOverrides | void;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -529,12 +534,6 @@ export interface HttpRequestInit {
|
|||
window?: null;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpResponse extends InterceptedHttpResponse {
|
||||
// (undocumented)
|
||||
request: Readonly<Request>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpServiceBase {
|
||||
addLoadingCount(countSource$: Observable<number>): void;
|
||||
|
@ -613,11 +612,16 @@ export interface IHttpInterceptController {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface InterceptedHttpResponse {
|
||||
// (undocumented)
|
||||
body?: HttpBody;
|
||||
// (undocumented)
|
||||
response?: Response;
|
||||
export interface IHttpResponse<TResponseBody = any> {
|
||||
readonly body?: TResponseBody;
|
||||
readonly request: Readonly<Request>;
|
||||
readonly response?: Readonly<Response>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface IHttpResponseInterceptorOverrides<TResponseBody = any> {
|
||||
readonly body?: TResponseBody;
|
||||
readonly response?: Readonly<Response>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -34,7 +34,7 @@ const defaultProps = {
|
|||
isDirty: false,
|
||||
onClose: () => {},
|
||||
basePath: '',
|
||||
post: () => Promise.resolve(),
|
||||
post: () => Promise.resolve({} as any),
|
||||
objectType: 'dashboard',
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ const defaultProps = {
|
|||
allowShortUrl: true,
|
||||
objectType: 'dashboard',
|
||||
basePath: '',
|
||||
post: () => Promise.resolve(),
|
||||
post: () => Promise.resolve({} as any),
|
||||
};
|
||||
|
||||
test('render', () => {
|
||||
|
|
|
@ -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' },
|
||||
]);
|
||||
|
|
|
@ -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(<IndexPatternDataPanel {...props} />);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue