mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-11-09 13:25:23 +03:00
console: add support for application/x-www-form-urlencoded in rest connectors
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4354 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Rikin Kachhia <54616969+rikinsk@users.noreply.github.com> GitOrigin-RevId: 44dc48f3f226c57aac4393133245bf70d5f68acd
This commit is contained in:
parent
59df4dffb3
commit
b09bb602bd
@ -46,6 +46,7 @@ is `graphql-default`, the field names generated will be `my_table`, `my_tableByP
|
||||
- server: do not serialize env vars in logs or errors for remote schemas
|
||||
- server: fix failure when executing consecutive delete mutations on mssql (#8462)
|
||||
- server: bugfix: insertion of multiple empty objects should result in multiple entries (#8475)
|
||||
- console: add support for application/x-www-form-urlencoded in rest connectors (#8097)
|
||||
|
||||
## v2.7.0
|
||||
|
||||
|
@ -435,7 +435,7 @@ export const modifyV1ActionTransform = () => {
|
||||
createV1ActionTransform('login');
|
||||
|
||||
cy.wait(AWAIT_SHORT);
|
||||
// modify and save the action, the action should be converted into v2 and checkbox to remove body should be visible
|
||||
// modify and save the action, the action should be converted into v2
|
||||
cy.visit('/actions/manage/login/modify');
|
||||
cy.url({ timeout: AWAIT_LONG }).should(
|
||||
'eq',
|
||||
@ -453,9 +453,6 @@ export const modifyV1ActionTransform = () => {
|
||||
.should('be.visible')
|
||||
.and('contain', 'Action saved successfully');
|
||||
|
||||
// check if checkbox to remove body is visible
|
||||
cy.getBySel('transform-showRequestBody-checkbox').should('be.visible');
|
||||
|
||||
// delete the action
|
||||
deleteActionTransform();
|
||||
};
|
||||
|
@ -1,9 +1,14 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
RequestTransformContentType,
|
||||
RequestTransformMethod,
|
||||
RequestTransformContentType,
|
||||
} from '@/metadata/types';
|
||||
import { KeyValuePair, RequestTransformState } from './stateDefaults';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformState,
|
||||
RequestTransformStateBody,
|
||||
TransformationType,
|
||||
} from './stateDefaults';
|
||||
import RequestOptionsTransforms from './RequestOptionsTransforms';
|
||||
import PayloadOptionsTransforms from './PayloadOptionsTransforms';
|
||||
import SampleContextTransforms from './SampleContextTransforms';
|
||||
@ -11,6 +16,7 @@ import Button from '../Button';
|
||||
import AddIcon from '../Icons/Add';
|
||||
|
||||
type ConfigureTransformationProps = {
|
||||
transformationType: TransformationType;
|
||||
state: RequestTransformState;
|
||||
resetSampleInput: () => void;
|
||||
envVarsOnChange: (envVars: KeyValuePair[]) => void;
|
||||
@ -19,10 +25,9 @@ type ConfigureTransformationProps = {
|
||||
requestUrlOnChange: (requestUrl: string) => void;
|
||||
requestQueryParamsOnChange: (requestQueryParams: KeyValuePair[]) => void;
|
||||
requestAddHeadersOnChange: (requestAddHeaders: KeyValuePair[]) => void;
|
||||
requestBodyOnChange: (requestBody: string) => void;
|
||||
requestBodyEnabledOnChange: (enableRequestBody: boolean) => void;
|
||||
requestBodyOnChange: (requestBody: RequestTransformStateBody) => void;
|
||||
requestSampleInputOnChange: (requestSampleInput: string) => void;
|
||||
requestContentTypeOnChange: (
|
||||
requestContentTypeOnChange?: (
|
||||
requestContentType: RequestTransformContentType
|
||||
) => void;
|
||||
requestUrlTransformOnChange: (data: boolean) => void;
|
||||
@ -30,6 +35,7 @@ type ConfigureTransformationProps = {
|
||||
};
|
||||
|
||||
const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
|
||||
transformationType,
|
||||
state,
|
||||
resetSampleInput,
|
||||
envVarsOnChange,
|
||||
@ -39,9 +45,7 @@ const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
|
||||
requestQueryParamsOnChange,
|
||||
requestAddHeadersOnChange,
|
||||
requestBodyOnChange,
|
||||
requestBodyEnabledOnChange,
|
||||
requestSampleInputOnChange,
|
||||
requestContentTypeOnChange,
|
||||
requestUrlTransformOnChange,
|
||||
requestPayloadTransformOnChange,
|
||||
}) => {
|
||||
@ -58,8 +62,6 @@ const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
|
||||
requestBodyError,
|
||||
requestSampleInput,
|
||||
requestTransformedBody,
|
||||
enableRequestBody,
|
||||
requestContentType,
|
||||
isRequestUrlTransform,
|
||||
isRequestPayloadTransform,
|
||||
} = state;
|
||||
@ -105,6 +107,7 @@ const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
|
||||
|
||||
{isContextAreaActive ? (
|
||||
<SampleContextTransforms
|
||||
transformationType={transformationType}
|
||||
envVars={envVars}
|
||||
sessionVars={sessionVars}
|
||||
envVarsOnChange={envVarsOnChange}
|
||||
@ -170,17 +173,14 @@ const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
|
||||
</Button>
|
||||
{isRequestPayloadTransform ? (
|
||||
<PayloadOptionsTransforms
|
||||
transformationType={transformationType}
|
||||
requestBody={requestBody}
|
||||
requestBodyError={requestBodyError}
|
||||
requestSampleInput={requestSampleInput}
|
||||
requestTransformedBody={requestTransformedBody}
|
||||
enableRequestBody={enableRequestBody}
|
||||
requestContentType={requestContentType}
|
||||
resetSampleInput={resetSampleInput}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
requestBodyEnabledOnChange={requestBodyEnabledOnChange}
|
||||
requestSampleInputOnChange={requestSampleInputOnChange}
|
||||
requestContentTypeOnChange={requestContentTypeOnChange}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -4,12 +4,13 @@ import { Nullable } from '../../utils/tsUtils';
|
||||
import { getAceCompleterFromString, editorDebounceTime } from '../utils';
|
||||
import { useDebouncedEffect } from '../../../../hooks/useDebounceEffect';
|
||||
import CrossIcon from '../../Icons/Cross';
|
||||
import { RequestTransformStateBody } from '../stateDefaults';
|
||||
|
||||
type TemplateEditorProps = {
|
||||
requestBody: string;
|
||||
requestBody: RequestTransformStateBody;
|
||||
requestBodyError: string;
|
||||
requestSampleInput: string;
|
||||
requestBodyOnChange: (requestBody: string) => void;
|
||||
requestBodyOnChange: (requestBody: RequestTransformStateBody) => void;
|
||||
height?: string;
|
||||
width?: string;
|
||||
};
|
||||
@ -23,13 +24,15 @@ const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
||||
width,
|
||||
}) => {
|
||||
const editorRef = useRef<any>();
|
||||
const [localValue, setLocalValue] = useState<string>(requestBody);
|
||||
const [localValue, setLocalValue] = useState<string>(
|
||||
requestBody.template ?? ''
|
||||
);
|
||||
const [localError, setLocalError] = useState<Nullable<string>>(
|
||||
requestBodyError
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(requestBody);
|
||||
setLocalValue(requestBody.template ?? '');
|
||||
}, [requestBody]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -54,7 +57,7 @@ const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
||||
|
||||
useDebouncedEffect(
|
||||
() => {
|
||||
requestBodyOnChange(localValue);
|
||||
requestBodyOnChange({ ...requestBody, template: localValue });
|
||||
},
|
||||
editorDebounceTime,
|
||||
[localValue]
|
||||
|
@ -1,48 +1,82 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { RequestTransformBodyActions } from '@/metadata/types';
|
||||
import { useDebouncedEffect } from '@/hooks/useDebounceEffect';
|
||||
import { FaExclamationCircle } from 'react-icons/fa';
|
||||
import CrossIcon from '../Icons/Cross';
|
||||
import TemplateEditor from './CustomEditors/TemplateEditor';
|
||||
import JsonEditor from './CustomEditors/JsonEditor';
|
||||
import AceEditor from '../AceEditor/BaseEditor';
|
||||
import { RequestTransformContentType } from '../../../metadata/types';
|
||||
import ResetIcon from '../Icons/Reset';
|
||||
import { buttonShadow, focusYellowRing, inputStyles } from './utils';
|
||||
import {
|
||||
buttonShadow,
|
||||
capitaliseFirstLetter,
|
||||
editorDebounceTime,
|
||||
focusYellowRing,
|
||||
inputStyles,
|
||||
} from './utils';
|
||||
import NumberedSidebar from './CustomEditors/NumberedSidebar';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformStateBody,
|
||||
TransformationType,
|
||||
} from './stateDefaults';
|
||||
import KeyValueInput from './CustomEditors/KeyValueInput';
|
||||
import { isEmpty } from '../utils/jsUtils';
|
||||
import { requestBodyActionState } from './requestTransformState';
|
||||
|
||||
type PayloadOptionsTransformsProps = {
|
||||
requestBody: string;
|
||||
transformationType: TransformationType;
|
||||
requestBody: RequestTransformStateBody;
|
||||
requestBodyError: string;
|
||||
requestSampleInput: string;
|
||||
requestTransformedBody: string;
|
||||
requestContentType: RequestTransformContentType;
|
||||
enableRequestBody: boolean;
|
||||
resetSampleInput: () => void;
|
||||
requestBodyOnChange: (requestBody: string) => void;
|
||||
requestBodyEnabledOnChange: (enableRequestBody: boolean) => void;
|
||||
requestBodyOnChange: (requestBody: RequestTransformStateBody) => void;
|
||||
requestSampleInputOnChange: (requestSampleInput: string) => void;
|
||||
requestContentTypeOnChange: (
|
||||
requestContentType: RequestTransformContentType
|
||||
) => void;
|
||||
};
|
||||
|
||||
const PayloadOptionsTransforms: React.FC<PayloadOptionsTransformsProps> = ({
|
||||
transformationType,
|
||||
requestBody,
|
||||
requestBodyError,
|
||||
requestSampleInput,
|
||||
requestTransformedBody,
|
||||
requestContentType,
|
||||
enableRequestBody,
|
||||
resetSampleInput,
|
||||
requestBodyOnChange,
|
||||
requestBodyEnabledOnChange,
|
||||
requestSampleInputOnChange,
|
||||
requestContentTypeOnChange,
|
||||
}) => {
|
||||
const editorRef = useRef<any>();
|
||||
const showRequestContentTypeOptions = false;
|
||||
const requestContentTypeOptions = [
|
||||
'application/json',
|
||||
'application/x-www-form-urlencoded',
|
||||
const requestBodyTypeOptions = [
|
||||
{
|
||||
value: requestBodyActionState.remove,
|
||||
text: 'disabled',
|
||||
},
|
||||
{
|
||||
value: requestBodyActionState.transformApplicationJson,
|
||||
text: 'application/json',
|
||||
},
|
||||
{
|
||||
value: requestBodyActionState.transformFormUrlEncoded,
|
||||
text: 'application/x-www-form-urlencoded',
|
||||
},
|
||||
];
|
||||
const [localFormElements, setLocalFormElements] = React.useState<
|
||||
KeyValuePair[]
|
||||
>(requestBody.form_template ?? [{ name: '', value: '' }]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setLocalFormElements(
|
||||
requestBody.form_template ?? [{ name: '', value: '' }]
|
||||
);
|
||||
}, [requestBody]);
|
||||
|
||||
useDebouncedEffect(
|
||||
() => {
|
||||
requestBodyOnChange({ ...requestBody, form_template: localFormElements });
|
||||
},
|
||||
editorDebounceTime,
|
||||
[localFormElements]
|
||||
);
|
||||
|
||||
if (editorRef?.current?.editor?.renderer?.$cursorLayer?.element?.style) {
|
||||
editorRef.current.editor.renderer.$cursorLayer.element.style.display =
|
||||
@ -54,7 +88,9 @@ const PayloadOptionsTransforms: React.FC<PayloadOptionsTransformsProps> = ({
|
||||
<div className="mb-md">
|
||||
<NumberedSidebar
|
||||
title="Sample Input"
|
||||
description="Sample input defined by your Action Defintion."
|
||||
description={`Sample input defined by your ${capitaliseFirstLetter(
|
||||
transformationType
|
||||
)} Defintion.`}
|
||||
number="1"
|
||||
>
|
||||
<button
|
||||
@ -81,71 +117,78 @@ const PayloadOptionsTransforms: React.FC<PayloadOptionsTransformsProps> = ({
|
||||
<span>
|
||||
The template which will transform your request body into the
|
||||
required specification. You can use{' '}
|
||||
<code className="text-xs">$body</code> to access the original
|
||||
request body
|
||||
<code className="text-xs">{{$body}}</code> to
|
||||
access the original request body
|
||||
</span>
|
||||
}
|
||||
number="2"
|
||||
url="https://hasura.io/docs/latest/graphql/core/actions/transforms.html#request-body"
|
||||
/>
|
||||
<div className="mb-sm">
|
||||
<input
|
||||
checked={enableRequestBody}
|
||||
id="request-enable"
|
||||
name="request-body"
|
||||
type="checkbox"
|
||||
onChange={e => requestBodyEnabledOnChange(e.target.checked)}
|
||||
className="rounded border-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-400"
|
||||
data-test="transform-showRequestBody-checkbox"
|
||||
/>
|
||||
<label className="ml-xs" htmlFor="request-enable">
|
||||
Enable Request Body
|
||||
</label>
|
||||
</div>
|
||||
{enableRequestBody ? (
|
||||
>
|
||||
<select
|
||||
className={`ml-auto ${inputStyles}`}
|
||||
value={requestBody.action}
|
||||
onChange={e =>
|
||||
requestBodyOnChange({
|
||||
...requestBody,
|
||||
action: e.target.value as RequestTransformBodyActions,
|
||||
})
|
||||
}
|
||||
>
|
||||
<option disabled>Request Body Type</option>
|
||||
{requestBodyTypeOptions.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.text}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</NumberedSidebar>
|
||||
{requestBody.action ===
|
||||
requestBodyActionState.transformApplicationJson ? (
|
||||
<TemplateEditor
|
||||
requestBody={requestBody}
|
||||
requestBodyError={requestBodyError}
|
||||
requestSampleInput={requestSampleInput}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
/>
|
||||
) : (
|
||||
) : null}
|
||||
|
||||
{requestBody.action ===
|
||||
requestBodyActionState.transformFormUrlEncoded ? (
|
||||
<>
|
||||
{!isEmpty(requestBodyError) && (
|
||||
<div className="mb-sm" data-test="transform-requestBody-error">
|
||||
<CrossIcon />
|
||||
<span className="text-red-500 ml-sm">{requestBodyError}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid gap-3 grid-cols-3 mb-sm">
|
||||
<KeyValueInput
|
||||
pairs={localFormElements}
|
||||
setPairs={setLocalFormElements}
|
||||
testId="add-url-encoded-body"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{requestBody.action === requestBodyActionState.remove ? (
|
||||
<div className="flex items-center text-gray-600 bg-gray-200 border border-gray-400 text-sm rounded p-sm">
|
||||
<FaExclamationCircle className="mr-sm" />
|
||||
The request body is disabled. No request body will be sent with this
|
||||
action. Enable the request body to modify your request
|
||||
{transformationType}. Enable the request body to modify your request
|
||||
transformation.
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{enableRequestBody ? (
|
||||
{requestBody.action !== requestBodyActionState.remove ? (
|
||||
<div className="mb-md">
|
||||
<NumberedSidebar
|
||||
title="Transformed Request Body"
|
||||
description="Sample request body to be delivered based on your input and
|
||||
transformation template."
|
||||
number="3"
|
||||
>
|
||||
{showRequestContentTypeOptions ? (
|
||||
<select
|
||||
className={`ml-auto ${inputStyles}`}
|
||||
value={requestContentType}
|
||||
onChange={e =>
|
||||
requestContentTypeOnChange(
|
||||
e.target.value as RequestTransformContentType
|
||||
)
|
||||
}
|
||||
>
|
||||
<option disabled>Data Type</option>
|
||||
{requestContentTypeOptions.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : null}
|
||||
</NumberedSidebar>
|
||||
/>
|
||||
<AceEditor
|
||||
mode="json"
|
||||
editorRef={editorRef}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useDebouncedEffect } from '@/hooks/useDebounceEffect';
|
||||
import { KeyValuePair } from './stateDefaults';
|
||||
import { KeyValuePair, TransformationType } from './stateDefaults';
|
||||
import KeyValueInput from './CustomEditors/KeyValueInput';
|
||||
import NumberedSidebar from './CustomEditors/NumberedSidebar';
|
||||
import { editorDebounceTime, setEnvVarsToLS } from './utils';
|
||||
|
||||
type SampleContextTransformsProps = {
|
||||
transformationType: TransformationType;
|
||||
envVars: KeyValuePair[];
|
||||
sessionVars: KeyValuePair[];
|
||||
envVarsOnChange: (envVars: KeyValuePair[]) => void;
|
||||
@ -13,6 +14,7 @@ type SampleContextTransformsProps = {
|
||||
};
|
||||
|
||||
const SampleContextTransforms: React.FC<SampleContextTransformsProps> = ({
|
||||
transformationType,
|
||||
envVars,
|
||||
sessionVars,
|
||||
envVarsOnChange,
|
||||
@ -57,7 +59,8 @@ const SampleContextTransforms: React.FC<SampleContextTransformsProps> = ({
|
||||
<span>
|
||||
Enter a sample input for your provided env variables.
|
||||
<br />
|
||||
e.g. the sample value for ACTION_BASE_URL
|
||||
e.g. the sample value for {transformationType.toUpperCase()}
|
||||
_BASE_URL
|
||||
</span>
|
||||
}
|
||||
number="1"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
RequestTransformMethod,
|
||||
RequestTransformContentType,
|
||||
RequestTransformBodyActions,
|
||||
} from '../../../metadata/types';
|
||||
import {
|
||||
SET_ENV_VARS,
|
||||
@ -15,7 +16,6 @@ import {
|
||||
SET_REQUEST_BODY_ERROR,
|
||||
SET_REQUEST_SAMPLE_INPUT,
|
||||
SET_REQUEST_TRANSFORMED_BODY,
|
||||
SET_ENABLE_REQUEST_BODY,
|
||||
SET_REQUEST_CONTENT_TYPE,
|
||||
SET_REQUEST_URL_TRANSFORM,
|
||||
SET_REQUEST_PAYLOAD_TRANSFORM,
|
||||
@ -32,7 +32,6 @@ import {
|
||||
SetRequestBodyError,
|
||||
SetRequestSampleInput,
|
||||
SetRequestTransformedBody,
|
||||
SetEnableRequestBody,
|
||||
SetRequestTransformState,
|
||||
SetRequestContentType,
|
||||
SetRequestUrlTransform,
|
||||
@ -46,6 +45,7 @@ import {
|
||||
KeyValuePair,
|
||||
defaultEventRequestBody,
|
||||
defaultEventRequestSampleInput,
|
||||
RequestTransformStateBody,
|
||||
} from './stateDefaults';
|
||||
import { getSessionVarsFromLS, getEnvVarsFromLS } from './utils';
|
||||
|
||||
@ -101,7 +101,9 @@ export const setRequestAddHeaders = (
|
||||
requestAddHeaders,
|
||||
});
|
||||
|
||||
export const setRequestBody = (requestBody: string): SetRequestBody => ({
|
||||
export const setRequestBody = (
|
||||
requestBody: RequestTransformStateBody
|
||||
): SetRequestBody => ({
|
||||
type: SET_REQUEST_BODY,
|
||||
requestBody,
|
||||
});
|
||||
@ -127,13 +129,6 @@ export const setRequestTransformedBody = (
|
||||
requestTransformedBody,
|
||||
});
|
||||
|
||||
export const setEnableRequestBody = (
|
||||
enableRequestBody: boolean
|
||||
): SetEnableRequestBody => ({
|
||||
type: SET_ENABLE_REQUEST_BODY,
|
||||
enableRequestBody,
|
||||
});
|
||||
|
||||
export const setRequestContentType = (
|
||||
requestContentType: RequestTransformContentType
|
||||
): SetRequestContentType => ({
|
||||
@ -164,6 +159,12 @@ export const setRequestTransformState = (
|
||||
|
||||
const currentVersion = 2;
|
||||
|
||||
export const requestBodyActionState = {
|
||||
remove: 'remove' as RequestTransformBodyActions,
|
||||
transformApplicationJson: 'transform' as RequestTransformBodyActions,
|
||||
transformFormUrlEncoded: 'x_www_form_urlencoded' as RequestTransformBodyActions,
|
||||
};
|
||||
|
||||
export const requestTransformState: RequestTransformState = {
|
||||
version: currentVersion,
|
||||
envVars: [],
|
||||
@ -174,11 +175,10 @@ export const requestTransformState: RequestTransformState = {
|
||||
requestUrlPreview: '',
|
||||
requestQueryParams: [],
|
||||
requestAddHeaders: [],
|
||||
requestBody: '',
|
||||
requestBody: { action: requestBodyActionState.transformApplicationJson },
|
||||
requestBodyError: '',
|
||||
requestSampleInput: '',
|
||||
requestTransformedBody: '',
|
||||
enableRequestBody: true,
|
||||
requestContentType: defaultRequestContentType,
|
||||
isRequestUrlTransform: false,
|
||||
isRequestPayloadTransform: false,
|
||||
@ -192,7 +192,11 @@ export const getActionRequestTransformDefaultState = (): RequestTransformState =
|
||||
sessionVars: getSessionVarsFromLS(),
|
||||
requestQueryParams: [{ name: '', value: '' }],
|
||||
requestAddHeaders: [{ name: '', value: '' }],
|
||||
requestBody: defaultActionRequestBody,
|
||||
requestBody: {
|
||||
action: requestBodyActionState.transformApplicationJson,
|
||||
template: defaultActionRequestBody,
|
||||
form_template: [{ name: 'name', value: '{{$body.action.name}}' }],
|
||||
},
|
||||
requestSampleInput: defaultActionRequestSampleInput,
|
||||
};
|
||||
};
|
||||
@ -204,7 +208,11 @@ export const getEventRequestTransformDefaultState = (): RequestTransformState =>
|
||||
sessionVars: getSessionVarsFromLS(),
|
||||
requestQueryParams: [{ name: '', value: '' }],
|
||||
requestAddHeaders: [{ name: '', value: '' }],
|
||||
requestBody: defaultEventRequestBody,
|
||||
requestBody: {
|
||||
action: requestBodyActionState.transformApplicationJson,
|
||||
template: defaultEventRequestBody,
|
||||
form_template: [{ name: 'name', value: '{{$body.table.name}}' }],
|
||||
},
|
||||
requestSampleInput: defaultEventRequestSampleInput,
|
||||
};
|
||||
};
|
||||
@ -274,11 +282,6 @@ export const requestTransformReducer = (
|
||||
...state,
|
||||
requestTransformedBody: action.requestTransformedBody,
|
||||
};
|
||||
case SET_ENABLE_REQUEST_BODY:
|
||||
return {
|
||||
...state,
|
||||
enableRequestBody: action.enableRequestBody,
|
||||
};
|
||||
case SET_REQUEST_CONTENT_TYPE:
|
||||
return {
|
||||
...state,
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
RequestTransformMethod,
|
||||
RequestTransformContentType,
|
||||
RequestTransformTemplateEngine,
|
||||
RequestTransformBody,
|
||||
} from '../../../metadata/types';
|
||||
import { Nullable } from '../utils/tsUtils';
|
||||
|
||||
@ -82,7 +83,7 @@ export interface SetRequestAddHeaders extends ReduxAction {
|
||||
|
||||
export interface SetRequestBody extends ReduxAction {
|
||||
type: typeof SET_REQUEST_BODY;
|
||||
requestBody: string;
|
||||
requestBody: RequestTransformStateBody;
|
||||
}
|
||||
|
||||
export interface SetRequestBodyError extends ReduxAction {
|
||||
@ -100,11 +101,6 @@ export interface SetRequestTransformedBody extends ReduxAction {
|
||||
requestTransformedBody: string;
|
||||
}
|
||||
|
||||
export interface SetEnableRequestBody extends ReduxAction {
|
||||
type: typeof SET_ENABLE_REQUEST_BODY;
|
||||
enableRequestBody: boolean;
|
||||
}
|
||||
|
||||
export interface SetRequestContentType extends ReduxAction {
|
||||
type: typeof SET_REQUEST_CONTENT_TYPE;
|
||||
requestContentType: RequestTransformContentType;
|
||||
@ -138,7 +134,6 @@ export type RequestTransformEvents =
|
||||
| SetRequestBodyError
|
||||
| SetRequestSampleInput
|
||||
| SetRequestTransformedBody
|
||||
| SetEnableRequestBody
|
||||
| SetRequestContentType
|
||||
| SetRequestUrlTransform
|
||||
| SetRequestPayloadTransform
|
||||
@ -154,17 +149,21 @@ export type RequestTransformState = {
|
||||
requestUrlPreview: string;
|
||||
requestQueryParams: KeyValuePair[];
|
||||
requestAddHeaders: KeyValuePair[];
|
||||
requestBody: string;
|
||||
requestBody: RequestTransformStateBody;
|
||||
requestBodyError: string;
|
||||
requestSampleInput: string;
|
||||
requestTransformedBody: string;
|
||||
enableRequestBody: boolean;
|
||||
requestContentType: RequestTransformContentType;
|
||||
isRequestUrlTransform: boolean;
|
||||
isRequestPayloadTransform: boolean;
|
||||
templatingEngine: RequestTransformTemplateEngine;
|
||||
};
|
||||
|
||||
export type RequestTransformStateBody = Omit<
|
||||
RequestTransformBody,
|
||||
'form_template'
|
||||
> & { form_template?: KeyValuePair[] };
|
||||
|
||||
export type KeyValuePair = {
|
||||
name: string;
|
||||
value: string;
|
||||
@ -178,6 +177,8 @@ export type GraphiQlHeader = {
|
||||
isDisabled: boolean;
|
||||
};
|
||||
|
||||
export type TransformationType = 'action' | 'event';
|
||||
|
||||
export const defaultActionRequestSampleInput = getActionRequestSampleInput(
|
||||
defaultActionDefSdl,
|
||||
defaultTypesDefSdl
|
||||
|
@ -1,15 +1,23 @@
|
||||
import { RequestTransform, RequestTransformMethod } from '@/metadata/types';
|
||||
import {
|
||||
RequestTransform,
|
||||
RequestTransformBody,
|
||||
RequestTransformMethod,
|
||||
} from '@/metadata/types';
|
||||
import { getLSItem, setLSItem, LS_KEYS } from '@/utils/localStorage';
|
||||
import {
|
||||
defaultRequestContentType,
|
||||
GraphiQlHeader,
|
||||
KeyValuePair,
|
||||
RequestTransformState,
|
||||
RequestTransformStateBody,
|
||||
} from './stateDefaults';
|
||||
import { isEmpty, isJsonString } from '../utils/jsUtils';
|
||||
import { Nullable } from '../utils/tsUtils';
|
||||
import { requestBodyActionState } from './requestTransformState';
|
||||
|
||||
export const getPairsObjFromArray = (pairs: KeyValuePair[]) => {
|
||||
export const getPairsObjFromArray = (
|
||||
pairs: KeyValuePair[]
|
||||
): Record<string, string> => {
|
||||
let obj = {};
|
||||
|
||||
pairs.forEach(({ name, value }) => {
|
||||
@ -101,12 +109,22 @@ const getUrlWithBasePrefix = (val?: string) => {
|
||||
return val ? `{{$base_url}}${val}` : undefined;
|
||||
};
|
||||
|
||||
const getTransformBodyServer = (reqBody: RequestTransformStateBody) => {
|
||||
if (reqBody.action === requestBodyActionState.remove)
|
||||
return { action: reqBody.action };
|
||||
else if (reqBody.action === requestBodyActionState.transformApplicationJson)
|
||||
return { action: reqBody.action, template: reqBody.template };
|
||||
return {
|
||||
action: reqBody.action,
|
||||
form_template: getPairsObjFromArray(reqBody.form_template ?? []),
|
||||
};
|
||||
};
|
||||
|
||||
export const getRequestTransformObject = (
|
||||
transformState: RequestTransformState
|
||||
) => {
|
||||
const isRequestUrlTransform = transformState.isRequestUrlTransform;
|
||||
const isRequestPayloadTransform = transformState.isRequestPayloadTransform;
|
||||
const enableRequestBody = transformState.enableRequestBody;
|
||||
|
||||
if (!isRequestUrlTransform && !isRequestPayloadTransform) return null;
|
||||
|
||||
@ -135,16 +153,22 @@ export const getRequestTransformObject = (
|
||||
if (isRequestPayloadTransform) {
|
||||
obj = {
|
||||
...obj,
|
||||
body: enableRequestBody
|
||||
? {
|
||||
action: 'transform',
|
||||
template: checkEmptyString(transformState.requestBody),
|
||||
}
|
||||
: {
|
||||
action: 'remove',
|
||||
},
|
||||
content_type: transformState.requestContentType,
|
||||
body: getTransformBodyServer(transformState.requestBody),
|
||||
};
|
||||
if (
|
||||
transformState.requestBody.action ===
|
||||
requestBodyActionState.transformFormUrlEncoded
|
||||
) {
|
||||
obj = {
|
||||
...obj,
|
||||
request_headers: {
|
||||
remove_headers: ['content-type'],
|
||||
add_headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
@ -209,14 +233,14 @@ type RequestTransformerV1 = RequestTransformerFields & {
|
||||
|
||||
type RequestTransformerV2 = RequestTransformerFields & {
|
||||
version: 2;
|
||||
body?: Record<string, string>;
|
||||
body?: RequestTransformBody;
|
||||
};
|
||||
|
||||
type RequestTransformer = RequestTransformerV1 | RequestTransformerV2;
|
||||
|
||||
const getTransformer = (
|
||||
version: 1 | 2,
|
||||
transformerBody?: string,
|
||||
transformerBody?: RequestTransformStateBody,
|
||||
transformerUrl?: string,
|
||||
requestMethod?: Nullable<RequestTransformMethod>,
|
||||
queryParams?: KeyValuePair[]
|
||||
@ -224,7 +248,7 @@ const getTransformer = (
|
||||
return version === 1
|
||||
? {
|
||||
version,
|
||||
body: checkEmptyString(transformerBody),
|
||||
body: checkEmptyString(transformerBody?.template ?? ''),
|
||||
url: checkEmptyString(transformerUrl),
|
||||
method: requestMethod,
|
||||
query_params: queryParams
|
||||
@ -234,10 +258,9 @@ const getTransformer = (
|
||||
}
|
||||
: {
|
||||
version,
|
||||
body: {
|
||||
action: 'transform',
|
||||
template: checkEmptyString(transformerBody) ?? '{}',
|
||||
},
|
||||
body: transformerBody
|
||||
? getTransformBodyServer(transformerBody)
|
||||
: undefined,
|
||||
url: checkEmptyString(transformerUrl),
|
||||
method: requestMethod,
|
||||
query_params: queryParams
|
||||
@ -275,7 +298,7 @@ type ValidateTransformOptionsArgsType = {
|
||||
webhookUrl: string;
|
||||
envVarsFromContext?: KeyValuePair[];
|
||||
sessionVarsFromContext?: KeyValuePair[];
|
||||
transformerBody?: string;
|
||||
transformerBody?: RequestTransformStateBody;
|
||||
requestUrl?: string;
|
||||
queryParams?: KeyValuePair[];
|
||||
isEnvVar?: boolean;
|
||||
@ -384,6 +407,28 @@ const getTrimmedRequestUrl = (val: string) => {
|
||||
return val.startsWith(prefix) ? val.slice(prefix.length) : val;
|
||||
};
|
||||
|
||||
const getRequestTransformBody = (
|
||||
transform: RequestTransform
|
||||
): RequestTransformStateBody => {
|
||||
if (transform.body) {
|
||||
return transform.version === 1
|
||||
? {
|
||||
action: requestBodyActionState.transformApplicationJson,
|
||||
template: transform?.body ?? '',
|
||||
}
|
||||
: {
|
||||
...transform.body,
|
||||
form_template: getArrayFromServerPairObject(
|
||||
transform.body?.form_template
|
||||
),
|
||||
};
|
||||
}
|
||||
return {
|
||||
action: requestBodyActionState.transformApplicationJson,
|
||||
template: '',
|
||||
};
|
||||
};
|
||||
|
||||
export const getTransformState = (
|
||||
transform: RequestTransform,
|
||||
sampleInput: string
|
||||
@ -401,15 +446,10 @@ export const getTransformState = (
|
||||
requestAddHeaders: getArrayFromServerPairObject(
|
||||
transform?.request_headers?.add_headers
|
||||
) ?? [{ name: '', value: '' }],
|
||||
requestBody:
|
||||
transform?.version === 1
|
||||
? transform?.body ?? ''
|
||||
: transform?.body?.template ?? '',
|
||||
requestBody: getRequestTransformBody(transform),
|
||||
requestBodyError: '',
|
||||
requestSampleInput: sampleInput,
|
||||
requestTransformedBody: '',
|
||||
enableRequestBody:
|
||||
transform?.version === 2 ? transform?.body?.action === 'transform' : true,
|
||||
requestContentType: transform?.content_type ?? defaultRequestContentType,
|
||||
isRequestUrlTransform:
|
||||
!!transform?.method ||
|
||||
@ -419,6 +459,9 @@ export const getTransformState = (
|
||||
templatingEngine: transform?.template_engine ?? 'Kriti',
|
||||
});
|
||||
|
||||
export const capitaliseFirstLetter = (val: string) =>
|
||||
`${val[0].toUpperCase()}${val.slice(1)}`;
|
||||
|
||||
export const sidebarNumberStyles =
|
||||
'-mb-9 -ml-14 bg-gray-50 text-sm font-medium border border-gray-400 rounded-full flex items-center justify-center h-lg w-lg';
|
||||
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
setRequestBodyError,
|
||||
setRequestSampleInput,
|
||||
setRequestTransformedBody,
|
||||
setEnableRequestBody,
|
||||
setRequestContentType,
|
||||
setRequestUrlTransform,
|
||||
setRequestPayloadTransform,
|
||||
@ -33,7 +32,10 @@ import {
|
||||
RequestTransformContentType,
|
||||
RequestTransformMethod,
|
||||
} from '@/metadata/types';
|
||||
import { KeyValuePair } from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformStateBody,
|
||||
} from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import ConfigureTransformation from '@/components/Common/ConfigureTransformation/ConfigureTransformation';
|
||||
import ActionEditor from '../Common/components/ActionEditor';
|
||||
import Button from '../../../Common/Button';
|
||||
@ -189,7 +191,7 @@ const AddAction: React.FC<AddActionProps> = ({
|
||||
transformDispatch(setRequestAddHeaders(requestAddHeaders));
|
||||
};
|
||||
|
||||
const requestBodyOnChange = (requestBody: string) => {
|
||||
const requestBodyOnChange = (requestBody: RequestTransformStateBody) => {
|
||||
transformDispatch(setRequestBody(requestBody));
|
||||
};
|
||||
|
||||
@ -205,10 +207,6 @@ const AddAction: React.FC<AddActionProps> = ({
|
||||
transformDispatch(setRequestTransformedBody(requestTransformedBody));
|
||||
};
|
||||
|
||||
const requestBodyEnabledOnChange = (enableRequestBody: boolean) => {
|
||||
transformDispatch(setEnableRequestBody(enableRequestBody));
|
||||
};
|
||||
|
||||
const requestContentTypeOnChange = (
|
||||
requestContentType: RequestTransformContentType
|
||||
) => {
|
||||
@ -356,6 +354,7 @@ const AddAction: React.FC<AddActionProps> = ({
|
||||
/>
|
||||
|
||||
<ConfigureTransformation
|
||||
transformationType="action"
|
||||
state={transformState}
|
||||
resetSampleInput={resetSampleInput}
|
||||
envVarsOnChange={envVarsOnChange}
|
||||
@ -365,7 +364,6 @@ const AddAction: React.FC<AddActionProps> = ({
|
||||
requestQueryParamsOnChange={requestQueryParamsOnChange}
|
||||
requestAddHeadersOnChange={requestAddHeadersOnChange}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
requestBodyEnabledOnChange={requestBodyEnabledOnChange}
|
||||
requestSampleInputOnChange={requestSampleInputOnChange}
|
||||
requestContentTypeOnChange={requestContentTypeOnChange}
|
||||
requestUrlTransformOnChange={requestUrlTransformOnChange}
|
||||
|
@ -24,13 +24,15 @@ import {
|
||||
setRequestBodyError,
|
||||
setRequestSampleInput,
|
||||
setRequestTransformedBody,
|
||||
setEnableRequestBody,
|
||||
setRequestContentType,
|
||||
setRequestUrlTransform,
|
||||
setRequestPayloadTransform,
|
||||
setRequestTransformState,
|
||||
} from '@/components/Common/ConfigureTransformation/requestTransformState';
|
||||
import { KeyValuePair } from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformStateBody,
|
||||
} from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import {
|
||||
RequestTransformContentType,
|
||||
RequestTransformMethod,
|
||||
@ -214,14 +216,10 @@ const ModifyAction: React.FC<ModifyProps> = ({
|
||||
transformDispatch(setRequestAddHeaders(requestAddHeaders));
|
||||
};
|
||||
|
||||
const requestBodyOnChange = (requestBody: string) => {
|
||||
const requestBodyOnChange = (requestBody: RequestTransformStateBody) => {
|
||||
transformDispatch(setRequestBody(requestBody));
|
||||
};
|
||||
|
||||
const requestBodyEnabledOnChange = (enableRequestBody: boolean) => {
|
||||
transformDispatch(setEnableRequestBody(enableRequestBody));
|
||||
};
|
||||
|
||||
const requestBodyErrorOnChange = (requestBodyError: string) => {
|
||||
transformDispatch(setRequestBodyError(requestBodyError));
|
||||
};
|
||||
@ -399,6 +397,7 @@ const ModifyAction: React.FC<ModifyProps> = ({
|
||||
/>
|
||||
|
||||
<ConfigureTransformation
|
||||
transformationType="action"
|
||||
state={transformState}
|
||||
resetSampleInput={resetSampleInput}
|
||||
envVarsOnChange={envVarsOnChange}
|
||||
@ -408,7 +407,6 @@ const ModifyAction: React.FC<ModifyProps> = ({
|
||||
requestQueryParamsOnChange={requestQueryParamsOnChange}
|
||||
requestAddHeadersOnChange={requestAddHeadersOnChange}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
requestBodyEnabledOnChange={requestBodyEnabledOnChange}
|
||||
requestSampleInputOnChange={requestSampleInputOnChange}
|
||||
requestContentTypeOnChange={requestContentTypeOnChange}
|
||||
requestUrlTransformOnChange={requestUrlTransformOnChange}
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
setRequestBodyError,
|
||||
setRequestSampleInput,
|
||||
setRequestTransformedBody,
|
||||
setEnableRequestBody,
|
||||
setRequestContentType,
|
||||
setRequestUrlTransform,
|
||||
setRequestPayloadTransform,
|
||||
@ -25,7 +24,10 @@ import {
|
||||
RequestTransformContentType,
|
||||
RequestTransformMethod,
|
||||
} from '@/metadata/types';
|
||||
import { KeyValuePair } from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformStateBody,
|
||||
} from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import ConfigureTransformation from '@/components/Common/ConfigureTransformation/ConfigureTransformation';
|
||||
import {
|
||||
getValidateTransformOptions,
|
||||
@ -184,14 +186,10 @@ const Add: React.FC<Props> = props => {
|
||||
transformDispatch(setRequestAddHeaders(requestAddHeaders));
|
||||
};
|
||||
|
||||
const requestBodyOnChange = (requestBody: string) => {
|
||||
const requestBodyOnChange = (requestBody: RequestTransformStateBody) => {
|
||||
transformDispatch(setRequestBody(requestBody));
|
||||
};
|
||||
|
||||
const requestBodyEnabledOnChange = (enableRequestBody: boolean) => {
|
||||
transformDispatch(setEnableRequestBody(enableRequestBody));
|
||||
};
|
||||
|
||||
const requestBodyErrorOnChange = (requestBodyError: string) => {
|
||||
transformDispatch(setRequestBodyError(requestBodyError));
|
||||
};
|
||||
@ -407,6 +405,7 @@ const Add: React.FC<Props> = props => {
|
||||
handleToggleAllColumn={setState.toggleAllColumnChecked}
|
||||
/>
|
||||
<ConfigureTransformation
|
||||
transformationType="event"
|
||||
state={transformState}
|
||||
resetSampleInput={resetSampleInput}
|
||||
envVarsOnChange={envVarsOnChange}
|
||||
@ -416,7 +415,6 @@ const Add: React.FC<Props> = props => {
|
||||
requestQueryParamsOnChange={requestQueryParamsOnChange}
|
||||
requestAddHeadersOnChange={requestAddHeadersOnChange}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
requestBodyEnabledOnChange={requestBodyEnabledOnChange}
|
||||
requestSampleInputOnChange={requestSampleInputOnChange}
|
||||
requestContentTypeOnChange={requestContentTypeOnChange}
|
||||
requestUrlTransformOnChange={requestUrlTransformOnChange}
|
||||
|
@ -14,7 +14,6 @@ import {
|
||||
setRequestBodyError,
|
||||
setRequestSampleInput,
|
||||
setRequestTransformedBody,
|
||||
setEnableRequestBody,
|
||||
setRequestContentType,
|
||||
setRequestUrlTransform,
|
||||
setRequestTransformState,
|
||||
@ -25,7 +24,10 @@ import {
|
||||
RequestTransformContentType,
|
||||
RequestTransformMethod,
|
||||
} from '@/metadata/types';
|
||||
import { KeyValuePair } from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import {
|
||||
KeyValuePair,
|
||||
RequestTransformStateBody,
|
||||
} from '@/components/Common/ConfigureTransformation/stateDefaults';
|
||||
import ConfigureTransformation from '@/components/Common/ConfigureTransformation/ConfigureTransformation';
|
||||
import requestAction from '@/utils/requestAction';
|
||||
import Endpoints from '@/Endpoints';
|
||||
@ -162,14 +164,10 @@ const Modify: React.FC<Props> = props => {
|
||||
transformDispatch(setRequestAddHeaders(requestAddHeaders));
|
||||
};
|
||||
|
||||
const requestBodyOnChange = (requestBody: string) => {
|
||||
const requestBodyOnChange = (requestBody: RequestTransformStateBody) => {
|
||||
transformDispatch(setRequestBody(requestBody));
|
||||
};
|
||||
|
||||
const requestBodyEnabledOnChange = (enableRequestBody: boolean) => {
|
||||
transformDispatch(setEnableRequestBody(enableRequestBody));
|
||||
};
|
||||
|
||||
const requestBodyErrorOnChange = (requestBodyError: string) => {
|
||||
transformDispatch(setRequestBodyError(requestBodyError));
|
||||
};
|
||||
@ -379,6 +377,7 @@ const Modify: React.FC<Props> = props => {
|
||||
save={saveWrapper('headers')}
|
||||
/>
|
||||
<ConfigureTransformation
|
||||
transformationType="event"
|
||||
state={transformState}
|
||||
resetSampleInput={resetSampleInput}
|
||||
envVarsOnChange={envVarsOnChange}
|
||||
@ -388,7 +387,6 @@ const Modify: React.FC<Props> = props => {
|
||||
requestQueryParamsOnChange={requestQueryParamsOnChange}
|
||||
requestAddHeadersOnChange={requestAddHeadersOnChange}
|
||||
requestBodyOnChange={requestBodyOnChange}
|
||||
requestBodyEnabledOnChange={requestBodyEnabledOnChange}
|
||||
requestSampleInputOnChange={requestSampleInputOnChange}
|
||||
requestContentTypeOnChange={requestContentTypeOnChange}
|
||||
requestUrlTransformOnChange={requestUrlTransformOnChange}
|
||||
|
@ -897,6 +897,17 @@ export type RequestTransformContentType =
|
||||
| 'application/json'
|
||||
| 'application/x-www-form-urlencoded';
|
||||
|
||||
export type RequestTransformBodyActions =
|
||||
| 'remove'
|
||||
| 'transform'
|
||||
| 'x_www_form_urlencoded';
|
||||
|
||||
export type RequestTransformBody = {
|
||||
action: RequestTransformBodyActions;
|
||||
template?: string;
|
||||
form_template?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type RequestTransformHeaders = {
|
||||
add_headers?: Record<string, string>;
|
||||
remove_headers?: string[];
|
||||
@ -920,7 +931,7 @@ interface RequestTransformV1 extends RequestTransformFields {
|
||||
|
||||
interface RequestTransformV2 extends RequestTransformFields {
|
||||
version: 2;
|
||||
body?: Record<string, Nullable<string>>;
|
||||
body?: RequestTransformBody;
|
||||
}
|
||||
|
||||
export type RequestTransform = RequestTransformV1 | RequestTransformV2;
|
||||
|
@ -380,117 +380,32 @@ then you should provide the template URL as `{{$base_url}}/{{escapeUri $session_
|
||||
|
||||
:::
|
||||
|
||||
### Request Content-Type
|
||||
|
||||
You can change the `Content-Type` of the request to either `application/json` or `x-www-form-urlencoded`. The default is `application/json`.
|
||||
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
Console support coming soon.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
||||
Update the `actions.yaml` file inside the `metadata` directory and add a [request_transform][RequestTransformation] field to the action:
|
||||
|
||||
```yaml {9}
|
||||
- name: create_user
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: https://action.my_app.com/create-user
|
||||
timeout: 60
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
method: POST
|
||||
content_type: application/json
|
||||
url: '{{$base_url}}/create_user'
|
||||
query_params:
|
||||
id: '{{$session_variables[''x-hasura-user-id'']}}'
|
||||
body: '{"username": {{$body.input.username}}}'
|
||||
comment: Custom action to create user
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
|
||||
```bash
|
||||
hasura metadata apply
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="api" label="API">
|
||||
|
||||
REST Connectors can be configured for actions using the [create_action][metadata-create-action] or
|
||||
[update_action][metadata-update-action] metadata APIs by adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {31}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
{
|
||||
"type":"create_action",
|
||||
"args":{
|
||||
"name":"create_user",
|
||||
"definition":{
|
||||
"kind":"synchronous",
|
||||
"arguments":[
|
||||
{
|
||||
"name":"username",
|
||||
"type":"String!"
|
||||
},
|
||||
{
|
||||
"name":"email",
|
||||
"type":"String!"
|
||||
}
|
||||
],
|
||||
"output_type":"User",
|
||||
"handler":"{{ACTION_BASE_URL}}",
|
||||
"timeout":60,
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"method": "POST",
|
||||
"url": "{{$base_url}}/create_user",
|
||||
"query_params": {
|
||||
"id": "{{$session_variables['x-hasura-user-id']}}"
|
||||
},
|
||||
"content_type": "application/json",
|
||||
"body": "{\"username\": {{$body.input.username}}}"
|
||||
}
|
||||
},
|
||||
"comment": "Custom action to create user"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
With `x-www-form-urlencoded`, the key-value pairs in `body` are transformed to `name={{$body.input.name}}&key2={{$body.input.email}}`.
|
||||
|
||||
### Request Body
|
||||
|
||||
You can generate a custom request body by configuring a template to transform the default payload to a custom payload.
|
||||
The `body` field takes a template in the [Kriti templating language](https://github.com/hasura/kriti-lang) to evaluate the transform.
|
||||
You can generate a custom request body by configuring a template to transform the default payload to a custom payload. Request body could be provided using the `body` field
|
||||
as an [object](/graphql/core/api-reference/syntax-defs.mdx/#bodytransform), which additionally gives the ability to disable request body,
|
||||
transform request body to `application/json`, or transform request body to `x_www_form_urlencoded` formats.
|
||||
|
||||
- [Disabling Request Body](#disabling-request-body)
|
||||
- [Request Body with application/json format](#request-body-with-applicationjson-format)
|
||||
- [Request Body with x_www_form_urlencoded format](#request-body-with-x_www_form_urlencoded-format)
|
||||
|
||||
##### Disabling Request Body
|
||||
|
||||
If you are using a `GET` request, you might want to not send any request body, and additionally not send a `content-type` header to the webhook. You can do that using the disable body feature.
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
In the `Configure REST Connectors` section, click on `Add Payload Transform`:
|
||||
|
||||
A sample payload input auto-generated based on your schema is shown.
|
||||
In the `Configure REST Connectors` section, click on `Add Request Options Transform`, and convert the `Request Method` as `GET`.
|
||||
Then click on `Add Payload Transform`, disable the payload body by using the dropdown next to the `Configure Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/actions/transform-body.png"
|
||||
alt="Add payload transformation"
|
||||
src="/img/graphql/core/actions/transform-body-disable.png"
|
||||
alt="Disable payload body"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
The transformed sample payload should be shown as the `Transformed Request Body` given all required [sample context](#action-transforms-sample-context) is set.
|
||||
|
||||
Hit `Save Action` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
@ -498,7 +413,7 @@ Hit `Save Action` to apply your changes.
|
||||
|
||||
Update the `actions.yaml` file inside the `metadata` directory and add a [request_transform][RequestTransformation] field to the action:
|
||||
|
||||
```yaml {13}
|
||||
```yaml {8-9,13-16}
|
||||
- name: create_user
|
||||
definition:
|
||||
kind: synchronous
|
||||
@ -506,12 +421,15 @@ Update the `actions.yaml` file inside the `metadata` directory and add a [reques
|
||||
timeout: 60
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
method: POST
|
||||
content_type: application/json
|
||||
version: 2
|
||||
method: GET
|
||||
url: '{{$base_url}}/create_user'
|
||||
query_params:
|
||||
id: '{{$session_variables[''x-hasura-user-id'']}}'
|
||||
body: '{"username": {{$body.input.username}}}'
|
||||
body:
|
||||
action: 'remove'
|
||||
request_headers:
|
||||
remove_headers: ['content-type]
|
||||
comment: Custom action to create user
|
||||
```
|
||||
|
||||
@ -528,7 +446,7 @@ REST Connectors can be configured for actions using the [create_action][metadata
|
||||
[update_action][metadata-update-action] metadata APIs by adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {32}
|
||||
```http {26-27,32-37}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
@ -554,13 +472,18 @@ X-Hasura-Role: admin
|
||||
"timeout":60,
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"method": "POST",
|
||||
"version": 2,
|
||||
"method": "GET",
|
||||
"url": "{{$base_url}}/create_user",
|
||||
"query_params": {
|
||||
"id": "{{$session_variables['x-hasura-user-id']}}"
|
||||
},
|
||||
"content_type": "application/json",
|
||||
"body": "{\"username\": {{$body.input.username}}}"
|
||||
"body": {
|
||||
"action": "remove"
|
||||
},
|
||||
"request_headers": {
|
||||
"remove_headers": ["content-type"],
|
||||
},
|
||||
}
|
||||
},
|
||||
"comment": "Custom action to create user"
|
||||
@ -571,6 +494,226 @@ X-Hasura-Role: admin
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
##### Request Body with application/json format
|
||||
|
||||
You can transform Request Body to `application/json` format using the following steps:
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
In the `Configure REST Connectors` section, click on `Add Payload Transform`.
|
||||
By default console sends the body as `application/json` which can be seen in the dropdown next to the `Configure Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/actions/transform-body-application-json.png"
|
||||
alt="payload body application/json"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
Hit `Save Action` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
||||
Update the `actions.yaml` file inside the `metadata` directory and add a [request_transform][RequestTransformation] field to the action:
|
||||
|
||||
```yaml {8,13-15}
|
||||
- name: create_user
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: https://action.my_app.com/create-user
|
||||
timeout: 60
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
version: 2
|
||||
method: POST
|
||||
url: '{{$base_url}}/create_user'
|
||||
query_params:
|
||||
id: '{{$session_variables[''x-hasura-user-id'']}}'
|
||||
body:
|
||||
action: 'transform'
|
||||
template: '{"username": {{$body.input.username}}}'
|
||||
comment: Custom action to create user
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
|
||||
```bash
|
||||
hasura metadata apply
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="api" label="API">
|
||||
|
||||
REST Connectors can be configured for actions using the [create_action][metadata-create-action] or
|
||||
[update_action][metadata-update-action] metadata APIs by adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {26,32-35}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
{
|
||||
"type":"create_action",
|
||||
"args":{
|
||||
"name":"create_user",
|
||||
"definition":{
|
||||
"kind":"synchronous",
|
||||
"arguments":[
|
||||
{
|
||||
"name":"username",
|
||||
"type":"String!"
|
||||
},
|
||||
{
|
||||
"name":"email",
|
||||
"type":"String!"
|
||||
}
|
||||
],
|
||||
"output_type":"User",
|
||||
"handler":"{{ACTION_BASE_URL}}",
|
||||
"timeout":60,
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"version": 2,
|
||||
"method": "POST",
|
||||
"url": "{{$base_url}}/create_user",
|
||||
"query_params": {
|
||||
"id": "{{$session_variables['x-hasura-user-id']}}"
|
||||
},
|
||||
"body": {
|
||||
"action": "transform"
|
||||
"template": "{\"username\": {{$body.input.username}}}"
|
||||
},
|
||||
}
|
||||
},
|
||||
"comment": "Custom action to create user"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
##### Request Body with x_www_form_urlencoded format
|
||||
|
||||
While doing `x_www_form_urlencoded` transformation, please note that as all changes to the request must be made explicit when calling the API,
|
||||
so you will need to remove the default `application/json` header and add a `application/x-www-form-urlencoded` header.
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
In the `Configure REST Connectors` section, click on `Add Payload Transform`.
|
||||
Change the dropdown next to `Configure Request Body` section to `x_www_form_urlencoded`. You can see the body transformed body in the `Transformed Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/actions/transform-body-xurl-formencoded.png"
|
||||
alt="payload body x_www_form_urlencoded"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
Hit `Save Action` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
||||
Update the `actions.yaml` file inside the `metadata` directory and add a [request_transform][RequestTransformation] field to the action:
|
||||
|
||||
```yaml {8,13-20}
|
||||
- name: create_user
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: https://action.my_app.com/create-user
|
||||
timeout: 60
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
version: 2
|
||||
method: POST
|
||||
url: '{{$base_url}}/create_user'
|
||||
query_params:
|
||||
id: '{{$session_variables[''x-hasura-user-id'']}}'
|
||||
body:
|
||||
action: 'x_www_form_urlencoded'
|
||||
form_template:
|
||||
username: '{{$body.input.username}}'
|
||||
request_headers:
|
||||
remove_headers: ['content-type']
|
||||
add_headers:
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
|
||||
comment: Custom action to create user
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
|
||||
```bash
|
||||
hasura metadata apply
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="api" label="API">
|
||||
|
||||
REST Connectors can be configured for actions using the [create_action][metadata-create-action] or
|
||||
[update_action][metadata-update-action] metadata APIs by adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {26,32-43}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
{
|
||||
"type":"create_action",
|
||||
"args":{
|
||||
"name":"create_user",
|
||||
"definition":{
|
||||
"kind":"synchronous",
|
||||
"arguments":[
|
||||
{
|
||||
"name":"username",
|
||||
"type":"String!"
|
||||
},
|
||||
{
|
||||
"name":"email",
|
||||
"type":"String!"
|
||||
}
|
||||
],
|
||||
"output_type":"User",
|
||||
"handler":"{{ACTION_BASE_URL}}",
|
||||
"timeout":60,
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"version": 2,
|
||||
"method": "POST",
|
||||
"url": "{{$base_url}}/create_user",
|
||||
"query_params": {
|
||||
"id": "{{$session_variables['x-hasura-user-id']}}"
|
||||
},
|
||||
"body": {
|
||||
"action": "x_www_form_urlencoded",
|
||||
"form_template": {
|
||||
"username": "{{$body.input.username}}"
|
||||
},
|
||||
},
|
||||
"request_headers": {
|
||||
"remove_headers": ["content-type"],
|
||||
"add_headers": {
|
||||
"content-type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
"comment": "Custom action to create user"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
Let's integrate Auth0's management API to update the profile of a user:
|
||||
|
@ -1269,15 +1269,20 @@ Enum](https://spec.graphql.org/June2018/#sec-Enums)
|
||||
|
||||
| Key | required | Schema | Description |
|
||||
|-----------------|----------|----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| version | false | "1" \| "2" | Sets the `RequestTransformation` schema version. Version `1` uses a `String` for the `body` field and Version `2` takes a [BodyTransform](#bodytransform). Defaults to version `1`. Warning: You must remove any "version 2" schemas from your metadata prior to downgrading to `v2.4.0` or earlier |
|
||||
| version | false | "1" \| "2" | Sets the `RequestTransformation` schema version. Version `1` uses a `String` for the `body` field and Version `2` takes a [BodyTransform](#bodytransform). Defaults to version `1`. |
|
||||
| method | false | String | Change the request method to this value. |
|
||||
| url | false | String | Change the request URL to this value. |
|
||||
| body | false | [BodyTransform](#bodytransform) \| String | A template script for transforming the request body. |
|
||||
| content_type | false | String | Replace the Content-Type with this value. Only "application/json" and "application/x-www-form-urlencoded" are allowed. Default: "application/json" |
|
||||
| content_type | false | String | Replace the Content-Type with this value. Default: "application/json" *(valid only for version 1)* |
|
||||
| query_params | false | Object (String : String) | Replace the query params on the URL with this value. |
|
||||
| request_headers | false | [TransformHeaders](#transformheaders) | Request Header Transformation. |
|
||||
| template_engine | false | [TemplateEngine](#templateengine) | Template language to be used for this transformation. Default: "Kriti" |
|
||||
|
||||
:::tip Supported from
|
||||
|
||||
Version 2 is supported in `v2.5.0` and above. You must remove any "version 2" schemas from your metadata prior to downgrading to `v2.4.0` or earlier
|
||||
|
||||
:::
|
||||
|
||||
:::info Note
|
||||
|
||||
@ -1350,7 +1355,7 @@ HGE provides the following functions that can be used in the template:
|
||||
|
||||
| Key | required | Schema | Description |
|
||||
|---------------|----------|---------------------|--------------------------------------------------------------------------------------------------------|
|
||||
| action | true | remove \| transform | The action to perform on the request body. |
|
||||
| action | true | remove \| transform \| x_www_form_urlencoded | The action to perform on the request body. |
|
||||
| template | false | String | The transformation template to be applied to the body. This is required if the action is *transform*. |
|
||||
| form_template | false | Object ([String](/graphql/core/databases/postgres/postgresql-types.mdx#string) : [String](/graphql/core/databases/postgres/postgresql-types.mdx#string)) | The key/value pairs to be used in a `x-www-url-formencoded` body. The values can be transfomation templates. |
|
||||
|
||||
|
@ -86,7 +86,7 @@ You can configure REST Connectors for event triggers using the
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {25-34}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
@ -98,7 +98,7 @@ X-Hasura-Role: admin
|
||||
"source": "default",
|
||||
"table": {
|
||||
"name": "users",
|
||||
"schema": "public"
|
||||
"schema": "public"
|
||||
},
|
||||
"webhook": "https://api.somedomain.com",
|
||||
"insert": {
|
||||
@ -406,22 +406,41 @@ contain non-ASCII values, then you should provide the template URL as
|
||||
|
||||
:::
|
||||
|
||||
### Request Content-Type
|
||||
### Request Body
|
||||
|
||||
You can change the `Content-Type` of the request to either `application/json` or `x-www-form-urlencoded`. The default is `application/json`.
|
||||
You can generate a custom request body by configuring a template to transform the default payload to a custom payload. Request body could be provided using the `body` field
|
||||
as an [object](/graphql/core/api-reference/syntax-defs.mdx/#bodytransform), which additionally gives the ability to disable request body,
|
||||
transform request body to `application/json`, or transform request body to `x_www_form_urlencoded` formats.
|
||||
|
||||
- [Disabling Request Body](#disabling-request-body)
|
||||
- [Request Body with application/json format](#request-body-with-applicationjson-format)
|
||||
- [Request Body with x_www_form_urlencoded format](#request-body-with-x_www_form_urlencoded-format)
|
||||
|
||||
##### Disabling Request Body
|
||||
|
||||
If you are using a `GET` request, you might want to not send any request body, and additionally not send a `content-type` header to the webhook. You can do that using the disable body feature.
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
Console support coming soon.
|
||||
In the `Configure REST Connectors` section, click on `Add Request Options Transform`, and convert the `Request Method` as `GET`.
|
||||
Then click on `Add Payload Transform`, disable the payload body by using the dropdown next to the `Configure Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/event-triggers/transform-body-disable.png"
|
||||
alt="Disable payload body"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
Hit `Create Event Trigger` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
||||
Update the `databases > [source-name] > tables > [table-name].yaml` file
|
||||
inside the `metadata` directory and add a [request_transform][RequestTransformation] field to the event trigger:
|
||||
Update the `databases > [source-name] > tables > [table-name].yaml` file inside the `metadata` directory and add a
|
||||
[request_transform][RequestTransformation] field to the event trigger:
|
||||
|
||||
```yaml {19}
|
||||
```yaml {15-16,20-23}
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
@ -436,12 +455,15 @@ event_triggers:
|
||||
value: bearer-xxxx
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
method: POST
|
||||
version: 2
|
||||
method: GET
|
||||
url: "{{$base_url}}/api/v3/endpoint"
|
||||
query_params:
|
||||
query_param: xxxxx
|
||||
content_type: application/json
|
||||
body: "{\n \"table\": {\n \"name\": {{$body.table.name}},\n \"schema\": {{$body.table.schema}}\n },\n \"To\": {\n \"username\": {{$body.event.data.new.name}},\n \"email\": {{$body.event.data.new.email}}\n }\n}"
|
||||
body:
|
||||
action: 'remove'
|
||||
request_headers:
|
||||
remove_headers: ['content-type]
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
@ -457,8 +479,8 @@ You can configure REST Connectors for event triggers using the
|
||||
[pg_create_event_trigger][metadata-pg-create-event-trigger] metadata API and adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {32}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
```http {27-28,33-38}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
@ -484,13 +506,18 @@ X-Hasura-Role: admin
|
||||
],
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"method": "POST",
|
||||
"version": 2,
|
||||
"method": "GET",
|
||||
"url": "{{$base_url}}/api/v3/endpoint",
|
||||
"query_params": {
|
||||
"query_param": "xxxxx"
|
||||
},
|
||||
"content_type": "application/json",
|
||||
"body": "{\n \"table\": {\n \"name\": {{$body.table.name}},\n \"schema\": {{$body.table.schema}}\n },\n \"To\": {\n \"username\": {{$body.event.data.new.name}},\n \"email\": {{$body.event.data.new.email}}\n }\n}"
|
||||
"body": {
|
||||
"action": "remove"
|
||||
},
|
||||
"request_headers": {
|
||||
"remove_headers": ["content-type"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -499,40 +526,24 @@ X-Hasura-Role: admin
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
With `x-www-form-urlencoded`, the key-value pairs in `body` are transformed to `name={{$body.input.name}}&key2={{$body.input.email}}`.
|
||||
|
||||
### Request Body
|
||||
##### Request Body with application/json format
|
||||
|
||||
You can generate a custom request body by configuring a template to transform the default payload to a custom payload.
|
||||
The `body` field takes a template in the [Kriti templating language](https://github.com/hasura/kriti-lang) to evaluate the transform.
|
||||
|
||||
For example, you can obtain the following transformed event trigger request body for a `users` table:
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/event-triggers/transform-request-body.png"
|
||||
alt="Transformed Request Body"
|
||||
width="900px"
|
||||
/>
|
||||
You can transform Request Body to `application/json` format using the following steps:
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
Head to `Events > [event_trigger_name] > Modify` tab. Under `Configure REST Connectors` click on `Add Payload Transform`.
|
||||
|
||||
A sample payload input auto-generated based on your schema is shown.
|
||||
|
||||
Under `Configure Request Body` enter the required request body template:
|
||||
In the `Configure REST Connectors` section, click on `Add Payload Transform`.
|
||||
By default console sends the body as `application/json` which can be seen in the dropdown next to the `Configure Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/event-triggers/transform-generic-request-body.png"
|
||||
alt="Configure request body"
|
||||
src="/img/graphql/core/event-triggers/transform-body-application-json.png"
|
||||
alt="payload body application/json"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
The transformed sample payload should be shown as the `Transformed Request Body` given all required
|
||||
[sample context](#event-trigger-transforms-sample-context) is set.
|
||||
|
||||
Hit `Save Event Trigger` to apply your changes.
|
||||
Hit `Create Event Trigger` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
@ -540,7 +551,7 @@ Hit `Save Event Trigger` to apply your changes.
|
||||
Update the `databases > [source-name] > tables > [table-name].yaml` file inside the `metadata` directory and add a
|
||||
[request_transform][RequestTransformation] field to the event trigger:
|
||||
|
||||
```yaml {20}
|
||||
```yaml {15,20-22}
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
@ -555,18 +566,20 @@ event_triggers:
|
||||
value: bearer-xxxx
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
version: 2
|
||||
method: POST
|
||||
url: "{{$base_url}}/api/v3/endpoint"
|
||||
query_params:
|
||||
query_param: xxxxx
|
||||
content_type: application/json
|
||||
body: "{\n \"table\": {\n \"name\": {{$body.table.name}},\n \"schema\": {{$body.table.schema}}\n },\n \"To\": {\n \"username\": {{$body.event.data.new.name}},\n \"email\": {{$body.event.data.new.email}}\n }\n}"
|
||||
body:
|
||||
action: 'transform'
|
||||
template: '{"username": {{$body.table.username}}}'
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
|
||||
```bash
|
||||
hasura metadata apply
|
||||
hasura metadata apply
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -576,8 +589,8 @@ You can configure REST Connectors for event triggers using the
|
||||
[pg_create_event_trigger][metadata-pg-create-event-trigger] metadata API and adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {33}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
```http {27,33-36}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
@ -603,13 +616,16 @@ X-Hasura-Role: admin
|
||||
],
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"version": 2,
|
||||
"method": "POST",
|
||||
"url": "{{$base_url}}/api/v3/endpoint",
|
||||
"query_params": {
|
||||
"query_param": "xxxxx"
|
||||
},
|
||||
"content_type": "application/json",
|
||||
"body": "{\n \"table\": {\n \"name\": {{$body.table.name}},\n \"schema\": {{$body.table.schema}}\n },\n \"To\": {\n \"username\": {{$body.event.data.new.name}},\n \"email\": {{$body.event.data.new.email}}\n }\n}"
|
||||
"body": {
|
||||
"action": "transform",
|
||||
"template": "{\"username\": {{$body.table.username}}}"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,6 +634,129 @@ X-Hasura-Role: admin
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
##### Request Body with x_www_form_urlencoded format
|
||||
|
||||
While doing `x_www_form_urlencoded` transformation, please note that as all changes to the request must be made explicit when calling the API,
|
||||
so you will need to remove the default `application/json` header and add a `application/x-www-form-urlencoded` header.
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
In the `Configure REST Connectors` section, click on `Add Payload Transform`.
|
||||
Change the dropdown next to `Configure Request Body` section to `x_www_form_urlencoded`. You can see the body transformed body in the `Transformed Request Body` section.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/event-triggers/transform-body-xurl-formencoded.png"
|
||||
alt="payload body x_www_form_urlencoded"
|
||||
width="1100px"
|
||||
/>
|
||||
|
||||
Hit `Create Event Trigger` to apply your changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
||||
Update the `databases > [source-name] > tables > [table-name].yaml` file inside the `metadata` directory and add a
|
||||
[request_transform][RequestTransformation] field to the event trigger:
|
||||
|
||||
```yaml {15,20-27}
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
event_triggers:
|
||||
- name: insert_trigger_on_users
|
||||
definition:
|
||||
insert:
|
||||
columns: "*"
|
||||
webhook: https://api.somedomain.com
|
||||
headers:
|
||||
- name: Authorization
|
||||
value: bearer-xxxx
|
||||
request_transform:
|
||||
template_engine: Kriti
|
||||
version: 2
|
||||
method: POST
|
||||
url: "{{$base_url}}/api/v3/endpoint"
|
||||
query_params:
|
||||
query_param: xxxxx
|
||||
body:
|
||||
action: 'x_www_form_urlencoded'
|
||||
form_template:
|
||||
username: '{{$body.table.username}}'
|
||||
request_headers:
|
||||
remove_headers: ['content-type']
|
||||
add_headers:
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
```
|
||||
|
||||
Apply the metadata by running:
|
||||
|
||||
```bash
|
||||
hasura metadata apply
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="api" label="API">
|
||||
|
||||
You can configure REST Connectors for event triggers using the
|
||||
[pg_create_event_trigger][metadata-pg-create-event-trigger] metadata API and adding a
|
||||
[request_transform][RequestTransformation] field to the args:
|
||||
|
||||
```http {27,33-44}
|
||||
POST /v1/metadata HTTP/1.1
|
||||
Content-Type: application/json
|
||||
X-Hasura-Role: admin
|
||||
|
||||
{
|
||||
"type": "pg_create_event_trigger",
|
||||
"args": {
|
||||
"name": "insert_trigger_on_users",
|
||||
"replace": true,
|
||||
"source": "default",
|
||||
"table": {
|
||||
"name": "users",
|
||||
"schema": "public"
|
||||
},
|
||||
"webhook": "https://api.somedomain.com",
|
||||
"insert": {
|
||||
"columns": "*"
|
||||
},
|
||||
"headers": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"value": "bearer xxxx"
|
||||
}
|
||||
],
|
||||
"request_transform": {
|
||||
"template_engine": "Kriti",
|
||||
"version": 2,
|
||||
"method": "POST",
|
||||
"url": "{{$base_url}}/api/v3/endpoint",
|
||||
"query_params": {
|
||||
"query_param": "xxxxx"
|
||||
},
|
||||
"body": {
|
||||
"action": "x_www_form_urlencoded",
|
||||
"form_template": {
|
||||
"username": "{{$body.table.username}}"
|
||||
},
|
||||
},
|
||||
"request_headers": {
|
||||
"remove_headers": ["content-type"],
|
||||
"add_headers": {
|
||||
"content-type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Example: Trigger SendGrid's Mail Send API
|
||||
|
||||
To see the REST Connectors for event triggers in action, let's set up an event trigger to send an email using the [SendGrid Mail Send API](https://docs.sendgrid.com/api-reference/mail-send/mail-send).
|
||||
|
BIN
docs/static/img/graphql/core/actions/transform-body-application-json.png
vendored
Normal file
BIN
docs/static/img/graphql/core/actions/transform-body-application-json.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
BIN
docs/static/img/graphql/core/actions/transform-body-disable.png
vendored
Normal file
BIN
docs/static/img/graphql/core/actions/transform-body-disable.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
BIN
docs/static/img/graphql/core/actions/transform-body-xurl-formencoded.png
vendored
Normal file
BIN
docs/static/img/graphql/core/actions/transform-body-xurl-formencoded.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 124 KiB |
BIN
docs/static/img/graphql/core/event-triggers/transform-body-application-json.png
vendored
Normal file
BIN
docs/static/img/graphql/core/event-triggers/transform-body-application-json.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
BIN
docs/static/img/graphql/core/event-triggers/transform-body-disable.png
vendored
Normal file
BIN
docs/static/img/graphql/core/event-triggers/transform-body-disable.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
BIN
docs/static/img/graphql/core/event-triggers/transform-body-xurl-formencoded.png
vendored
Normal file
BIN
docs/static/img/graphql/core/event-triggers/transform-body-xurl-formencoded.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
Loading…
Reference in New Issue
Block a user