Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data views] Field editor endpoint versioning and schema validation #159626

Merged
merged 15 commits into from
Jun 30, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import { act } from 'react-dom/test-utils';
import { ReactWrapper } from 'enzyme';
import { registerTestBed, TestBed } from '@kbn/test-jest-helpers';

import { API_BASE_PATH } from '../../common/constants';
import { FIELD_PREVIEW_PATH } from '../../common/constants';
import { Context } from '../../public/components/field_editor_context';
import {
FieldEditorFlyoutContent,
@@ -118,7 +118,7 @@ const getActions = (testBed: TestBed) => {

while (i >= 0) {
const request = server.requests[i];
if (request.method === 'POST' && request.url === `${API_BASE_PATH}/field_preview`) {
if (request.method === 'POST' && request.url === FIELD_PREVIEW_PATH) {
return {
...request,
requestBody: JSON.parse(JSON.parse(request.requestBody).body),
4 changes: 3 additions & 1 deletion src/plugins/data_view_field_editor/common/constants.ts
Original file line number Diff line number Diff line change
@@ -6,4 +6,6 @@
* Side Public License, v 1.
*/

export const API_BASE_PATH = '/api/index_pattern_field_editor';
export const FIELD_PREVIEW_PATH = '/internal/data_view_field_editor/field_preview';

export const INITIAL_REST_VERSION = '1';
8 changes: 6 additions & 2 deletions src/plugins/data_view_field_editor/public/lib/api.ts
Original file line number Diff line number Diff line change
@@ -6,7 +6,10 @@
* Side Public License, v 1.
*/
import { HttpSetup } from '@kbn/core/public';
import { API_BASE_PATH } from '../../common/constants';
import {
FIELD_PREVIEW_PATH as path,
INITIAL_REST_VERSION as version,
} from '../../common/constants';
import { sendRequest } from '../shared_imports';
import { PainlessExecuteContext, FieldPreviewResponse } from '../components/preview';

@@ -23,14 +26,15 @@ export const initApi = (httpClient: HttpSetup) => {
document: Record<string, unknown>;
}) => {
return sendRequest<FieldPreviewResponse>(httpClient, {
path: `${API_BASE_PATH}/field_preview`,
path,
method: 'post',
body: {
index,
context,
script,
document,
},
version,
});
};

Original file line number Diff line number Diff line change
@@ -7,9 +7,7 @@
*/

import { schema } from '@kbn/config-schema';
import { HttpResponsePayload } from '@kbn/core/server';

import { API_BASE_PATH } from '../../common/constants';
import { FIELD_PREVIEW_PATH as path } from '../../common/constants';
import { RouteDependencies } from '../types';
import { handleEsError } from '../shared_imports';

@@ -29,12 +27,35 @@ const bodySchema = schema.object({
document: schema.object({}, { unknowns: 'allow' }),
});

const geoPoint = schema.object({
type: schema.literal('Point'),
coordinates: schema.arrayOf(schema.number(), { minSize: 2, maxSize: 2 }),
});

const valueSchema = schema.oneOf([schema.boolean(), schema.number(), schema.string(), geoPoint]);

export const registerFieldPreviewRoute = ({ router }: RouteDependencies): void => {
router.post(
router.versioned.post({ path, access: 'internal' }).addVersion(
{
path: `${API_BASE_PATH}/field_preview`,
version: '1',
validate: {
body: bodySchema,
request: {
body: bodySchema,
},
response: {
200: {
body: schema.object({
values: schema.oneOf([
// composite field
schema.recordOf(schema.string(), schema.arrayOf(valueSchema)),
// primitive field
schema.arrayOf(valueSchema),
]),
error: schema.maybe(schema.object({}, { unknowns: 'allow' })),
status: schema.maybe(schema.number()),
}),
},
},
},
},
async (ctx, req, res) => {
@@ -51,17 +72,17 @@ export const registerFieldPreviewRoute = ({ router }: RouteDependencies): void =

try {
// client types need to be update to support this request format
// when it does, supply response types
// @ts-expect-error
const { result } = await client.asCurrentUser.scriptsPainlessExecute(body);
const fieldValue = result as HttpResponsePayload;

return res.ok({ body: { values: fieldValue } });
return res.ok({ body: { values: result } });
} catch (error) {
// Assume invalid painless script was submitted
// Return 200 with error object
const handleCustomError = () => {
return res.ok({
body: { values: [], ...error.body },
body: { values: [], error: error.body?.error, status: error.statusCode },
});
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -8,9 +8,13 @@

import expect from '@kbn/expect';

import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { getErrorCodeFromErrorReason } from '@kbn/data-view-field-editor-plugin/public/lib/runtime_field_validation';
import {
FIELD_PREVIEW_PATH,
INITIAL_REST_VERSION,
} from '@kbn/data-view-field-editor-plugin/common/constants';
import { FtrProviderContext } from '../../ftr_provider_context';
import { API_BASE_PATH } from './constants';

const INDEX_NAME = 'api-integration-test-field-preview';

@@ -83,7 +87,8 @@ export default function ({ getService }: FtrProviderContext) {
};

const { body: response } = await supertest
.post(`${API_BASE_PATH}/field_preview`)
.post(FIELD_PREVIEW_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION)
.send(payload)
.set('kbn-xsrf', 'xxx')
.expect(200);
@@ -96,7 +101,8 @@ export default function ({ getService }: FtrProviderContext) {
describe('payload validation', () => {
it('should require a script', async () => {
await supertest
.post(`${API_BASE_PATH}/field_preview`)
.post(FIELD_PREVIEW_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION)
.send({
context: 'keyword_field',
index: INDEX_NAME,
@@ -107,7 +113,8 @@ export default function ({ getService }: FtrProviderContext) {

it('should require a context', async () => {
await supertest
.post(`${API_BASE_PATH}/field_preview`)
.post(FIELD_PREVIEW_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION)
.send({
script: { source: 'emit("hello")' },
index: INDEX_NAME,
@@ -118,7 +125,8 @@ export default function ({ getService }: FtrProviderContext) {

it('should require an index', async () => {
await supertest
.post(`${API_BASE_PATH}/field_preview`)
.post(FIELD_PREVIEW_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION)
.send({
script: { source: 'emit("hello")' },
context: 'keyword_field',
@@ -134,7 +142,8 @@ export default function ({ getService }: FtrProviderContext) {
// If this test fail we'll need to update the "getErrorCodeFromErrorReason()" handler
it('should detect a script casting error', async () => {
const { body: response } = await supertest
.post(`${API_BASE_PATH}/field_preview`)
.post(FIELD_PREVIEW_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION)
.send({
script: { source: 'emit(123)' }, // We send a long but the type is "keyword"
context: 'keyword_field',