mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
feat: refactor of rest endpoint details component
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9783 GitOrigin-RevId: b40ef6dafd699c51da1089d0b6687c9cf934e275
This commit is contained in:
parent
fdddac8057
commit
9eb1097957
@ -280,7 +280,7 @@ export const supportedNumericTypes = [
|
|||||||
'decimal',
|
'decimal',
|
||||||
];
|
];
|
||||||
|
|
||||||
const getValueWithType = (variableData: VariableState) => {
|
export const getValueWithType = (variableData: VariableState) => {
|
||||||
if (variableData.type === 'Boolean') {
|
if (variableData.type === 'Boolean') {
|
||||||
if (variableData.value.trim().toLowerCase() === 'false') {
|
if (variableData.value.trim().toLowerCase() === 'false') {
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,7 +41,20 @@ describe('useOperationsFromQueryCollection with no query collections', () => {
|
|||||||
|
|
||||||
const operations = result.current.data!;
|
const operations = result.current.data!;
|
||||||
|
|
||||||
expect(operations[0].query).toEqual('query MyQuery { user { email name}}');
|
expect(operations[0].query)
|
||||||
|
.toEqual(`mutation update_user_by_pk($id: Int!, $object: user_set_input!) {
|
||||||
|
update_user_by_pk(pk_columns: {id: $id}, _set: $object) {
|
||||||
|
address
|
||||||
|
bool
|
||||||
|
count
|
||||||
|
date
|
||||||
|
email
|
||||||
|
id
|
||||||
|
name
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
expect(operations).toHaveLength(3);
|
expect(operations).toHaveLength(3);
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,22 @@ export const queryCollectionInitialData: Partial<Metadata['metadata']> = {
|
|||||||
name: 'allowed-queries',
|
name: 'allowed-queries',
|
||||||
definition: {
|
definition: {
|
||||||
queries: [
|
queries: [
|
||||||
{ name: 'MyQuery', query: 'query MyQuery { user { email name}}' },
|
{
|
||||||
|
name: 'MyQuery',
|
||||||
|
query: `mutation update_user_by_pk($id: Int!, $object: user_set_input!) {
|
||||||
|
update_user_by_pk(pk_columns: {id: $id}, _set: $object) {
|
||||||
|
address
|
||||||
|
bool
|
||||||
|
count
|
||||||
|
date
|
||||||
|
email
|
||||||
|
id
|
||||||
|
name
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
{ name: 'MyQuery2', query: 'query MyQuery2 { user { email name}}' },
|
{ name: 'MyQuery2', query: 'query MyQuery2 { user { email name}}' },
|
||||||
{ name: 'MyQuery3', query: 'query MyQuery3 { user { email name}}' },
|
{ name: 'MyQuery3', query: 'query MyQuery3 { user { email name}}' },
|
||||||
],
|
],
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
import { FaPlus } from 'react-icons/fa';
|
||||||
|
import { Button } from '../../../../new-components/Button';
|
||||||
|
import { Collapsible } from '../../../../new-components/Collapsible';
|
||||||
|
import { Header } from './RestEndpointDetails';
|
||||||
|
import { CardedTable } from '../../../../new-components/CardedTable';
|
||||||
|
import { Checkbox } from '../../../../new-components/Form';
|
||||||
|
|
||||||
|
type RequestHeadersProps = {
|
||||||
|
headers: Header[];
|
||||||
|
setHeaders: (headers: Header[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RequestHeaders = (props: RequestHeadersProps) => {
|
||||||
|
const { headers, setHeaders } = props;
|
||||||
|
return (
|
||||||
|
<Collapsible
|
||||||
|
defaultOpen
|
||||||
|
triggerChildren={
|
||||||
|
<div className="font-semibold text-muted">Request Headers</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute top-0 right-0">
|
||||||
|
<Button
|
||||||
|
icon={<FaPlus />}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
setHeaders([...headers, { name: '', value: '', selected: true }]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Header
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="font-semibold text-muted mb-4">Headers List</div>
|
||||||
|
<CardedTable
|
||||||
|
showActionCell
|
||||||
|
columns={[
|
||||||
|
<Checkbox
|
||||||
|
checked={headers.every(header => header.selected)}
|
||||||
|
onCheckedChange={checked =>
|
||||||
|
setHeaders(
|
||||||
|
headers.map(header => ({
|
||||||
|
...header,
|
||||||
|
selected: !!checked,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
'Name',
|
||||||
|
'Value',
|
||||||
|
]}
|
||||||
|
data={headers.map((header, i) => [
|
||||||
|
<Checkbox
|
||||||
|
checked={header.selected}
|
||||||
|
onCheckedChange={checked =>
|
||||||
|
setHeaders(
|
||||||
|
headers.map(h => ({
|
||||||
|
...h,
|
||||||
|
selected: h.name === header.name ? !!checked : h.selected,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
<input
|
||||||
|
data-testid={`header-name-${i}`}
|
||||||
|
placeholder="Enter name..."
|
||||||
|
className="w-full"
|
||||||
|
value={header.name}
|
||||||
|
onChange={e =>
|
||||||
|
setHeaders(
|
||||||
|
headers.map(h => ({
|
||||||
|
...h,
|
||||||
|
name: h.name === header.name ? e.target.value : h.name,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
<input
|
||||||
|
data-testid={`header-value-${i}`}
|
||||||
|
placeholder="Enter value..."
|
||||||
|
className="w-full"
|
||||||
|
value={header.value}
|
||||||
|
onChange={e =>
|
||||||
|
setHeaders(
|
||||||
|
headers.map(h => ({
|
||||||
|
...h,
|
||||||
|
value: h.name === header.name ? e.target.value : h.value,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
|
||||||
|
(headers.length > 1 ||
|
||||||
|
headers?.[0]?.name ||
|
||||||
|
headers?.[0]?.value) && (
|
||||||
|
<Button
|
||||||
|
mode="destructive"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
const newHeaders = headers
|
||||||
|
.slice(0, i)
|
||||||
|
.concat(headers.slice(i + 1));
|
||||||
|
|
||||||
|
if (newHeaders.length === 0) {
|
||||||
|
newHeaders.push({
|
||||||
|
name: '',
|
||||||
|
value: '',
|
||||||
|
selected: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setHeaders(newHeaders);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,75 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StoryObj, Meta } from '@storybook/react';
|
||||||
|
import { within, userEvent, waitFor } from '@storybook/testing-library';
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import {
|
||||||
|
RestEndpointDetails,
|
||||||
|
RestEndpointDetailsProps,
|
||||||
|
} from './RestEndpointDetails';
|
||||||
|
import { ReactQueryDecorator } from '../../../../storybook/decorators/react-query';
|
||||||
|
import { handlers } from '../../../../mocks/metadata.mock';
|
||||||
|
import { rest } from 'msw';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Features/REST endpoints/Rest Endpoint Details',
|
||||||
|
component: RestEndpointDetails,
|
||||||
|
decorators: [ReactQueryDecorator()],
|
||||||
|
parameters: {
|
||||||
|
msw: [
|
||||||
|
...handlers({ delay: 0 }),
|
||||||
|
rest.post('**/api/rest/test/1', (req, res, ctx) =>
|
||||||
|
res(
|
||||||
|
ctx.delay(0),
|
||||||
|
ctx.json({
|
||||||
|
data: {
|
||||||
|
update_user_by_pk: {
|
||||||
|
id: 1,
|
||||||
|
name: 'Hasura',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
argTypes: {},
|
||||||
|
} satisfies Meta<typeof RestEndpointDetails>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export const Default: StoryObj<RestEndpointDetailsProps> = {
|
||||||
|
render: args => {
|
||||||
|
return <RestEndpointDetails {...args} name="MyQuery" />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Default.play = async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(canvas.queryByText('Run Request')).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
// await expect(screen.queryByText('user')).toBeInTheDocument();
|
||||||
|
|
||||||
|
// // toggle the user permission and check the success notification
|
||||||
|
// await userEvent.click(canvas.getByTestId('user'));
|
||||||
|
// await expect(
|
||||||
|
// await canvas.findByText(`Allow list permissions updated`)
|
||||||
|
// ).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Add new role
|
||||||
|
await userEvent.type(canvas.getByTestId('header-name-0'), 'Authorization');
|
||||||
|
|
||||||
|
await userEvent.type(canvas.getByTestId('header-value-0'), 'Bearer 123');
|
||||||
|
await userEvent.click(canvas.getByText('Add Header'));
|
||||||
|
|
||||||
|
await userEvent.type(canvas.getByTestId('variable-id'), '1');
|
||||||
|
|
||||||
|
await userEvent.type(
|
||||||
|
canvas.getByTestId('variable-object'),
|
||||||
|
'{"object": {"name": "Hasura"}}'
|
||||||
|
);
|
||||||
|
|
||||||
|
await userEvent.click(canvas.getByText('Run Request'));
|
||||||
|
};
|
@ -0,0 +1,198 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import {
|
||||||
|
CheckboxesField,
|
||||||
|
CodeEditorField,
|
||||||
|
InputField,
|
||||||
|
Textarea,
|
||||||
|
useConsoleForm,
|
||||||
|
} from '../../../../new-components/Form';
|
||||||
|
import { Button } from '../../../../new-components/Button';
|
||||||
|
import { FaArrowRight, FaPlay } from 'react-icons/fa';
|
||||||
|
import { useRestEndpoint } from '../../hooks/useRestEndpoint';
|
||||||
|
import { getSessionVarsFromLS } from '../../../../components/Common/ConfigureTransformation/utils';
|
||||||
|
import { parseQueryVariables } from '../../../../components/Services/ApiExplorer/Rest/utils';
|
||||||
|
import { useRestEndpointRequest } from '../../hooks/useRestEndpointRequest';
|
||||||
|
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
|
||||||
|
import { RequestHeaders } from './RequestHeaders';
|
||||||
|
import { Variables } from './Variables';
|
||||||
|
import { AllowedRESTMethods } from '../../../../metadata/types';
|
||||||
|
|
||||||
|
export type Variable = Exclude<
|
||||||
|
ReturnType<typeof parseQueryVariables>,
|
||||||
|
undefined
|
||||||
|
>[0] & {
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Header = {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
selected: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RestEndpointDetailsProps = {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const commonEditorOptions = {
|
||||||
|
showLineNumbers: true,
|
||||||
|
useSoftTabs: true,
|
||||||
|
showPrintMargin: false,
|
||||||
|
showGutter: true,
|
||||||
|
wrap: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestEditorOptions = {
|
||||||
|
...commonEditorOptions,
|
||||||
|
minLines: 10,
|
||||||
|
maxLines: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const responseEditorOptions = {
|
||||||
|
...commonEditorOptions,
|
||||||
|
minLines: 50,
|
||||||
|
maxLines: 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationSchema = z.object({
|
||||||
|
name: z.string().min(1, { message: 'Please add a name' }),
|
||||||
|
comment: z.union([z.string(), z.null()]),
|
||||||
|
url: z.string().min(1, { message: 'Please add a location' }),
|
||||||
|
methods: z
|
||||||
|
.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
|
||||||
|
.array()
|
||||||
|
.nonempty({ message: 'Choose at least one method' }),
|
||||||
|
request: z.string().min(1, { message: 'Please add a GraphQL query' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RestEndpointDetails = (props: RestEndpointDetailsProps) => {
|
||||||
|
const endpoint = useRestEndpoint(props.name);
|
||||||
|
|
||||||
|
const initialHeaders = getSessionVarsFromLS();
|
||||||
|
|
||||||
|
const [headers, setHeaders] = React.useState(
|
||||||
|
initialHeaders.map(header => ({
|
||||||
|
...header,
|
||||||
|
selected: true,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
const [variables, setVariables] = React.useState<Variable[]>([]);
|
||||||
|
|
||||||
|
const { data, refetch, isFetching, error } = useRestEndpointRequest(
|
||||||
|
endpoint?.endpoint,
|
||||||
|
headers,
|
||||||
|
variables
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
Form,
|
||||||
|
methods: { setValue },
|
||||||
|
} = useConsoleForm({
|
||||||
|
schema: validationSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (endpoint?.query?.query) {
|
||||||
|
const parsedVariables = parseQueryVariables(endpoint.query.query);
|
||||||
|
setVariables(parsedVariables?.map(v => ({ ...v, value: '' })) ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint) {
|
||||||
|
setValue('name', endpoint.endpoint?.name);
|
||||||
|
setValue('comment', endpoint?.endpoint?.comment);
|
||||||
|
setValue('url', endpoint?.endpoint?.url);
|
||||||
|
setValue('methods', endpoint?.endpoint?.methods);
|
||||||
|
setValue('request', endpoint?.query?.query);
|
||||||
|
}
|
||||||
|
}, [endpoint?.query?.query, endpoint?.endpoint]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue('response', JSON.stringify(data, null, 2));
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form onSubmit={() => {}}>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<div className="relative">
|
||||||
|
<CodeEditorField
|
||||||
|
disabled
|
||||||
|
editorOptions={requestEditorOptions}
|
||||||
|
description="Support GraphQL queries and mutations."
|
||||||
|
name="request"
|
||||||
|
label="GraphQL Request"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="text-sm absolute top-6 right-0 mt-2 mr-2">
|
||||||
|
<a href="/api/api-explorer">
|
||||||
|
Test it in GraphiQL <FaArrowRight />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
disabled
|
||||||
|
name="comment"
|
||||||
|
label="Description"
|
||||||
|
placeholder="Description"
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
disabled
|
||||||
|
name="url"
|
||||||
|
label="Location"
|
||||||
|
placeholder="Location"
|
||||||
|
description={`This is the location of your endpoint (must be unique). Any parameterized variables`}
|
||||||
|
/>
|
||||||
|
<CheckboxesField
|
||||||
|
disabled
|
||||||
|
name="methods"
|
||||||
|
label="Methods"
|
||||||
|
options={[
|
||||||
|
{ value: 'GET', label: 'GET' },
|
||||||
|
{ value: 'POST', label: 'POST' },
|
||||||
|
{ value: 'PUT', label: 'PUT' },
|
||||||
|
{ value: 'PATCH', label: 'PATCH' },
|
||||||
|
{ value: 'DELETE', label: 'DELETE' },
|
||||||
|
].filter(({ value }) =>
|
||||||
|
endpoint.endpoint?.methods.includes(value as AllowedRESTMethods)
|
||||||
|
)}
|
||||||
|
orientation="horizontal"
|
||||||
|
/>
|
||||||
|
<RequestHeaders headers={headers} setHeaders={setHeaders} />
|
||||||
|
<Variables variables={variables} setVariables={setVariables} />
|
||||||
|
|
||||||
|
<div className="mt-2">
|
||||||
|
{error && (
|
||||||
|
<IndicatorCard status="negative" headline="An error has occured">
|
||||||
|
{JSON.stringify(error, null, 2)}
|
||||||
|
</IndicatorCard>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
disabled={!endpoint?.endpoint}
|
||||||
|
isLoading={isFetching}
|
||||||
|
icon={<FaPlay />}
|
||||||
|
onClick={() => {
|
||||||
|
refetch();
|
||||||
|
}}
|
||||||
|
mode="primary"
|
||||||
|
>
|
||||||
|
Run Request
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CodeEditorField
|
||||||
|
editorOptions={responseEditorOptions}
|
||||||
|
name="response"
|
||||||
|
label="GraphQL Response"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,47 @@
|
|||||||
|
import { CardedTable } from '../../../../new-components/CardedTable';
|
||||||
|
import { Collapsible } from '../../../../new-components/Collapsible';
|
||||||
|
import { Variable } from './RestEndpointDetails';
|
||||||
|
|
||||||
|
type VariablesProps = {
|
||||||
|
variables: Variable[];
|
||||||
|
setVariables: (variables: Variable[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Variables = (props: VariablesProps) => {
|
||||||
|
const { variables, setVariables } = props;
|
||||||
|
return (
|
||||||
|
<Collapsible
|
||||||
|
defaultOpen
|
||||||
|
triggerChildren={
|
||||||
|
<div className="font-semibold text-muted">Request Variables</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute top-0 right-0"></div>
|
||||||
|
<div className="font-semibold text-muted mb-4">Variables List</div>
|
||||||
|
<CardedTable
|
||||||
|
showActionCell
|
||||||
|
columns={['Name', 'Type', 'Value']}
|
||||||
|
data={variables.map((variable, i) => [
|
||||||
|
<span className="font-semibold text-muted">{variable.name}</span>,
|
||||||
|
variable.type,
|
||||||
|
<input
|
||||||
|
data-testid={`variable-${variable.name}`}
|
||||||
|
placeholder="Enter value..."
|
||||||
|
className="w-full font-normal text-muted"
|
||||||
|
value={variable.value}
|
||||||
|
onChange={e =>
|
||||||
|
setVariables(
|
||||||
|
variables.map(v => ({
|
||||||
|
...v,
|
||||||
|
value: v.name === variable.name ? e.target.value : v.value,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './RestEndpointDetails';
|
@ -0,0 +1,27 @@
|
|||||||
|
import { useMetadata } from '../../MetadataAPI';
|
||||||
|
|
||||||
|
export const useRestEndpoint = (name: string) => {
|
||||||
|
const { data: metadata } = useMetadata();
|
||||||
|
|
||||||
|
const endpoint = metadata?.metadata?.rest_endpoints?.find(
|
||||||
|
endpoint => endpoint.name === name
|
||||||
|
);
|
||||||
|
|
||||||
|
const queryCollection = metadata?.metadata?.query_collections?.find(
|
||||||
|
collection =>
|
||||||
|
collection.name === endpoint?.definition?.query?.collection_name
|
||||||
|
);
|
||||||
|
|
||||||
|
const query = queryCollection?.definition?.queries?.find(
|
||||||
|
query => query.name === endpoint?.definition?.query?.query_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!endpoint || !query) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
endpoint,
|
||||||
|
query,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,75 @@
|
|||||||
|
import { RestEndpointEntry } from '../../../metadata/types';
|
||||||
|
import { Header, Variable } from '../components/RestEndpointDetails';
|
||||||
|
import { Api } from '../../../hooks/apiUtils';
|
||||||
|
import {
|
||||||
|
getCurrentPageHost,
|
||||||
|
getValueWithType,
|
||||||
|
} from '../../../components/Services/ApiExplorer/Rest/utils';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
|
type QueryKey = [
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
endpoint: RestEndpointEntry | undefined;
|
||||||
|
headers: Header[];
|
||||||
|
variables: Variable[];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const useRestEndpointRequest = (
|
||||||
|
endpoint: RestEndpointEntry | undefined,
|
||||||
|
headers: Header[],
|
||||||
|
variables: Variable[]
|
||||||
|
) => {
|
||||||
|
const makeRequest = ({ queryKey }: { queryKey: QueryKey }) => {
|
||||||
|
const [, { endpoint, headers, variables }] = queryKey;
|
||||||
|
|
||||||
|
const selectedHeaders = headers
|
||||||
|
.filter(h => !!h.name && h.selected)
|
||||||
|
.map(h => ({ name: h.name, value: h.value }));
|
||||||
|
|
||||||
|
const processedVariable = variables.map(v => ({
|
||||||
|
name: v.name,
|
||||||
|
value: getValueWithType(v),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const bodyVariables = [];
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = endpoint.url;
|
||||||
|
|
||||||
|
for (const variable of processedVariable) {
|
||||||
|
if (url.match(`/:${variable.name}`)) {
|
||||||
|
url = url.replace(`/:${variable.name}`, `/${variable.value}`);
|
||||||
|
} else {
|
||||||
|
bodyVariables.push(variable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Api.base({
|
||||||
|
method: endpoint.methods?.[0],
|
||||||
|
url: `${getCurrentPageHost()}/api/rest/${url}`,
|
||||||
|
body: bodyVariables.reduce((acc, curr) => {
|
||||||
|
acc[curr.name] = curr.value;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, unknown>),
|
||||||
|
headers: selectedHeaders.reduce((acc, curr) => {
|
||||||
|
acc[curr.name] = curr.value;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, string>),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [
|
||||||
|
'rest-endpoint-request ',
|
||||||
|
{ endpoint, headers, variables },
|
||||||
|
] as QueryKey,
|
||||||
|
queryFn: makeRequest,
|
||||||
|
enabled: false,
|
||||||
|
retry: 1,
|
||||||
|
});
|
||||||
|
};
|
@ -7,16 +7,16 @@ import { MetadataReducer } from '../../../mocks/actions';
|
|||||||
export const restEndpointsInitialData: Partial<Metadata['metadata']> = {
|
export const restEndpointsInitialData: Partial<Metadata['metadata']> = {
|
||||||
rest_endpoints: [
|
rest_endpoints: [
|
||||||
{
|
{
|
||||||
comment: '',
|
comment: 'Description of my rest endpoint',
|
||||||
definition: {
|
definition: {
|
||||||
query: {
|
query: {
|
||||||
collection_name: 'allowed-queries',
|
collection_name: 'allowed-queries',
|
||||||
query_name: 'test',
|
query_name: 'MyQuery',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: ['GET'],
|
methods: ['POST'],
|
||||||
name: 'test',
|
name: 'MyQuery',
|
||||||
url: 'test',
|
url: 'test/:id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user