mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
RTK APIs: Extract base query logic (#99800)
* RTK APIs: Extract base query function * Add error handling * Add return type * Use createBaseQuery in browseDashboards * Support custom manageError * Export getConfigError * Remove redundant type * data -> body
This commit is contained in:
parent
111f973242
commit
f51eacef9a
43
public/app/api/createBaseQuery.ts
Normal file
43
public/app/api/createBaseQuery.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { BaseQueryFn } from '@reduxjs/toolkit/query';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { BackendSrvRequest, getBackendSrv, isFetchError } from '@grafana/runtime';
|
||||
|
||||
interface RequestOptions extends BackendSrvRequest {
|
||||
manageError?: (err: unknown) => { error: unknown };
|
||||
body?: BackendSrvRequest['data'];
|
||||
}
|
||||
|
||||
export function createBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
|
||||
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
|
||||
try {
|
||||
const { data: responseData, ...meta } = await lastValueFrom(
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseURL + requestOptions.url,
|
||||
showErrorAlert: requestOptions.showErrorAlert ?? false,
|
||||
data: requestOptions.body,
|
||||
})
|
||||
);
|
||||
return { data: responseData, meta };
|
||||
} catch (error) {
|
||||
if (requestOptions.manageError) {
|
||||
return requestOptions.manageError(error);
|
||||
} else {
|
||||
return handleRequestError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backendSrvBaseQuery;
|
||||
}
|
||||
|
||||
export function handleRequestError(error: unknown) {
|
||||
if (isFetchError(error)) {
|
||||
return { error: new Error(error.data.message) };
|
||||
} else if (error instanceof Error) {
|
||||
return { error };
|
||||
} else {
|
||||
return { error: new Error('Unknown error') };
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { BaseQueryFn, createApi } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { AppEvents, isTruthy, locationUtil } from '@grafana/data';
|
||||
import { BackendSrvRequest, config, getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { config, getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { createBaseQuery, handleRequestError } from 'app/api/createBaseQuery';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api';
|
||||
@ -28,11 +28,6 @@ import { DashboardTreeSelection } from '../types';
|
||||
|
||||
import { PAGE_SIZE } from './services';
|
||||
|
||||
interface RequestOptions extends BackendSrvRequest {
|
||||
manageError?: (err: unknown) => { error: unknown };
|
||||
showErrorAlert?: boolean;
|
||||
}
|
||||
|
||||
interface DeleteItemsArgs {
|
||||
selectedItems: Omit<DashboardTreeSelection, 'panel' | '$all'>;
|
||||
}
|
||||
@ -64,28 +59,6 @@ interface HardDeleteDashboardArgs {
|
||||
dashboardUID: string;
|
||||
}
|
||||
|
||||
function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
|
||||
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
|
||||
// Suppress error pop-up for root (aka 'general') folder
|
||||
const isGeneralFolder = requestOptions.url === `/folders/general`;
|
||||
requestOptions = isGeneralFolder ? { ...requestOptions, showErrorAlert: false } : requestOptions;
|
||||
|
||||
try {
|
||||
const { data: responseData, ...meta } = await lastValueFrom(
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseURL + requestOptions.url,
|
||||
})
|
||||
);
|
||||
return { data: responseData, meta };
|
||||
} catch (error) {
|
||||
return requestOptions.manageError ? requestOptions.manageError(error) : { error };
|
||||
}
|
||||
}
|
||||
|
||||
return backendSrvBaseQuery;
|
||||
}
|
||||
|
||||
export interface ListFolderQueryArgs {
|
||||
page: number;
|
||||
parentUid: string | undefined;
|
||||
@ -96,7 +69,7 @@ export interface ListFolderQueryArgs {
|
||||
export const browseDashboardsAPI = createApi({
|
||||
tagTypes: ['getFolder'],
|
||||
reducerPath: 'browseDashboardsAPI',
|
||||
baseQuery: createBackendSrvBaseQuery({ baseURL: '/api' }),
|
||||
baseQuery: createBaseQuery({ baseURL: '/api' }),
|
||||
endpoints: (builder) => ({
|
||||
listFolders: builder.query<FolderListItemDTO[], ListFolderQueryArgs>({
|
||||
providesTags: (result) => result?.map((folder) => ({ type: 'getFolder', id: folder.uid })) ?? [],
|
||||
@ -117,7 +90,7 @@ export const browseDashboardsAPI = createApi({
|
||||
query: ({ title, parentUid }) => ({
|
||||
method: 'POST',
|
||||
url: '/folders',
|
||||
data: {
|
||||
body: {
|
||||
title,
|
||||
parentUid,
|
||||
},
|
||||
@ -144,7 +117,7 @@ export const browseDashboardsAPI = createApi({
|
||||
query: ({ uid, title, version }) => ({
|
||||
method: 'PUT',
|
||||
url: `/folders/${uid}`,
|
||||
data: {
|
||||
body: {
|
||||
title,
|
||||
version,
|
||||
},
|
||||
@ -167,7 +140,7 @@ export const browseDashboardsAPI = createApi({
|
||||
query: ({ folder, destinationUID }) => ({
|
||||
url: `/folders/${folder.uid}/move`,
|
||||
method: 'POST',
|
||||
data: { parentUID: destinationUID },
|
||||
body: { parentUID: destinationUID },
|
||||
}),
|
||||
onQueryStarted: ({ folder, destinationUID }, { queryFulfilled, dispatch }) => {
|
||||
const { parentUid } = folder;
|
||||
@ -256,7 +229,7 @@ export const browseDashboardsAPI = createApi({
|
||||
await baseQuery({
|
||||
url: `/folders/${folderUID}/move`,
|
||||
method: 'POST',
|
||||
data: { parentUID: destinationUID },
|
||||
body: { parentUID: destinationUID },
|
||||
});
|
||||
}
|
||||
|
||||
@ -363,7 +336,7 @@ export const browseDashboardsAPI = createApi({
|
||||
}
|
||||
throw new Error('Invalid dashboard version');
|
||||
} catch (error) {
|
||||
return { error };
|
||||
return handleRequestError(error);
|
||||
}
|
||||
},
|
||||
|
||||
@ -385,7 +358,7 @@ export const browseDashboardsAPI = createApi({
|
||||
query: ({ dashboard, overwrite, inputs, folderUid }) => ({
|
||||
method: 'POST',
|
||||
url: '/dashboards/import',
|
||||
data: {
|
||||
body: {
|
||||
dashboard,
|
||||
overwrite,
|
||||
inputs,
|
||||
@ -410,7 +383,7 @@ export const browseDashboardsAPI = createApi({
|
||||
restoreDashboard: builder.mutation<void, RestoreDashboardArgs>({
|
||||
query: ({ dashboardUID, targetFolderUID }) => ({
|
||||
url: `/dashboards/uid/${dashboardUID}/trash`,
|
||||
data: {
|
||||
body: {
|
||||
folderUid: targetFolderUID,
|
||||
},
|
||||
method: 'PATCH',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseQueryFn, createApi } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { BackendSrvRequest, config, FetchError, getBackendSrv, isFetchError } from '@grafana/runtime/src';
|
||||
import { config, FetchError, isFetchError } from '@grafana/runtime/src';
|
||||
import { createBaseQuery } from 'app/api/createBaseQuery';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createErrorNotification, createSuccessNotification } from 'app/core/copy/appNotification';
|
||||
import { t } from 'app/core/internationalization';
|
||||
@ -19,39 +19,17 @@ import {
|
||||
PublicDashboardListWithPaginationResponse,
|
||||
} from 'app/features/manage-dashboards/types';
|
||||
|
||||
type ReqOptions = {
|
||||
manageError?: (err: unknown) => { error: unknown };
|
||||
showErrorAlert?: boolean;
|
||||
};
|
||||
|
||||
function isFetchBaseQueryError(error: unknown): error is { error: FetchError } {
|
||||
return typeof error === 'object' && error != null && 'error' in error;
|
||||
}
|
||||
|
||||
const backendSrvBaseQuery =
|
||||
({ baseUrl }: { baseUrl: string }): BaseQueryFn<BackendSrvRequest & ReqOptions> =>
|
||||
async (requestOptions) => {
|
||||
try {
|
||||
const { data: responseData, ...meta } = await lastValueFrom(
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseUrl + requestOptions.url,
|
||||
showErrorAlert: requestOptions.showErrorAlert,
|
||||
})
|
||||
);
|
||||
return { data: responseData, meta };
|
||||
} catch (error) {
|
||||
return requestOptions.manageError ? requestOptions.manageError(error) : { error };
|
||||
}
|
||||
};
|
||||
|
||||
const getConfigError = (err: unknown) => ({
|
||||
export const getConfigError = (err: unknown) => ({
|
||||
error: isFetchError(err) && err.data.messageId !== 'publicdashboards.notFound' ? err : null,
|
||||
});
|
||||
|
||||
export const publicDashboardApi = createApi({
|
||||
reducerPath: 'publicDashboardApi',
|
||||
baseQuery: backendSrvBaseQuery({ baseUrl: '/api' }),
|
||||
baseQuery: createBaseQuery({ baseURL: '/api' }),
|
||||
tagTypes: ['PublicDashboard', 'AuditTablePublicDashboard', 'UsersWithActiveSessions', 'ActiveUserDashboards'],
|
||||
refetchOnMountOrArgChange: true,
|
||||
endpoints: (builder) => ({
|
||||
@ -81,7 +59,7 @@ export const publicDashboardApi = createApi({
|
||||
return {
|
||||
url: `/dashboards/uid/${dashUid}/public-dashboards`,
|
||||
method: 'POST',
|
||||
data: params.payload,
|
||||
body: params.payload,
|
||||
};
|
||||
},
|
||||
async onQueryStarted({ dashboard, payload: { share } }, { dispatch, queryFulfilled }) {
|
||||
@ -121,7 +99,7 @@ export const publicDashboardApi = createApi({
|
||||
return {
|
||||
url: `/dashboards/uid/${dashUid}/public-dashboards/${payload.uid}`,
|
||||
method: 'PATCH',
|
||||
data: payload,
|
||||
body: payload,
|
||||
};
|
||||
},
|
||||
async onQueryStarted({ dashboard }, { dispatch, queryFulfilled }) {
|
||||
@ -153,7 +131,7 @@ export const publicDashboardApi = createApi({
|
||||
return {
|
||||
url: `/dashboards/uid/${dashUid}/public-dashboards/${payload.uid}`,
|
||||
method: 'PATCH',
|
||||
data: payload,
|
||||
body: payload,
|
||||
};
|
||||
},
|
||||
async onQueryStarted({ dashboard, payload: { isEnabled } }, { dispatch, queryFulfilled }) {
|
||||
@ -193,7 +171,7 @@ export const publicDashboardApi = createApi({
|
||||
return {
|
||||
url: `/dashboards/uid/${dashUid}/public-dashboards/${payload.uid}`,
|
||||
method: 'PATCH',
|
||||
data: payload,
|
||||
body: payload,
|
||||
};
|
||||
},
|
||||
async onQueryStarted({ dashboard, payload: { share } }, { dispatch, queryFulfilled }) {
|
||||
|
@ -53,7 +53,7 @@ export function QueryTemplatesList(props: QueryTemplatesListProps) {
|
||||
return uniqBy(loadQueryMetadataResult.value, 'datasourceName').map((row) => row.datasourceName);
|
||||
}, [loadQueryMetadataResult.value]);
|
||||
|
||||
if (error) {
|
||||
if (error instanceof Error) {
|
||||
return (
|
||||
<EmptyState variant="not-found" message={`Something went wrong`}>
|
||||
{error.message}
|
||||
|
@ -1,38 +1,9 @@
|
||||
import { BaseQueryFn, createApi } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { BackendSrvRequest, getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
interface RequestOptions extends BackendSrvRequest {
|
||||
manageError?: (err: unknown) => { error: unknown };
|
||||
showErrorAlert?: boolean;
|
||||
|
||||
// rtk codegen sets this
|
||||
body?: BackendSrvRequest['data'];
|
||||
}
|
||||
|
||||
function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
|
||||
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
|
||||
try {
|
||||
const { data: responseData, ...meta } = await lastValueFrom(
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseURL + requestOptions.url,
|
||||
showErrorAlert: false,
|
||||
data: requestOptions.body,
|
||||
})
|
||||
);
|
||||
return { data: responseData, meta };
|
||||
} catch (error) {
|
||||
return requestOptions.manageError ? requestOptions.manageError(error) : { error };
|
||||
}
|
||||
}
|
||||
|
||||
return backendSrvBaseQuery;
|
||||
}
|
||||
import { createBaseQuery } from 'app/api/createBaseQuery';
|
||||
|
||||
export const baseAPI = createApi({
|
||||
reducerPath: 'migrateToCloudGeneratedAPI',
|
||||
baseQuery: createBackendSrvBaseQuery({ baseURL: '/api' }),
|
||||
baseQuery: createBaseQuery({ baseURL: '/api' }),
|
||||
endpoints: () => ({}),
|
||||
});
|
||||
|
@ -1,11 +1,14 @@
|
||||
export * from './endpoints.gen';
|
||||
import { BaseQueryFn, EndpointDefinition } from '@reduxjs/toolkit/query';
|
||||
|
||||
import { getLocalPlugins } from 'app/features/plugins/admin/api';
|
||||
import { LocalPlugin } from 'app/features/plugins/admin/types';
|
||||
|
||||
import { handleRequestError } from '../../../api/createBaseQuery';
|
||||
|
||||
import { generatedAPI } from './endpoints.gen';
|
||||
|
||||
export * from './endpoints.gen';
|
||||
|
||||
export const cloudMigrationAPI = generatedAPI
|
||||
.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
@ -16,7 +19,7 @@ export const cloudMigrationAPI = generatedAPI
|
||||
const list = await getLocalPlugins();
|
||||
return { data: list };
|
||||
} catch (error) {
|
||||
return { error: error };
|
||||
return handleRequestError(error);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
@ -1,36 +1,9 @@
|
||||
import { BaseQueryFn, createApi } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { BackendSrvRequest, getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
interface RequestOptions extends BackendSrvRequest {
|
||||
manageError?: (err: unknown) => { error: unknown };
|
||||
showErrorAlert?: boolean;
|
||||
body?: BackendSrvRequest['data'];
|
||||
}
|
||||
|
||||
function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
|
||||
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
|
||||
try {
|
||||
const { data: responseData, ...meta } = await lastValueFrom(
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseURL + requestOptions.url,
|
||||
showErrorAlert: requestOptions.showErrorAlert,
|
||||
data: requestOptions.body,
|
||||
})
|
||||
);
|
||||
return { data: responseData, meta };
|
||||
} catch (error) {
|
||||
return requestOptions.manageError ? requestOptions.manageError(error) : { error };
|
||||
}
|
||||
}
|
||||
|
||||
return backendSrvBaseQuery;
|
||||
}
|
||||
import { createBaseQuery } from 'app/api/createBaseQuery';
|
||||
|
||||
export const baseAPI = createApi({
|
||||
reducerPath: 'userPreferencesAPI',
|
||||
baseQuery: createBackendSrvBaseQuery({ baseURL: '/api' }),
|
||||
baseQuery: createBaseQuery({ baseURL: '/api' }),
|
||||
endpoints: () => ({}),
|
||||
});
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { baseQuery } from './query';
|
||||
import { createBaseQuery } from '../../../api/createBaseQuery';
|
||||
|
||||
import { BASE_URL } from './query';
|
||||
|
||||
// Currently, we are loading all query templates
|
||||
// Organizations can have maximum of 1000 query templates
|
||||
export const QUERY_LIBRARY_GET_LIMIT = 1000;
|
||||
|
||||
export const queryLibraryApi = createApi({
|
||||
baseQuery,
|
||||
baseQuery: createBaseQuery({ baseURL: BASE_URL }),
|
||||
endpoints: () => ({}),
|
||||
});
|
||||
|
@ -1,8 +1,3 @@
|
||||
import { BaseQueryFn } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { BackendSrvRequest, getBackendSrv, isFetchError } from '@grafana/runtime/src/services/backendSrv';
|
||||
|
||||
import { getAPINamespace } from '../../../api/utils';
|
||||
|
||||
/**
|
||||
@ -23,29 +18,3 @@ export enum QueryTemplateKinds {
|
||||
* @alpha
|
||||
*/
|
||||
export const BASE_URL = `/apis/${API_VERSION}/namespaces/${getAPINamespace()}`;
|
||||
|
||||
interface QueryLibraryBackendRequest extends BackendSrvRequest {
|
||||
body?: BackendSrvRequest['data'];
|
||||
}
|
||||
|
||||
export const baseQuery: BaseQueryFn<QueryLibraryBackendRequest, unknown, Error> = async (requestOptions) => {
|
||||
try {
|
||||
const responseObservable = getBackendSrv().fetch({
|
||||
url: `${BASE_URL}/${requestOptions.url ?? ''}`,
|
||||
showErrorAlert: true,
|
||||
method: requestOptions.method || 'GET',
|
||||
data: requestOptions.body,
|
||||
params: requestOptions.params,
|
||||
headers: { ...requestOptions.headers },
|
||||
});
|
||||
return await lastValueFrom(responseObservable);
|
||||
} catch (error) {
|
||||
if (isFetchError(error)) {
|
||||
return { error: new Error(error.data.message) };
|
||||
} else if (error instanceof Error) {
|
||||
return { error };
|
||||
} else {
|
||||
return { error: new Error('Unknown error') };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user