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
Show file tree
Hide file tree
Changes from 12 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
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
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
Expand Up @@ -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
Expand Up @@ -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';

Expand All @@ -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,
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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(), valueSchema),
// primitive field
schema.arrayOf(valueSchema),
]),
error: schema.maybe(schema.object({}, { unknowns: 'allow' })),
status: schema.maybe(schema.number()),
}),
},
},
},
},
async (ctx, req, res) => {
Expand All @@ -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 },
});
};

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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',
Expand All @@ -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',
Expand Down