Skip to content

Commit

Permalink
[Cases ]Expose the bulk get cases API from the cases UI client (#154235)
Browse files Browse the repository at this point in the history
## Summary

This PR exposes the bulk get cases API from the cases UI client.

Fixes: #153926

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
cnasikas and kibanamachine authored Apr 4, 2023
1 parent 098c3fe commit 4cd0460
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 8 deletions.
14 changes: 14 additions & 0 deletions x-pack/plugins/cases/public/api/decoders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ import type {
CasesFindResponse,
CasesStatusResponse,
CasesMetricsResponse,
CasesBulkGetResponseCertainFields,
CaseResponse,
} from '../../common/api';
import {
CasesFindResponseRt,
CasesStatusResponseRt,
CasesResponseRt,
getTypeForCertainFieldsFromArray,
CasesMetricsResponseRt,
} from '../../common/api';

Expand All @@ -36,3 +40,13 @@ export const decodeCasesMetricsResponse = (metrics?: CasesMetricsResponse) =>
CasesMetricsResponseRt.decode(metrics),
fold(throwErrors(createToasterPlainError), identity)
);

export const decodeCasesBulkGetResponse = <Field extends keyof CaseResponse = keyof CaseResponse>(
res: CasesBulkGetResponseCertainFields<Field>,
fields?: string[]
) => {
const typeToDecode = getTypeForCertainFieldsFromArray(CasesResponseRt, fields);
pipe(typeToDecode.decode(res.cases), fold(throwErrors(createToasterPlainError), identity));

return res;
};
31 changes: 29 additions & 2 deletions x-pack/plugins/cases/public/api/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import { httpServiceMock } from '@kbn/core/public/mocks';
import { getCases, getCasesMetrics } from '.';
import { allCases, allCasesSnake } from '../containers/mock';
import { bulkGetCases, getCases, getCasesMetrics } from '.';
import { allCases, allCasesSnake, casesSnake } from '../containers/mock';

describe('api', () => {
beforeEach(() => {
Expand Down Expand Up @@ -47,4 +47,31 @@ describe('api', () => {
});
});
});

describe('bulkGetCases', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
http.post.mockResolvedValue({ cases: [{ title: 'test' }], errors: [] });

it('should return the correct cases with a subset of fields', async () => {
expect(await bulkGetCases({ http, params: { ids: ['test'], fields: ['title'] } })).toEqual({
cases: [{ title: 'test' }],
errors: [],
});
});

it('should return the correct cases with all fields', async () => {
http.post.mockResolvedValueOnce({ cases: casesSnake, errors: [] });
expect(await bulkGetCases({ http, params: { ids: ['test'] } })).toEqual({
cases: casesSnake,
errors: [],
});
});

it('should have been called with the correct path', async () => {
await bulkGetCases({ http, params: { ids: ['test'], fields: ['title'] } });
expect(http.post).toHaveBeenCalledWith('/internal/cases/_bulk_get', {
body: '{"ids":["test"],"fields":["title"]}',
});
});
});
});
29 changes: 28 additions & 1 deletion x-pack/plugins/cases/public/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@

