Api Dry Run
This commit is contained in:
parent
3dd7713aac
commit
c9914c4246
|
|
@ -57,6 +57,13 @@ export const deleteActionSuccess = (payload: { id: string }) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const dryRunAction = (payload: RestAction) => {
|
||||
return {
|
||||
type: ReduxActionTypes.DRY_RUN_ACTION,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
createAction: createActionRequest,
|
||||
fetchActions,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import API, { HttpMethod } from "./Api";
|
|||
import { ApiResponse, GenericApiResponse, ResponseMeta } from "./ApiResponses";
|
||||
import { APIRequest } from "../constants/ApiConstants";
|
||||
import { AxiosPromise } from "axios";
|
||||
import { Datasource } from "./DatasourcesApi";
|
||||
|
||||
export interface CreateActionRequest<T> extends APIRequest {
|
||||
datasourceId: string;
|
||||
|
|
@ -51,14 +52,14 @@ export interface ActionCreateUpdateResponse extends ApiResponse {
|
|||
export interface RestAction {
|
||||
id: string;
|
||||
name: string;
|
||||
datasourceId: string;
|
||||
datasource: Pick<Datasource, "id"> | Omit<Datasource, "id">;
|
||||
pluginId: string;
|
||||
pageId?: string;
|
||||
actionConfiguration: Partial<APIConfigRequest>;
|
||||
}
|
||||
|
||||
export interface ExecuteActionRequest extends APIRequest {
|
||||
actionId: string;
|
||||
action: Pick<RestAction, "id"> | Omit<RestAction, "id">;
|
||||
params?: Property[];
|
||||
}
|
||||
|
||||
|
|
@ -68,10 +69,22 @@ export interface ExecuteActionResponse extends ApiResponse {
|
|||
}
|
||||
|
||||
export interface ActionApiResponse {
|
||||
responseMeta?: ResponseMeta;
|
||||
body: JSON;
|
||||
responseMeta: ResponseMeta;
|
||||
data: {
|
||||
body: object;
|
||||
headers: Record<string, string[]>;
|
||||
statusCode: string | number;
|
||||
};
|
||||
clientMeta: {
|
||||
duration: string;
|
||||
size: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ActionResponse {
|
||||
body: object;
|
||||
headers: Record<string, string[]>;
|
||||
statusCode: string;
|
||||
statusCode: string | number;
|
||||
duration: string;
|
||||
size: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
REQUEST_HEADERS,
|
||||
AUTH_CREDENTIALS,
|
||||
} from "../constants/ApiConstants";
|
||||
import { ActionApiResponse, ActionResponse } from "./ActionAPI";
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: BASE_URL,
|
||||
|
|
@ -20,10 +21,12 @@ axiosInstance.interceptors.request.use((config: any) => {
|
|||
return { ...config, timer: performance.now() };
|
||||
});
|
||||
|
||||
const makeExecuteActionResponse = (response: any) => ({
|
||||
const makeExecuteActionResponse = (response: any): ActionApiResponse => ({
|
||||
...response.data,
|
||||
size: response.headers["content-length"],
|
||||
duration: Number(performance.now() - response.config.timer).toFixed(),
|
||||
clientMeta: {
|
||||
size: response.headers["content-length"],
|
||||
duration: Number(performance.now() - response.config.timer).toFixed(),
|
||||
},
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { BaseTabbedView } from "../designSystems/appsmith/TabbedView";
|
|||
import styled from "styled-components";
|
||||
import { AppState } from "../../reducers";
|
||||
import CodeEditor from "./CodeEditor";
|
||||
import { ActionApiResponse } from "../../api/ActionAPI";
|
||||
import { ActionResponse } from "../../api/ActionAPI";
|
||||
import { formatBytes } from "../../utils/helpers";
|
||||
|
||||
const ResponseWrapper = styled.div`
|
||||
|
|
@ -62,7 +62,7 @@ const LoadingScreen = styled.div`
|
|||
|
||||
interface ReduxStateProps {
|
||||
responses: {
|
||||
[id: string]: ActionApiResponse;
|
||||
[id: string]: ActionResponse;
|
||||
};
|
||||
isRunning: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export const ReduxActionTypes: { [key: string]: string } = {
|
|||
UPDATE_ACTION_SUCCESS: "UPDATE_ACTION_SUCCESS",
|
||||
DELETE_ACTION_INIT: "DELETE_ACTION_INIT",
|
||||
DELETE_ACTION_SUCCESS: "DELETE_ACTION_SUCCESS",
|
||||
DRY_RUN_ACTION: "DRY_RUN_ACTION",
|
||||
FETCH_DATASOURCES_INIT: "FETCH_DATASOURCES_INIT",
|
||||
FETCH_DATASOURCES_SUCCESS: "FETCH_DATASOURCES_SUCCESS",
|
||||
CREATE_DATASOURCE_INIT: "CREATE_DATASOURCE_INIT",
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
name="actionConfiguration.httpMethod"
|
||||
options={HTTP_METHOD_OPTIONS}
|
||||
/>
|
||||
<DatasourcesField name="datasourceId" />
|
||||
<DatasourcesField name="datasource.id" />
|
||||
<ForwardSlash />
|
||||
<TextField
|
||||
placeholderMessage="API Path"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
executeAction,
|
||||
deleteAction,
|
||||
updateAction,
|
||||
dryRunAction,
|
||||
} from "../../actions/actionActions";
|
||||
import { RestAction } from "../../api/ActionAPI";
|
||||
import { AppState } from "../../reducers";
|
||||
|
|
@ -24,6 +25,7 @@ interface ReduxActionProps {
|
|||
submitForm: (name: string) => void;
|
||||
createAction: (values: RestAction) => void;
|
||||
runAction: (id: string) => void;
|
||||
dryRunAction: (data: RestAction) => void;
|
||||
deleteAction: (id: string) => void;
|
||||
updateAction: (data: RestAction) => void;
|
||||
initialize: (formName: string, data?: Partial<RestAction>) => void;
|
||||
|
|
@ -78,7 +80,12 @@ class ApiEditor extends React.Component<Props> {
|
|||
this.props.deleteAction(this.props.match.params.id);
|
||||
};
|
||||
handleRunClick = () => {
|
||||
this.props.runAction(this.props.match.params.id);
|
||||
const { formData } = this.props;
|
||||
if (formData.id) {
|
||||
this.props.runAction(this.props.match.params.id);
|
||||
} else {
|
||||
this.props.dryRunAction(formData);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
@ -117,6 +124,7 @@ const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
|
|||
},
|
||||
]),
|
||||
),
|
||||
dryRunAction: (data: RestAction) => dispatch(dryRunAction(data)),
|
||||
deleteAction: (id: string) => dispatch(deleteAction({ id })),
|
||||
updateAction: (data: RestAction) => dispatch(updateAction({ data })),
|
||||
initialize: (formName: string, data?: Partial<RestAction>) =>
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@ import {
|
|||
ReduxActionTypes,
|
||||
ReduxAction,
|
||||
} from "../../constants/ReduxActionConstants";
|
||||
import { ActionApiResponse } from "../../api/ActionAPI";
|
||||
import { ActionResponse } from "../../api/ActionAPI";
|
||||
import { ActionDataState } from "./actionsReducer";
|
||||
|
||||
const initialState: APIDataState = {};
|
||||
|
||||
export interface APIDataState {
|
||||
[id: string]: ActionApiResponse;
|
||||
[id: string]: ActionResponse;
|
||||
}
|
||||
|
||||
const apiDataReducer = createReducer(initialState, {
|
||||
[ReduxActionTypes.EXECUTE_ACTION_SUCCESS]: (
|
||||
state: ActionDataState,
|
||||
action: ReduxAction<{ [id: string]: ActionApiResponse }>,
|
||||
action: ReduxAction<{ [id: string]: ActionResponse }>,
|
||||
) => ({ ...state, ...action.payload }),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { ActionPayload, PageAction } from "../constants/ActionConstants";
|
|||
import ActionAPI, {
|
||||
ActionApiResponse,
|
||||
ActionCreateUpdateResponse,
|
||||
ActionResponse,
|
||||
ExecuteActionRequest,
|
||||
RestAction,
|
||||
} from "../api/ActionAPI";
|
||||
|
|
@ -45,6 +46,23 @@ const getAction = (
|
|||
return _.find(state.entities.actions.data, { id: actionId });
|
||||
};
|
||||
|
||||
const createActionResponse = (response: ActionApiResponse): ActionResponse => ({
|
||||
...response.data,
|
||||
...response.clientMeta,
|
||||
});
|
||||
|
||||
const createActionErrorResponse = (
|
||||
response: ActionApiResponse,
|
||||
): ActionResponse => ({
|
||||
body: response.responseMeta.error || { error: "Error" },
|
||||
statusCode: response.responseMeta.error
|
||||
? response.responseMeta.error.code
|
||||
: "Error",
|
||||
headers: {},
|
||||
duration: "0",
|
||||
size: "0",
|
||||
});
|
||||
|
||||
export function* evaluateJSONPathSaga(path: string): any {
|
||||
const dataTree = yield select(getDataTree);
|
||||
return getDynamicBoundValue(dataTree, path);
|
||||
|
|
@ -54,7 +72,9 @@ export function* executeAPIQueryActionSaga(apiAction: ActionPayload) {
|
|||
const api: PageAction = yield select(getAction, apiAction.actionId);
|
||||
|
||||
const executeActionRequest: ExecuteActionRequest = {
|
||||
actionId: apiAction.actionId,
|
||||
action: {
|
||||
id: apiAction.actionId,
|
||||
},
|
||||
};
|
||||
if (!_.isNil(api.jsonPathKeys)) {
|
||||
const values: any = _.flatten(
|
||||
|
|
@ -73,13 +93,9 @@ export function* executeAPIQueryActionSaga(apiAction: ActionPayload) {
|
|||
const response: ActionApiResponse = yield ActionAPI.executeAction(
|
||||
executeActionRequest,
|
||||
);
|
||||
let payload = response;
|
||||
let payload = createActionResponse(response);
|
||||
if (response.responseMeta && response.responseMeta.error) {
|
||||
payload = {
|
||||
body: response.responseMeta.error,
|
||||
statusCode: response.responseMeta.error.code,
|
||||
...response,
|
||||
};
|
||||
payload = createActionErrorResponse(response);
|
||||
if (apiAction.onError) {
|
||||
yield put({
|
||||
type: ReduxActionTypes.EXECUTE_ACTION,
|
||||
|
|
@ -127,6 +143,26 @@ export function* executeReduxActionSaga(action: ReduxAction<ActionPayload[]>) {
|
|||
}
|
||||
}
|
||||
|
||||
function* dryRunActionSaga(action: ReduxAction<RestAction>) {
|
||||
const executeActionRequest: ExecuteActionRequest = {
|
||||
action: {
|
||||
...action.payload,
|
||||
},
|
||||
};
|
||||
// TODO(hetu): No support for dynamic bindings in dry runs yet
|
||||
const response: ActionApiResponse = yield ActionAPI.executeAction(
|
||||
executeActionRequest,
|
||||
);
|
||||
let payload = createActionResponse(response);
|
||||
if (response.responseMeta && response.responseMeta.error) {
|
||||
payload = createActionErrorResponse(response);
|
||||
}
|
||||
yield put({
|
||||
type: ReduxActionTypes.EXECUTE_ACTION_SUCCESS,
|
||||
payload: { [action.type]: payload },
|
||||
});
|
||||
}
|
||||
|
||||
export function* createActionSaga(actionPayload: ReduxAction<RestAction>) {
|
||||
const response: ActionCreateUpdateResponse = yield ActionAPI.createAPI(
|
||||
actionPayload.payload,
|
||||
|
|
@ -208,5 +244,6 @@ export function* watchActionSagas() {
|
|||
takeLatest(ReduxActionTypes.CREATE_ACTION_INIT, createActionSaga),
|
||||
takeLatest(ReduxActionTypes.UPDATE_ACTION_INIT, updateActionSaga),
|
||||
takeLatest(ReduxActionTypes.DELETE_ACTION_INIT, deleteActionSaga),
|
||||
takeLatest(ReduxActionTypes.DRY_RUN_ACTION, dryRunActionSaga),
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ function* createDatasourceSaga(
|
|||
type: ReduxActionTypes.CREATE_DATASOURCE_SUCCESS,
|
||||
payload: response.data,
|
||||
});
|
||||
yield put(change(API_EDITOR_FORM_NAME, "datasourceId", response.data.id));
|
||||
yield put(change(API_EDITOR_FORM_NAME, "datasource.id", response.data.id));
|
||||
} else {
|
||||
yield put({
|
||||
type: ReduxActionTypes.CREATE_DATASOURCES_ERROR,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user