(request: KibanaRequest<unknown, unknown, unknown> | LegacyRequest) => string
| returns basePath
value, specific for an incoming request. |
+| [get](./kibana-plugin-server.basepath.get.md) | | (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest) => string
| returns basePath
value, specific for an incoming request. |
| [prepend](./kibana-plugin-server.basepath.prepend.md) | | (path: string) => string
| Prepends path
with the basePath. |
| [remove](./kibana-plugin-server.basepath.remove.md) | | (path: string) => string
| Removes the prepended basePath from the path
. |
| [serverBasePath](./kibana-plugin-server.basepath.serverbasepath.md) | | string
| returns the server's basePathSee [BasePath.get](./kibana-plugin-server.basepath.get.md) for getting the basePath value for a specific request |
-| [set](./kibana-plugin-server.basepath.set.md) | | (request: KibanaRequest<unknown, unknown, unknown> | LegacyRequest, requestSpecificBasePath: string) => void
| sets basePath
value, specific for an incoming request. |
+| [set](./kibana-plugin-server.basepath.set.md) | | (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest, requestSpecificBasePath: string) => void
| sets basePath
value, specific for an incoming request. |
## Remarks
diff --git a/docs/development/core/server/kibana-plugin-server.basepath.set.md b/docs/development/core/server/kibana-plugin-server.basepath.set.md
index 1272a134ef5c4..56a7f644d34cc 100644
--- a/docs/development/core/server/kibana-plugin-server.basepath.set.md
+++ b/docs/development/core/server/kibana-plugin-server.basepath.set.md
@@ -9,5 +9,5 @@ sets `basePath` value, specific for an incoming request.
Signature:
```typescript
-set: (request: KibanaRequestRouteRegistrar
| Register a route handler for DELETE
request. |
-| [get](./kibana-plugin-server.irouter.get.md) | RouteRegistrar
| Register a route handler for GET
request. |
+| [delete](./kibana-plugin-server.irouter.delete.md) | RouteRegistrar<'delete'>
| Register a route handler for DELETE
request. |
+| [get](./kibana-plugin-server.irouter.get.md) | RouteRegistrar<'get'>
| Register a route handler for GET
request. |
| [handleLegacyErrors](./kibana-plugin-server.irouter.handlelegacyerrors.md) | <P extends ObjectType, Q extends ObjectType, B extends ObjectType>(handler: RequestHandler<P, Q, B>) => RequestHandler<P, Q, B>
| Wrap a router handler to catch and converts legacy boom errors to proper custom errors. |
-| [post](./kibana-plugin-server.irouter.post.md) | RouteRegistrar
| Register a route handler for POST
request. |
-| [put](./kibana-plugin-server.irouter.put.md) | RouteRegistrar
| Register a route handler for PUT
request. |
+| [patch](./kibana-plugin-server.irouter.patch.md) | RouteRegistrar<'patch'>
| Register a route handler for PATCH
request. |
+| [post](./kibana-plugin-server.irouter.post.md) | RouteRegistrar<'post'>
| Register a route handler for POST
request. |
+| [put](./kibana-plugin-server.irouter.put.md) | RouteRegistrar<'put'>
| Register a route handler for PUT
request. |
| [routerPath](./kibana-plugin-server.irouter.routerpath.md) | string
| Resulted path |
diff --git a/docs/development/core/server/kibana-plugin-server.irouter.patch.md b/docs/development/core/server/kibana-plugin-server.irouter.patch.md
new file mode 100644
index 0000000000000..460f1b9d23640
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.irouter.patch.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IRouter](./kibana-plugin-server.irouter.md) > [patch](./kibana-plugin-server.irouter.patch.md)
+
+## IRouter.patch property
+
+Register a route handler for `PATCH` request.
+
+Signature:
+
+```typescript
+patch: RouteRegistrar<'patch'>;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.irouter.post.md b/docs/development/core/server/kibana-plugin-server.irouter.post.md
index cd655c9ce0dc8..a2ac27ebc731a 100644
--- a/docs/development/core/server/kibana-plugin-server.irouter.post.md
+++ b/docs/development/core/server/kibana-plugin-server.irouter.post.md
@@ -9,5 +9,5 @@ Register a route handler for `POST` request.
Signature:
```typescript
-post: RouteRegistrar;
+post: RouteRegistrar<'post'>;
```
diff --git a/docs/development/core/server/kibana-plugin-server.irouter.put.md b/docs/development/core/server/kibana-plugin-server.irouter.put.md
index e553d4b79dd2b..219c5d8805661 100644
--- a/docs/development/core/server/kibana-plugin-server.irouter.put.md
+++ b/docs/development/core/server/kibana-plugin-server.irouter.put.md
@@ -9,5 +9,5 @@ Register a route handler for `PUT` request.
Signature:
```typescript
-put: RouteRegistrar;
+put: RouteRegistrar<'put'>;
```
diff --git a/docs/development/core/server/kibana-plugin-server.kibanarequest.md b/docs/development/core/server/kibana-plugin-server.kibanarequest.md
index b2460cd58f7a7..bc805fdc0b86f 100644
--- a/docs/development/core/server/kibana-plugin-server.kibanarequest.md
+++ b/docs/development/core/server/kibana-plugin-server.kibanarequest.md
@@ -9,7 +9,7 @@ Kibana specific abstraction for an incoming request.
Signature:
```typescript
-export declare class KibanaRequestParams
| |
| [query](./kibana-plugin-server.kibanarequest.query.md) | | Query
| |
-| [route](./kibana-plugin-server.kibanarequest.route.md) | | RecursiveReadonly<KibanaRequestRoute>
| matched route details |
+| [route](./kibana-plugin-server.kibanarequest.route.md) | | RecursiveReadonly<KibanaRequestRoute<Method>>
| matched route details |
| [socket](./kibana-plugin-server.kibanarequest.socket.md) | | IKibanaSocket
| |
| [url](./kibana-plugin-server.kibanarequest.url.md) | | Url
| a WHATWG URL standard object. |
diff --git a/docs/development/core/server/kibana-plugin-server.kibanarequest.route.md b/docs/development/core/server/kibana-plugin-server.kibanarequest.route.md
index 88954eedf4cfb..1905070a99068 100644
--- a/docs/development/core/server/kibana-plugin-server.kibanarequest.route.md
+++ b/docs/development/core/server/kibana-plugin-server.kibanarequest.route.md
@@ -9,5 +9,5 @@ matched route details
Signature:
```typescript
-readonly route: RecursiveReadonlyRouteMethod | 'patch' | 'options'
| |
-| [options](./kibana-plugin-server.kibanarequestroute.options.md) | Required<RouteConfigOptions>
| |
+| [method](./kibana-plugin-server.kibanarequestroute.method.md) | Method
| |
+| [options](./kibana-plugin-server.kibanarequestroute.options.md) | KibanaRequestRouteOptions<Method>
| |
| [path](./kibana-plugin-server.kibanarequestroute.path.md) | string
| |
diff --git a/docs/development/core/server/kibana-plugin-server.kibanarequestroute.method.md b/docs/development/core/server/kibana-plugin-server.kibanarequestroute.method.md
index c003b06e128e4..5775d28b1e053 100644
--- a/docs/development/core/server/kibana-plugin-server.kibanarequestroute.method.md
+++ b/docs/development/core/server/kibana-plugin-server.kibanarequestroute.method.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-method: RouteMethod | 'patch' | 'options';
+method: Method;
```
diff --git a/docs/development/core/server/kibana-plugin-server.kibanarequestroute.options.md b/docs/development/core/server/kibana-plugin-server.kibanarequestroute.options.md
index 98c898449a5b1..438263f61eb20 100644
--- a/docs/development/core/server/kibana-plugin-server.kibanarequestroute.options.md
+++ b/docs/development/core/server/kibana-plugin-server.kibanarequestroute.options.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-options: Requiredattributes
property. |
| [SavedObjectReference](./kibana-plugin-server.savedobjectreference.md) | A reference to another saved object. |
@@ -133,6 +135,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| Variable | Description |
| --- | --- |
| [kibanaResponseFactory](./kibana-plugin-server.kibanaresponsefactory.md) | Set of helpers used to create KibanaResponse
to form HTTP response on an incoming request. Should be returned as a result of [RequestHandler](./kibana-plugin-server.requesthandler.md) execution. |
+| [validBodyOutput](./kibana-plugin-server.validbodyoutput.md) | The set of valid body.output |
## Type Aliases
@@ -156,6 +159,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [IsAuthenticated](./kibana-plugin-server.isauthenticated.md) | Return authentication status for a request. |
| [ISavedObjectsRepository](./kibana-plugin-server.isavedobjectsrepository.md) | See [SavedObjectsRepository](./kibana-plugin-server.savedobjectsrepository.md) |
| [IScopedClusterClient](./kibana-plugin-server.iscopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient
but exposes additional callAsCurrentUser
method that doesn't use credentials of the Kibana internal user (as callAsInternalUser
does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md). |
+| [KibanaRequestRouteOptions](./kibana-plugin-server.kibanarequestrouteoptions.md) | Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. |
| [KibanaResponseFactory](./kibana-plugin-server.kibanaresponsefactory.md) | Creates an object containing request response payload, HTTP headers, error details, and other data transmitted to the client. |
| [KnownHeaders](./kibana-plugin-server.knownheaders.md) | Set of well-known HTTP headers. |
| [LifecycleResponseFactory](./kibana-plugin-server.lifecycleresponsefactory.md) | Creates an object containing redirection or error response with error details, HTTP headers, and other data transmitted to the client. |
@@ -176,8 +180,9 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [ResponseError](./kibana-plugin-server.responseerror.md) | Error message and optional data send to the client in case of error. |
| [ResponseErrorAttributes](./kibana-plugin-server.responseerrorattributes.md) | Additional data to provide error details. |
| [ResponseHeaders](./kibana-plugin-server.responseheaders.md) | Http response headers to set. |
+| [RouteContentType](./kibana-plugin-server.routecontenttype.md) | The set of supported parseable Content-Types |
| [RouteMethod](./kibana-plugin-server.routemethod.md) | The set of common HTTP methods supported by Kibana routing. |
-| [RouteRegistrar](./kibana-plugin-server.routeregistrar.md) | Handler to declare a route. |
+| [RouteRegistrar](./kibana-plugin-server.routeregistrar.md) | Route handler common definition |
| [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) | Type definition for a Saved Object attribute value |
| [SavedObjectAttributeSingle](./kibana-plugin-server.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) |
| [SavedObjectsClientContract](./kibana-plugin-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError()
helpers exposed at SavedObjectsErrorHelpers
should be used to understand and manage error responses from the SavedObjectsClient
.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type
or doing substring checks on error.body.error.reason
, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.\#\#\# 503s from missing indexUnlike all other methods, create requests are supposed to succeed even when the Kibana index does not exist because it will be automatically created by elasticsearch. When that is not the case it is because Elasticsearch's action.auto_create_index
setting prevents it from being created automatically so we throw a special 503 with the intention of informing the user that their Elasticsearch settings need to be updated.See [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) |
diff --git a/docs/development/core/server/kibana-plugin-server.requesthandler.md b/docs/development/core/server/kibana-plugin-server.requesthandler.md
index 035d16c9fca3c..79abfd4293e9f 100644
--- a/docs/development/core/server/kibana-plugin-server.requesthandler.md
+++ b/docs/development/core/server/kibana-plugin-server.requesthandler.md
@@ -9,7 +9,7 @@ A function executed when route path matched requested resource path. Request han
Signature:
```typescript
-export declare type RequestHandler = (context: RequestHandlerContext, request: KibanaRequest | Type
+export interface RouteConfig | Type (route: RouteConfig , handler: RequestHandler ) => void;
+export declare type RouteRegistrar | Type , handler: RequestHandler ) => void;
```
diff --git a/docs/development/core/server/kibana-plugin-server.routeschemas.body.md b/docs/development/core/server/kibana-plugin-server.routeschemas.body.md
new file mode 100644
index 0000000000000..78a9d25c25d9d
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeschemas.body.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteSchemas](./kibana-plugin-server.routeschemas.md) > [body](./kibana-plugin-server.routeschemas.body.md)
+
+## RouteSchemas.body property
+
+Signature:
+
+```typescript
+body?: B;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routeschemas.md b/docs/development/core/server/kibana-plugin-server.routeschemas.md
new file mode 100644
index 0000000000000..77b980551a8ff
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeschemas.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteSchemas](./kibana-plugin-server.routeschemas.md)
+
+## RouteSchemas interface
+
+RouteSchemas contains the schemas for validating the different parts of a request.
+
+Signature:
+
+```typescript
+export interface RouteSchemas | Type (
- handler: RequestHandler
-): RequestHandler => {
+ handler: RequestHandler
+): RequestHandler => {
return async (
context: RequestHandlerContext,
- request: KibanaRequest (
- req: Request,
- routeSchemas?: RouteSchemas ,
- withoutSecretHeaders: boolean = true
- ) {
+ public static from<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type , withoutSecretHeaders: boolean = true) {
const requestParts = KibanaRequest.validate(req, routeSchemas);
return new KibanaRequest(
req,
@@ -77,7 +91,11 @@ export class KibanaRequest (
+ private static validate<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type | undefined
): {
@@ -113,7 +131,7 @@ export class KibanaRequest {
+export interface RouteConfig<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type ;
}
/**
@@ -133,7 +214,11 @@ export interface RouteConfig {
+export interface RouteSchemas<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type (
- route: RouteConfig ,
- handler: RequestHandler
+export type RouteRegistrar ,
+ handler: RequestHandler
) => void;
/**
@@ -62,28 +74,35 @@ export interface IRouter {
* @param route {@link RouteConfig} - a route configuration.
* @param handler {@link RequestHandler} - a function to call to respond to an incoming request
*/
- get: RouteRegistrar;
+ get: RouteRegistrar<'get'>;
/**
* Register a route handler for `POST` request.
* @param route {@link RouteConfig} - a route configuration.
* @param handler {@link RequestHandler} - a function to call to respond to an incoming request
*/
- post: RouteRegistrar;
+ post: RouteRegistrar<'post'>;
/**
* Register a route handler for `PUT` request.
* @param route {@link RouteConfig} - a route configuration.
* @param handler {@link RequestHandler} - a function to call to respond to an incoming request
*/
- put: RouteRegistrar;
+ put: RouteRegistrar<'put'>;
+
+ /**
+ * Register a route handler for `PATCH` request.
+ * @param route {@link RouteConfig} - a route configuration.
+ * @param handler {@link RequestHandler} - a function to call to respond to an incoming request
+ */
+ patch: RouteRegistrar<'patch'>;
/**
* Register a route handler for `DELETE` request.
* @param route {@link RouteConfig} - a route configuration.
* @param handler {@link RequestHandler} - a function to call to respond to an incoming request
*/
- delete: RouteRegistrar;
+ delete: RouteRegistrar<'delete'>;
/**
* Wrap a router handler to catch and converts legacy boom errors to proper custom errors.
@@ -94,16 +113,19 @@ export interface IRouter {
) => RequestHandler ;
/**
- * Returns all routes registered with the this router.
+ * Returns all routes registered with this router.
* @returns List of registered routes.
* @internal
*/
getRoutes: () => RouterRoute[];
}
-export type ContextEnhancer = (
- handler: RequestHandler
-) => RequestHandlerEnhanced ;
+export type ContextEnhancer<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType,
+ Method extends RouteMethod
+> = (handler: RequestHandler ) => RequestHandlerEnhanced ;
function getRouteFullPath(routerPath: string, routePath: string) {
// If router's path ends with slash and route's path starts with slash,
@@ -121,8 +143,8 @@ function getRouteFullPath(routerPath: string, routePath: string) {
function routeSchemasFromRouteConfig<
P extends ObjectType,
Q extends ObjectType,
- B extends ObjectType
->(route: RouteConfig , routeMethod: RouteMethod) {
+ B extends ObjectType | Type , routeMethod: RouteMethod) {
// The type doesn't allow `validate` to be undefined, but it can still
// happen when it's used from JavaScript.
if (route.validate === undefined) {
@@ -144,6 +166,49 @@ function routeSchemasFromRouteConfig<
return route.validate ? route.validate : undefined;
}
+/**
+ * Create a valid options object with "sensible" defaults + adding some validation to the options fields
+ *
+ * @param method HTTP verb for these options
+ * @param routeConfig The route config definition
+ */
+function validOptions(
+ method: RouteMethod,
+ routeConfig: RouteConfig<
+ ObjectType,
+ ObjectType,
+ ObjectType | Type ,
- handler: RequestHandler
+ route: RouteConfig ,
+ handler: RequestHandler
) => {
- const { path, options = {} } = route;
const routeSchemas = routeSchemasFromRouteConfig(route, method);
this.routes.push({
@@ -179,8 +244,8 @@ export class Router implements IRouter {
handler: this.enhanceWithContext(handler),
}),
method,
- path: getRouteFullPath(this.routerPath, path),
- options,
+ path: getRouteFullPath(this.routerPath, route.path),
+ options: validOptions(method, route),
});
};
@@ -188,6 +253,7 @@ export class Router implements IRouter {
this.post = buildMethod('post');
this.delete = buildMethod('delete');
this.put = buildMethod('put');
+ this.patch = buildMethod('patch');
}
public getRoutes() {
@@ -200,7 +266,11 @@ export class Router implements IRouter {
return wrapErrors(handler);
}
- private async handle ({
+ private async handle<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type ;
+ handler: RequestHandlerEnhanced ;
routeSchemas?: RouteSchemas ;
}) {
- let kibanaRequest: KibanaRequest = (
+export type RequestHandler<
+ P extends ObjectType,
+ Q extends ObjectType,
+ B extends ObjectType | Type (handler: RequestHandler ) => RequestHandler ;
- post: RouteRegistrar;
- put: RouteRegistrar;
+ patch: RouteRegistrar<'patch'>;
+ post: RouteRegistrar<'post'>;
+ put: RouteRegistrar<'put'>;
routerPath: string;
}
@@ -753,37 +754,38 @@ export interface IUiSettingsClient {
}
// @public
-export class KibanaRequest (req: Request, routeSchemas?: RouteSchemas , withoutSecretHeaders?: boolean): KibanaRequest ;
+ static from | Type , withoutSecretHeaders?: boolean): KibanaRequest ;
readonly headers: Headers;
// (undocumented)
readonly params: Params;
// (undocumented)
readonly query: Query;
- readonly route: RecursiveReadonly = (context: RequestHandlerContext, request: KibanaRequest | Type {
- options?: RouteConfigOptions;
+export interface RouteConfig | Type | false;
}
// @public
-export interface RouteConfigOptions {
+export interface RouteConfigOptions (route: RouteConfig , handler: RequestHandler ) => void;
+export type RouteRegistrar | Type , handler: RequestHandler ) => void;
+
+// @public
+export interface RouteSchemas | Type, TypeOf>, response: KibanaResponseFactory) => IKibanaResponse
, TypeOf, Method>, response: KibanaResponseFactory) => IKibanaResponse
RouteConfigOptions
| Additional route options [RouteConfigOptions](./kibana-plugin-server.routeconfigoptions.md). |
+| [options](./kibana-plugin-server.routeconfig.options.md) | RouteConfigOptions<Method>
| Additional route options [RouteConfigOptions](./kibana-plugin-server.routeconfigoptions.md). |
| [path](./kibana-plugin-server.routeconfig.path.md) | string
| The endpoint \_within\_ the router path to register the route. |
| [validate](./kibana-plugin-server.routeconfig.validate.md) | RouteSchemas<P, Q, B> | false
| A schema created with @kbn/config-schema
that every request will be validated against. |
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfig.options.md b/docs/development/core/server/kibana-plugin-server.routeconfig.options.md
index 12ca36da6de7c..90ad294457101 100644
--- a/docs/development/core/server/kibana-plugin-server.routeconfig.options.md
+++ b/docs/development/core/server/kibana-plugin-server.routeconfig.options.md
@@ -9,5 +9,5 @@ Additional route options [RouteConfigOptions](./kibana-plugin-server.routeconfig
Signature:
```typescript
-options?: RouteConfigOptions;
+options?: RouteConfigOptionsboolean
| A flag shows that authentication for a route: enabled
when true disabled
when falseEnabled by default. |
+| [body](./kibana-plugin-server.routeconfigoptions.body.md) | Method extends 'get' | 'options' ? undefined : RouteConfigOptionsBody
| Additional body options [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md). |
| [tags](./kibana-plugin-server.routeconfigoptions.tags.md) | readonly string[]
| Additional metadata tag strings to attach to the route. |
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.accepts.md b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.accepts.md
new file mode 100644
index 0000000000000..f48c9a1d73b11
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.accepts.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md) > [accepts](./kibana-plugin-server.routeconfigoptionsbody.accepts.md)
+
+## RouteConfigOptionsBody.accepts property
+
+A string or an array of strings with the allowed mime types for the endpoint. Use this settings to limit the set of allowed mime types. Note that allowing additional mime types not listed above will not enable them to be parsed, and if parse is true, the request will result in an error response.
+
+Default value: allows parsing of the following mime types: \* application/json \* application/\*+json \* application/octet-stream \* application/x-www-form-urlencoded \* multipart/form-data \* text/\*
+
+Signature:
+
+```typescript
+accepts?: RouteContentType | RouteContentType[] | string | string[];
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.maxbytes.md b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.maxbytes.md
new file mode 100644
index 0000000000000..3d22dc07d5bae
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.maxbytes.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md) > [maxBytes](./kibana-plugin-server.routeconfigoptionsbody.maxbytes.md)
+
+## RouteConfigOptionsBody.maxBytes property
+
+Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.
+
+Default value: The one set in the kibana.yml config file under the parameter `server.maxPayloadBytes`.
+
+Signature:
+
+```typescript
+maxBytes?: number;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.md b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.md
new file mode 100644
index 0000000000000..6ef04de459fcf
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md)
+
+## RouteConfigOptionsBody interface
+
+Additional body options for a route
+
+Signature:
+
+```typescript
+export interface RouteConfigOptionsBody
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [accepts](./kibana-plugin-server.routeconfigoptionsbody.accepts.md) | RouteContentType | RouteContentType[] | string | string[]
| A string or an array of strings with the allowed mime types for the endpoint. Use this settings to limit the set of allowed mime types. Note that allowing additional mime types not listed above will not enable them to be parsed, and if parse is true, the request will result in an error response.Default value: allows parsing of the following mime types: \* application/json \* application/\*+json \* application/octet-stream \* application/x-www-form-urlencoded \* multipart/form-data \* text/\* |
+| [maxBytes](./kibana-plugin-server.routeconfigoptionsbody.maxbytes.md) | number
| Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.Default value: The one set in the kibana.yml config file under the parameter server.maxPayloadBytes
. |
+| [output](./kibana-plugin-server.routeconfigoptionsbody.output.md) | typeof validBodyOutput[number]
| The processed payload format. The value must be one of: \* 'data' - the incoming payload is read fully into memory. If parse is true, the payload is parsed (JSON, form-decoded, multipart) based on the 'Content-Type' header. If parse is false, a raw Buffer is returned. \* 'stream' - the incoming payload is made available via a Stream.Readable interface. If the payload is 'multipart/form-data' and parse is true, field values are presented as text while files are provided as streams. File streams from a 'multipart/form-data' upload will also have a hapi property containing the filename and headers properties. Note that payload streams for multipart payloads are a synthetic interface created on top of the entire multipart content loaded into memory. To avoid loading large multipart payloads into memory, set parse to false and handle the multipart payload in the handler using a streaming parser (e.g. pez).Default value: 'data', unless no validation.body is provided in the route definition. In that case the default is 'stream' to alleviate memory pressure. |
+| [parse](./kibana-plugin-server.routeconfigoptionsbody.parse.md) | boolean | 'gunzip'
| Determines if the incoming payload is processed or presented raw. Available values: \* true - if the request 'Content-Type' matches the allowed mime types set by allow (for the whole payload as well as parts), the payload is converted into an object when possible. If the format is unknown, a Bad Request (400) error response is sent. Any known content encoding is decoded. \* false - the raw payload is returned unmodified. \* 'gunzip' - the raw payload is returned unmodified after any known content encoding is decoded.Default value: true, unless no validation.body is provided in the route definition. In that case the default is false to alleviate memory pressure. |
+
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.output.md b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.output.md
new file mode 100644
index 0000000000000..b84bc709df3ec
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.output.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md) > [output](./kibana-plugin-server.routeconfigoptionsbody.output.md)
+
+## RouteConfigOptionsBody.output property
+
+The processed payload format. The value must be one of: \* 'data' - the incoming payload is read fully into memory. If parse is true, the payload is parsed (JSON, form-decoded, multipart) based on the 'Content-Type' header. If parse is false, a raw Buffer is returned. \* 'stream' - the incoming payload is made available via a Stream.Readable interface. If the payload is 'multipart/form-data' and parse is true, field values are presented as text while files are provided as streams. File streams from a 'multipart/form-data' upload will also have a hapi property containing the filename and headers properties. Note that payload streams for multipart payloads are a synthetic interface created on top of the entire multipart content loaded into memory. To avoid loading large multipart payloads into memory, set parse to false and handle the multipart payload in the handler using a streaming parser (e.g. pez).
+
+Default value: 'data', unless no validation.body is provided in the route definition. In that case the default is 'stream' to alleviate memory pressure.
+
+Signature:
+
+```typescript
+output?: typeof validBodyOutput[number];
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.parse.md b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.parse.md
new file mode 100644
index 0000000000000..d395f67c69669
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeconfigoptionsbody.parse.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md) > [parse](./kibana-plugin-server.routeconfigoptionsbody.parse.md)
+
+## RouteConfigOptionsBody.parse property
+
+Determines if the incoming payload is processed or presented raw. Available values: \* true - if the request 'Content-Type' matches the allowed mime types set by allow (for the whole payload as well as parts), the payload is converted into an object when possible. If the format is unknown, a Bad Request (400) error response is sent. Any known content encoding is decoded. \* false - the raw payload is returned unmodified. \* 'gunzip' - the raw payload is returned unmodified after any known content encoding is decoded.
+
+Default value: true, unless no validation.body is provided in the route definition. In that case the default is false to alleviate memory pressure.
+
+Signature:
+
+```typescript
+parse?: boolean | 'gunzip';
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routecontenttype.md b/docs/development/core/server/kibana-plugin-server.routecontenttype.md
new file mode 100644
index 0000000000000..010388c7b8f17
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routecontenttype.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteContentType](./kibana-plugin-server.routecontenttype.md)
+
+## RouteContentType type
+
+The set of supported parseable Content-Types
+
+Signature:
+
+```typescript
+export declare type RouteContentType = 'application/json' | 'application/*+json' | 'application/octet-stream' | 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/*';
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routemethod.md b/docs/development/core/server/kibana-plugin-server.routemethod.md
index dd1a050708bb3..4f83344f842b3 100644
--- a/docs/development/core/server/kibana-plugin-server.routemethod.md
+++ b/docs/development/core/server/kibana-plugin-server.routemethod.md
@@ -9,5 +9,5 @@ The set of common HTTP methods supported by Kibana routing.
Signature:
```typescript
-export declare type RouteMethod = 'get' | 'post' | 'put' | 'delete';
+export declare type RouteMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options';
```
diff --git a/docs/development/core/server/kibana-plugin-server.routeregistrar.md b/docs/development/core/server/kibana-plugin-server.routeregistrar.md
index 535927dc73743..0f5f49636fdd5 100644
--- a/docs/development/core/server/kibana-plugin-server.routeregistrar.md
+++ b/docs/development/core/server/kibana-plugin-server.routeregistrar.md
@@ -4,10 +4,10 @@
## RouteRegistrar type
-Handler to declare a route.
+Route handler common definition
Signature:
```typescript
-export declare type RouteRegistrar = B
| |
+| [params](./kibana-plugin-server.routeschemas.params.md) | P
| |
+| [query](./kibana-plugin-server.routeschemas.query.md) | Q
| |
+
diff --git a/docs/development/core/server/kibana-plugin-server.routeschemas.params.md b/docs/development/core/server/kibana-plugin-server.routeschemas.params.md
new file mode 100644
index 0000000000000..3dbf9fed94dc0
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeschemas.params.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteSchemas](./kibana-plugin-server.routeschemas.md) > [params](./kibana-plugin-server.routeschemas.params.md)
+
+## RouteSchemas.params property
+
+Signature:
+
+```typescript
+params?: P;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.routeschemas.query.md b/docs/development/core/server/kibana-plugin-server.routeschemas.query.md
new file mode 100644
index 0000000000000..5be5830cb4bc8
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.routeschemas.query.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [RouteSchemas](./kibana-plugin-server.routeschemas.md) > [query](./kibana-plugin-server.routeschemas.query.md)
+
+## RouteSchemas.query property
+
+Signature:
+
+```typescript
+query?: Q;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.validbodyoutput.md b/docs/development/core/server/kibana-plugin-server.validbodyoutput.md
new file mode 100644
index 0000000000000..ea866abf887fb
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.validbodyoutput.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [validBodyOutput](./kibana-plugin-server.validbodyoutput.md)
+
+## validBodyOutput variable
+
+The set of valid body.output
+
+Signature:
+
+```typescript
+validBodyOutput: readonly ["data", "stream"]
+```
diff --git a/packages/kbn-config-schema/README.md b/packages/kbn-config-schema/README.md
index 8ba2c43b5e1fe..fd62f1b3c03b2 100644
--- a/packages/kbn-config-schema/README.md
+++ b/packages/kbn-config-schema/README.md
@@ -12,6 +12,8 @@ Kibana configuration entries providing developers with a fully typed model of th
- [`schema.number()`](#schemanumber)
- [`schema.boolean()`](#schemaboolean)
- [`schema.literal()`](#schemaliteral)
+ - [`schema.buffer()`](#schemabuffer)
+ - [`schema.stream()`](#schemastream)
- [Composite types](#composite-types)
- [`schema.arrayOf()`](#schemaarrayof)
- [`schema.object()`](#schemaobject)
@@ -173,6 +175,36 @@ const valueSchema = [
];
```
+#### `schema.buffer()`
+
+Validates input data as a NodeJS `Buffer`.
+
+__Output type:__ `Buffer`
+
+__Options:__
+ * `defaultValue: TBuffer | Reference, TypeOf>,
+ request: KibanaRequest
, TypeOf, RouteMethod>,
response: KibanaResponseFactory
) => {
try {
diff --git a/src/core/server/http/router/index.ts b/src/core/server/http/router/index.ts
index f07ad3cfe85c0..35bfb3ba9c33a 100644
--- a/src/core/server/http/router/index.ts
+++ b/src/core/server/http/router/index.ts
@@ -22,11 +22,20 @@ export { Router, RequestHandler, IRouter, RouteRegistrar } from './router';
export {
KibanaRequest,
KibanaRequestRoute,
+ KibanaRequestRouteOptions,
isRealRequest,
LegacyRequest,
ensureRawRequest,
} from './request';
-export { RouteMethod, RouteConfig, RouteConfigOptions } from './route';
+export {
+ RouteMethod,
+ RouteConfig,
+ RouteConfigOptions,
+ RouteSchemas,
+ RouteContentType,
+ RouteConfigOptionsBody,
+ validBodyOutput,
+} from './route';
export { HapiResponseAdapter } from './response_adapter';
export {
CustomHttpResponseOptions,
diff --git a/src/core/server/http/router/request.ts b/src/core/server/http/router/request.ts
index 5d3b70ba27eee..b132899910569 100644
--- a/src/core/server/http/router/request.ts
+++ b/src/core/server/http/router/request.ts
@@ -20,23 +20,32 @@
import { Url } from 'url';
import { Request } from 'hapi';
-import { ObjectType, TypeOf } from '@kbn/config-schema';
+import { ObjectType, Type, TypeOf } from '@kbn/config-schema';
+import { Stream } from 'stream';
import { deepFreeze, RecursiveReadonly } from '../../../utils';
import { Headers } from './headers';
-import { RouteMethod, RouteSchemas, RouteConfigOptions } from './route';
+import { RouteMethod, RouteSchemas, RouteConfigOptions, validBodyOutput } from './route';
import { KibanaSocket, IKibanaSocket } from './socket';
const requestSymbol = Symbol('request');
+/**
+ * Route options: If 'GET' or 'OPTIONS' method, body options won't be returned.
+ * @public
+ */
+export type KibanaRequestRouteOptions
, TypeOf>;
+ let kibanaRequest: KibanaRequest
, TypeOf, typeof request.method>;
const hapiResponseAdapter = new HapiResponseAdapter(responseToolkit);
try {
kibanaRequest = KibanaRequest.from(request, routeSchemas);
@@ -236,8 +306,9 @@ type WithoutHeadArgument
, TypeOf>,
+ request: KibanaRequest
, TypeOf, Method>,
response: KibanaResponseFactory
) => IKibanaResponse
, TypeOf>, response: KibanaResponseFactory) => IKibanaResponse
, TypeOf, Method>, response: KibanaResponseFactory) => IKibanaResponse