Convert saved object routes to TypeScript (#32029) (#32405)

* Convert saved object routes to TS

* Convert some attributes to optional

* Cleanup

* Add comments as to why we added ts-ignore

* Fix lint issues

* Apply PR feedback
This commit is contained in:
Mike Côté 2019-03-04 12:35:14 -05:00 committed by GitHub
parent 07fbe6bf2b
commit 80b8d568aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 569 additions and 256 deletions

View file

@ -21,23 +21,23 @@ import Hapi from 'hapi';
import { defaultValidationErrorHandler } from '../../../../core/server/http/http_tools';
const defaultConfig = {
'kibana.index': '.kibana'
'kibana.index': '.kibana',
};
export function MockServer(config = defaultConfig) {
export function createMockServer(config: { [key: string]: any } = defaultConfig) {
const server = new Hapi.Server({
port: 0,
routes: {
validate: {
failAction: defaultValidationErrorHandler
}
}
failAction: defaultValidationErrorHandler,
},
},
});
server.config = function () {
server.config = () => {
return {
get: (key) => {
get(key: string) {
return config[key];
}
},
};
};

View file

@ -17,23 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createBulkCreateRoute } from './bulk_create';
import { MockServer } from './_mock_server';
describe('POST /api/saved_objects/_bulk_create', () => {
const savedObjectsClient = { bulkCreate: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.bulkCreate.mockImplementation(() => Promise.resolve(''));
server = new MockServer();
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -48,23 +58,27 @@ describe('POST /api/saved_objects/_bulk_create', () => {
const request = {
method: 'POST',
url: '/api/saved_objects/_bulk_create',
payload: [{
id: 'abc123',
type: 'index-pattern',
attributes: {
title: 'my_title',
payload: [
{
id: 'abc123',
type: 'index-pattern',
attributes: {
title: 'my_title',
},
},
}]
],
};
const clientResponse = {
saved_objects: [{
id: 'abc123',
type: 'index-pattern',
title: 'logstash-*',
version: 2,
references: [],
}]
saved_objects: [
{
id: 'abc123',
type: 'index-pattern',
title: 'logstash-*',
version: 2,
references: [],
},
],
};
savedObjectsClient.bulkCreate.mockImplementation(() => Promise.resolve(clientResponse));
@ -77,21 +91,24 @@ describe('POST /api/saved_objects/_bulk_create', () => {
});
it('calls upon savedObjectClient.bulkCreate', async () => {
const docs = [{
id: 'abc123',
type: 'index-pattern',
attributes: {
title: 'foo',
const docs = [
{
id: 'abc123',
type: 'index-pattern',
attributes: {
title: 'foo',
},
references: [],
},
references: [],
}, {
id: 'abc1234',
type: 'index-pattern',
attributes: {
title: 'bar',
{
id: 'abc1234',
type: 'index-pattern',
attributes: {
title: 'bar',
},
references: [],
},
references: [],
}];
];
const request = {
method: 'POST',
@ -110,14 +127,16 @@ describe('POST /api/saved_objects/_bulk_create', () => {
await server.inject({
method: 'POST',
url: '/api/saved_objects/_bulk_create?overwrite=true',
payload: [{
id: 'abc1234',
type: 'index-pattern',
attributes: {
title: 'foo',
payload: [
{
id: 'abc1234',
type: 'index-pattern',
attributes: {
title: 'foo',
},
references: [],
},
references: [],
}]
],
});
expect(savedObjectsClient.bulkCreate).toHaveBeenCalled();

View file

@ -17,9 +17,31 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectAttributes, SavedObjectsClient } from '../';
import { Prerequisites, SavedObjectReference, WithoutQueryAndParams } from './types';
export const createBulkCreateRoute = prereqs => ({
interface SavedObject {
type: string;
id?: string;
attributes: SavedObjectAttributes;
version?: string;
migrationVersion?: { [key: string]: string };
references: SavedObjectReference[];
}
interface BulkCreateRequest extends WithoutQueryAndParams<Hapi.Request> {
pre: {
savedObjectsClient: SavedObjectsClient;
};
query: {
overwrite: boolean;
};
payload: SavedObject[];
}
export const createBulkCreateRoute = (prereqs: Prerequisites) => ({
path: '/api/saved_objects/_bulk_create',
method: 'POST',
config: {
@ -37,18 +59,19 @@ export const createBulkCreateRoute = prereqs => ({
attributes: Joi.object().required(),
version: Joi.string(),
migrationVersion: Joi.object().optional(),
references: Joi.array().items(
Joi.object()
.keys({
references: Joi.array()
.items(
Joi.object().keys({
name: Joi.string().required(),
type: Joi.string().required(),
id: Joi.string().required(),
}),
).default([]),
})
)
.default([]),
}).required()
),
},
handler(request) {
handler(request: BulkCreateRequest) {
const { overwrite } = request.query;
const { savedObjectsClient } = request.pre;

View file

@ -17,22 +17,32 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createBulkGetRoute } from './bulk_get';
import { MockServer } from './_mock_server';
describe('POST /api/saved_objects/_bulk_get', () => {
const savedObjectsClient = { bulkGet: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.bulkGet.mockImplementation(() => Promise.resolve(''));
server = new MockServer();
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -47,20 +57,24 @@ describe('POST /api/saved_objects/_bulk_get', () => {
const request = {
method: 'POST',
url: '/api/saved_objects/_bulk_get',
payload: [{
id: 'abc123',
type: 'index-pattern'
}]
payload: [
{
id: 'abc123',
type: 'index-pattern',
},
],
};
const clientResponse = {
saved_objects: [{
id: 'abc123',
type: 'index-pattern',
title: 'logstash-*',
version: 'foo',
references: [],
}]
saved_objects: [
{
id: 'abc123',
type: 'index-pattern',
title: 'logstash-*',
version: 'foo',
references: [],
},
],
};
savedObjectsClient.bulkGet.mockImplementation(() => Promise.resolve(clientResponse));
@ -73,15 +87,17 @@ describe('POST /api/saved_objects/_bulk_get', () => {
});
it('calls upon savedObjectClient.bulkGet', async () => {
const docs = [{
id: 'abc123',
type: 'index-pattern'
}];
const docs = [
{
id: 'abc123',
type: 'index-pattern',
},
];
const request = {
method: 'POST',
url: '/api/saved_objects/_bulk_get',
payload: docs
payload: docs,
};
await server.inject(request);

View file

@ -17,23 +17,38 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectsClient } from '../';
import { Prerequisites } from './types';
export const createBulkGetRoute = (prereqs) => ({
interface BulkGetRequest extends Hapi.Request {
pre: {
savedObjectsClient: SavedObjectsClient;
};
payload: Array<{
type: string;
id: string;
}>;
}
export const createBulkGetRoute = (prereqs: Prerequisites) => ({
path: '/api/saved_objects/_bulk_get',
method: 'POST',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
payload: Joi.array().items(Joi.object({
type: Joi.string().required(),
id: Joi.string().required(),
}).required())
payload: Joi.array().items(
Joi.object({
type: Joi.string().required(),
id: Joi.string().required(),
}).required()
),
},
handler(request) {
handler(request: BulkGetRequest) {
const { savedObjectsClient } = request.pre;
return savedObjectsClient.bulkGet(request.payload);
}
}
},
},
});

View file

@ -17,23 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createCreateRoute } from './create';
import { MockServer } from './_mock_server';
describe('POST /api/saved_objects/{type}', () => {
const savedObjectsClient = { create: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.create.mockImplementation(() => Promise.resolve(''));
server = new MockServer();
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -50,9 +60,9 @@ describe('POST /api/saved_objects/{type}', () => {
url: '/api/saved_objects/index-pattern',
payload: {
attributes: {
title: 'Testing'
}
}
title: 'Testing',
},
},
};
const clientResponse = {
@ -75,7 +85,7 @@ describe('POST /api/saved_objects/{type}', () => {
const request = {
method: 'POST',
url: '/api/saved_objects/index-pattern',
payload: {}
payload: {},
};
const { statusCode, payload } = await server.inject(request);
@ -93,9 +103,9 @@ describe('POST /api/saved_objects/{type}', () => {
url: '/api/saved_objects/index-pattern',
payload: {
attributes: {
title: 'Testing'
}
}
title: 'Testing',
},
},
};
await server.inject(request);
@ -114,9 +124,9 @@ describe('POST /api/saved_objects/{type}', () => {
url: '/api/saved_objects/index-pattern/logstash-*',
payload: {
attributes: {
title: 'Testing'
}
}
title: 'Testing',
},
},
};
await server.inject(request);

View file

@ -17,9 +17,30 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectAttributes, SavedObjectsClient } from '../';
import { Prerequisites, SavedObjectReference, WithoutQueryAndParams } from './types';
export const createCreateRoute = prereqs => {
interface CreateRequest extends WithoutQueryAndParams<Hapi.Request> {
pre: {
savedObjectsClient: SavedObjectsClient;
};
query: {
overwrite: boolean;
};
params: {
type: string;
id?: string;
};
payload: {
attributes: SavedObjectAttributes;
migrationVersion?: { [key: string]: string };
references: SavedObjectReference[];
};
}
export const createCreateRoute = (prereqs: Prerequisites) => {
return {
path: '/api/saved_objects/{type}/{id?}',
method: 'POST',
@ -40,17 +61,18 @@ export const createCreateRoute = prereqs => {
payload: Joi.object({
attributes: Joi.object().required(),
migrationVersion: Joi.object().optional(),
references: Joi.array().items(
Joi.object()
.keys({
references: Joi.array()
.items(
Joi.object().keys({
name: Joi.string().required(),
type: Joi.string().required(),
id: Joi.string().required(),
}),
).default([]),
})
)
.default([]),
}).required(),
},
handler(request) {
handler(request: CreateRequest) {
const { savedObjectsClient } = request.pre;
const { type, id } = request.params;
const { overwrite } = request.query;

View file

@ -17,23 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createDeleteRoute } from './delete';
import { MockServer } from './_mock_server';
describe('DELETE /api/saved_objects/{type}/{id}', () => {
const savedObjectsClient = { delete: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.delete.mockImplementation(() => Promise.resolve('{}'));
server = new MockServer();
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -47,7 +57,7 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
it('formats successful response', async () => {
const request = {
method: 'DELETE',
url: '/api/saved_objects/index-pattern/logstash-*'
url: '/api/saved_objects/index-pattern/logstash-*',
};
const { payload, statusCode } = await server.inject(request);
@ -60,7 +70,7 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
it('calls upon savedObjectClient.delete', async () => {
const request = {
method: 'DELETE',
url: '/api/saved_objects/index-pattern/logstash-*'
url: '/api/saved_objects/index-pattern/logstash-*',
};
await server.inject(request);

View file

@ -17,24 +17,39 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectsClient } from '../';
import { Prerequisites } from './types';
export const createDeleteRoute = (prereqs) => ({
interface DeleteRequest extends Hapi.Request {
pre: {
savedObjectsClient: SavedObjectsClient;
};
params: {
type: string;
id: string;
};
}
export const createDeleteRoute = (prereqs: Prerequisites) => ({
path: '/api/saved_objects/{type}/{id}',
method: 'DELETE',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
params: Joi.object().keys({
type: Joi.string().required(),
id: Joi.string().required(),
}).required()
params: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
})
.required(),
},
handler(request) {
handler(request: DeleteRequest) {
const { savedObjectsClient } = request.pre;
const { type, id } = request.params;
return savedObjectsClient.delete(type, id);
}
}
},
},
});

View file

@ -1,50 +0,0 @@
/*
* 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 Joi from 'joi';
import { keysToCamelCaseShallow } from '../../../utils/case_conversion';
export const createFindRoute = (prereqs) => ({
path: '/api/saved_objects/_find',
method: 'GET',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
query: Joi.object().keys({
per_page: Joi.number().min(0).default(20),
page: Joi.number().min(0).default(1),
type: Joi.array().items(Joi.string()).single().required(),
search: Joi.string().allow('').optional(),
default_search_operator: Joi.string().valid('OR', 'AND').default('OR'),
search_fields: Joi.array().items(Joi.string()).single(),
sort_field: Joi.array().items(Joi.string()).single(),
has_reference: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
}).optional(),
fields: Joi.array().items(Joi.string()).single()
}).default()
},
handler(request) {
const options = keysToCamelCaseShallow(request.query);
return request.pre.savedObjectsClient.find(options);
}
}
});

View file

@ -17,23 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createFindRoute } from './find';
import { MockServer } from './_mock_server';
describe('GET /api/saved_objects/_find', () => {
const savedObjectsClient = { find: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.find.mockImplementation(() => Promise.resolve(''));
server = new MockServer();
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -47,7 +57,7 @@ describe('GET /api/saved_objects/_find', () => {
it('returns with status 400 when type is missing', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find'
url: '/api/saved_objects/_find',
};
const { payload, statusCode } = await server.inject(request);
@ -63,7 +73,7 @@ describe('GET /api/saved_objects/_find', () => {
it('formats successful response', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=index-pattern'
url: '/api/saved_objects/_find?type=index-pattern',
};
const clientResponse = {
@ -76,15 +86,16 @@ describe('GET /api/saved_objects/_find', () => {
timeFieldName: '@timestamp',
notExpandable: true,
references: [],
}, {
},
{
type: 'index-pattern',
id: 'stocks-*',
title: 'stocks-*',
timeFieldName: '@timestamp',
notExpandable: true,
references: [],
}
]
},
],
};
savedObjectsClient.find.mockImplementation(() => Promise.resolve(clientResponse));
@ -99,7 +110,7 @@ describe('GET /api/saved_objects/_find', () => {
it('calls upon savedObjectClient.find with defaults', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&type=bar'
url: '/api/saved_objects/_find?type=foo&type=bar',
};
await server.inject(request);
@ -107,13 +118,18 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['foo', 'bar'], defaultSearchOperator: 'OR' });
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['foo', 'bar'],
defaultSearchOperator: 'OR',
});
});
it('accepts the query parameter page/per_page', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&per_page=10&page=50'
url: '/api/saved_objects/_find?type=foo&per_page=10&page=50',
};
await server.inject(request);
@ -127,35 +143,7 @@ describe('GET /api/saved_objects/_find', () => {
it('accepts the query parameter search_fields', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&search_fields=title'
};
await server.inject(request);
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({ perPage: 20, page: 1, searchFields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' });
});
it('accepts the query parameter fields as a string', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&fields=title'
};
await server.inject(request);
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({ perPage: 20, page: 1, fields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' });
});
it('accepts the query parameter fields as an array', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&fields=title&fields=description'
url: '/api/saved_objects/_find?type=foo&search_fields=title',
};
await server.inject(request);
@ -164,14 +152,58 @@ describe('GET /api/saved_objects/_find', () => {
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20, page: 1, fields: ['title', 'description'], type: ['foo'], defaultSearchOperator: 'OR'
perPage: 20,
page: 1,
searchFields: ['title'],
type: ['foo'],
defaultSearchOperator: 'OR',
});
});
it('accepts the query parameter fields as a string', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&fields=title',
};
await server.inject(request);
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
fields: ['title'],
type: ['foo'],
defaultSearchOperator: 'OR',
});
});
it('accepts the query parameter fields as an array', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=foo&fields=title&fields=description',
};
await server.inject(request);
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
fields: ['title', 'description'],
type: ['foo'],
defaultSearchOperator: 'OR',
});
});
it('accepts the query parameter type as a string', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=index-pattern'
url: '/api/saved_objects/_find?type=index-pattern',
};
await server.inject(request);
@ -179,13 +211,18 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern'], defaultSearchOperator: 'OR' });
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
defaultSearchOperator: 'OR',
});
});
it('accepts the query parameter type as an array', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/_find?type=index-pattern&type=visualization'
url: '/api/saved_objects/_find?type=index-pattern&type=visualization',
};
await server.inject(request);
@ -193,6 +230,11 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern', 'visualization'], defaultSearchOperator: 'OR' });
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern', 'visualization'],
defaultSearchOperator: 'OR',
});
});
});

View file

@ -0,0 +1,100 @@
/*
* 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 Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectsClient } from '../';
import { Prerequisites, WithoutQueryAndParams } from './types';
interface FindRequest extends WithoutQueryAndParams<Hapi.Request> {
pre: {
savedObjectsClient: SavedObjectsClient;
};
query: {
per_page: number;
page: number;
type: string[];
search?: string;
default_search_operator: 'AND' | 'OR';
search_fields?: string[];
sort_field?: string;
has_reference?: {
type: string;
id: string;
};
fields?: string[];
};
}
export const createFindRoute = (prereqs: Prerequisites) => ({
path: '/api/saved_objects/_find',
method: 'GET',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
query: Joi.object()
.keys({
per_page: Joi.number()
.min(0)
.default(20),
page: Joi.number()
.min(0)
.default(1),
type: Joi.array()
.items(Joi.string())
.single()
.required(),
search: Joi.string()
.allow('')
.optional(),
default_search_operator: Joi.string()
.valid('OR', 'AND')
.default('OR'),
search_fields: Joi.array()
.items(Joi.string())
.single(),
sort_field: Joi.string(),
has_reference: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
})
.optional(),
fields: Joi.array()
.items(Joi.string())
.single(),
})
.default(),
},
handler(request: FindRequest) {
const query = request.query;
return request.pre.savedObjectsClient.find({
perPage: query.per_page,
page: query.page,
type: query.type,
search: query.search,
defaultSearchOperator: query.default_search_operator,
searchFields: query.search_fields,
sortField: query.sort_field,
hasReference: query.has_reference,
fields: query.fields,
});
},
},
});

View file

@ -17,23 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createGetRoute } from './get';
import { MockServer } from './_mock_server';
describe('GET /api/saved_objects/{type}/{id}', () => {
const savedObjectsClient = { get: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
savedObjectsClient.get.mockImplementation(() => Promise.resolve(true));
server = new MockServer();
savedObjectsClient.get.mockImplementation(() => Promise.resolve(''));
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -47,7 +57,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
it('formats successful response', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/index-pattern/logstash-*'
url: '/api/saved_objects/index-pattern/logstash-*',
};
const clientResponse = {
id: 'logstash-*',
@ -69,7 +79,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
it('calls upon savedObjectClient.get', async () => {
const request = {
method: 'GET',
url: '/api/saved_objects/index-pattern/logstash-*'
url: '/api/saved_objects/index-pattern/logstash-*',
};
await server.inject(request);

View file

@ -17,24 +17,39 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectsClient } from '../';
import { Prerequisites } from './types';
export const createGetRoute = (prereqs) => ({
interface GetRequest extends Hapi.Request {
pre: {
savedObjectsClient: SavedObjectsClient;
};
params: {
type: string;
id: string;
};
}
export const createGetRoute = (prereqs: Prerequisites) => ({
path: '/api/saved_objects/{type}/{id}',
method: 'GET',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
params: Joi.object().keys({
type: Joi.string().required(),
id: Joi.string().required(),
}).required()
params: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
})
.required(),
},
handler(request) {
handler(request: GetRequest) {
const { savedObjectsClient } = request.pre;
const { type, id } = request.params;
return savedObjectsClient.get(type, id);
}
}
},
},
});

View file

@ -0,0 +1,36 @@
/*
* 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 Hapi from 'hapi';
import { SavedObjectsClient } from '../';
export interface SavedObjectReference {
name: string;
type: string;
id: string;
}
export interface Prerequisites {
getSavedObjectsClient: {
assign: string;
method: (req: Hapi.Request) => SavedObjectsClient;
};
}
export type WithoutQueryAndParams<T> = Pick<T, Exclude<keyof T, 'query' | 'params'>>;

View file

@ -17,24 +17,33 @@
* under the License.
*/
import Hapi from 'hapi';
import { createMockServer } from './_mock_server';
import { createUpdateRoute } from './update';
import { MockServer } from './_mock_server';
describe('PUT /api/saved_objects/{type}/{id?}', () => {
const savedObjectsClient = { update: jest.fn() };
let server;
let server: Hapi.Server;
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
bulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
server = new MockServer();
savedObjectsClient.update.mockImplementation(() => Promise.resolve(true));
savedObjectsClient.update.mockImplementation(() => Promise.resolve(''));
server = createMockServer();
const prereqs = {
getSavedObjectsClient: {
assign: 'savedObjectsClient',
method() {
return savedObjectsClient;
}
},
},
};
@ -51,10 +60,10 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => {
url: '/api/saved_objects/index-pattern/logstash-*',
payload: {
attributes: {
title: 'Testing'
title: 'Testing',
},
references: [],
}
},
};
const clientResponse = {
@ -81,7 +90,7 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => {
payload: {
attributes: { title: 'Testing' },
version: 'foo',
}
},
};
await server.inject(request);

View file

@ -17,40 +17,61 @@
* under the License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { SavedObjectAttributes, SavedObjectsClient } from '../';
import { Prerequisites, SavedObjectReference } from './types';
export const createUpdateRoute = (prereqs) => {
interface UpdateRequest extends Hapi.Request {
pre: {
savedObjectsClient: SavedObjectsClient;
};
params: {
type: string;
id: string;
};
payload: {
attributes: SavedObjectAttributes;
version?: string;
references: SavedObjectReference[];
};
}
export const createUpdateRoute = (prereqs: Prerequisites) => {
return {
path: '/api/saved_objects/{type}/{id}',
method: 'PUT',
config: {
pre: [prereqs.getSavedObjectsClient],
validate: {
params: Joi.object().keys({
type: Joi.string().required(),
id: Joi.string().required(),
}).required(),
params: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
})
.required(),
payload: Joi.object({
attributes: Joi.object().required(),
version: Joi.string(),
references: Joi.array().items(
Joi.object()
.keys({
references: Joi.array()
.items(
Joi.object().keys({
name: Joi.string().required(),
type: Joi.string().required(),
id: Joi.string().required(),
}),
).default([]),
}).required()
})
)
.default([]),
}).required(),
},
handler(request) {
handler(request: UpdateRequest) {
const { savedObjectsClient } = request.pre;
const { type, id } = request.params;
const { attributes, version, references } = request.payload;
const options = { version, references };
return savedObjectsClient.update(type, id, attributes, options);
}
}
},
},
};
};