import type { HttpStart } from '@kbn/core/public';
import type { Cases, CasesStatus, CasesMetrics } from '../../common/ui';
import { CASE_FIND_URL, CASE_METRICS_URL, CASE_STATUS_URL } from '../../common/constants';
import {
CASE_FIND_URL,
CASE_METRICS_URL,
CASE_STATUS_URL,
INTERNAL_BULK_GET_CASES_URL,
} from '../../common/constants';
import type {
CaseResponse,
CasesBulkGetRequestCertainFields,
CasesBulkGetResponseCertainFields,
CasesFindRequest,
CasesFindResponse,
CasesMetricsRequest,
Expand All @@ -18,6 +26,7 @@ import type {
} from '../../common/api';
import { convertAllCasesToCamel, convertToCamelCase } from './utils';
import {
decodeCasesBulkGetResponse,
decodeCasesFindResponse,
decodeCasesMetricsResponse,
decodeCasesStatusResponse,
Expand Down Expand Up @@ -58,3 +67,21 @@ export const getCasesMetrics = async ({
const res = await http.get<CasesMetricsResponse>(CASE_METRICS_URL, { signal, query });
return convertToCamelCase(decodeCasesMetricsResponse(res));
};

export const bulkGetCases = async <Field extends keyof CaseResponse = keyof CaseResponse>({
http,
signal,
params,
}: HTTPService & { params: CasesBulkGetRequestCertainFields<Field> }): Promise<
CasesBulkGetResponseCertainFields<Field>
> => {
const res = await http.post<CasesBulkGetResponseCertainFields<Field>>(
INTERNAL_BULK_GET_CASES_URL,
{
body: JSON.stringify({ ...params }),
signal,
}
);

return decodeCasesBulkGetResponse(res, params.fields);
};
30 changes: 29 additions & 1 deletion x-pack/plugins/cases/public/client/api/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { httpServiceMock } from '@kbn/core/public/mocks';
import { createClientAPI } from '.';
import { allCases, allCasesSnake } from '../../containers/mock';
import { allCases, allCasesSnake, casesSnake } from '../../containers/mock';

describe('createClientAPI', () => {
beforeEach(() => {
Expand Down Expand Up @@ -80,5 +80,33 @@ describe('createClientAPI', () => {
});
});
});

describe('bulkGet', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
const api = createClientAPI({ http });
http.post.mockResolvedValue({ cases: [{ title: 'test' }], errors: [] });

it('should return the correct cases with a subset of fields', async () => {
expect(await api.cases.bulkGet({ ids: ['test'], fields: ['title'] })).toEqual({
cases: [{ title: 'test' }],
errors: [],
});
});

it('should return the correct cases with all fields', async () => {
http.post.mockResolvedValueOnce({ cases: casesSnake, errors: [] });
expect(await api.cases.bulkGet({ ids: ['test'], fields: ['title'] })).toEqual({
cases: casesSnake,
errors: [],
});
});

it('should have been called with the correct path', async () => {
await api.cases.bulkGet({ ids: ['test'], fields: ['title'] });
expect(http.post).toHaveBeenCalledWith('/internal/cases/_bulk_get', {
body: '{"ids":["test"],"fields":["title"]}',
});
});
});
});
});
3 changes: 2 additions & 1 deletion x-pack/plugins/cases/public/client/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
} from '../../../common/api';
import { getCasesFromAlertsUrl } from '../../../common/api';
import type { Cases, CasesStatus, CasesMetrics } from '../../../common/ui';
import { getCases, getCasesMetrics, getCasesStatus } from '../../api';
import { bulkGetCases, getCases, getCasesMetrics, getCasesStatus } from '../../api';
import type { CasesUiStart } from '../../types';

export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['api'] => {
Expand All @@ -32,6 +32,7 @@ export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['ap
getCasesStatus({ http, query, signal }),
getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal): Promise<CasesMetrics> =>
getCasesMetrics({ http, signal, query }),
bulkGet: (params, signal?: AbortSignal) => bulkGetCases({ http, signal, params }),
},
};
};
7 changes: 6 additions & 1 deletion x-pack/plugins/cases/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import type { CasesUiStart } from './types';

const apiMock: jest.Mocked<CasesUiStart['api']> = {
getRelatedCases: jest.fn(),
cases: { find: jest.fn(), getCasesMetrics: jest.fn(), getCasesStatus: jest.fn() },
cases: {
find: jest.fn(),
getCasesMetrics: jest.fn(),
getCasesStatus: jest.fn(),
bulkGet: jest.fn(),
},
};

const uiMock: jest.Mocked<CasesUiStart['ui']> = {
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/cases/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import type { FilesSetup, FilesStart } from '@kbn/files-plugin/public';
import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public';
import type {
CaseResponse,
CasesBulkGetRequestCertainFields,
CasesBulkGetResponseCertainFields,
CasesByAlertId,
CasesByAlertIDRequest,
CasesFindRequest,
Expand Down Expand Up @@ -102,6 +105,10 @@ export interface CasesUiStart {
find: (query: CasesFindRequest, signal?: AbortSignal) => Promise<Cases>;
getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal) => Promise<CasesStatus>;
getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal) => Promise<CasesMetrics>;
bulkGet: <Field extends keyof CaseResponse = keyof CaseResponse>(
params: CasesBulkGetRequestCertainFields<Field>,
signal?: AbortSignal
) => Promise<CasesBulkGetResponseCertainFields<Field>>;
};
};
ui: {
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/cases/server/client/cases/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ export interface CasesSubClient {
* Retrieves multiple cases with the specified IDs.
*/
bulkGet<Field extends keyof CaseResponse = keyof CaseResponse>(
params: CasesBulkGetRequestCertainFields<Field | 'id' | 'version' | 'owner'>
): Promise<CasesBulkGetResponseCertainFields<Field | 'id' | 'version' | 'owner'>>;
params: CasesBulkGetRequestCertainFields<Field>
): Promise<CasesBulkGetResponseCertainFields<Field>>;
/**
* Pushes a specific case to an external system.
*/
Expand Down

0 comments on commit 4cd0460

Please sign in to comment.