Skip to content

Commit bf2b6aa

Browse files
committed
fixes http request variable result collision
1 parent 6e29f09 commit bf2b6aa

File tree

4 files changed

+96
-66
lines changed

4 files changed

+96
-66
lines changed

src/features/executions/ExecutorRegistry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export type NodeExecutor<TData = Record<string, unknown>> = (
2121
const executorRegistry: Record<NodeType, NodeExecutor> = {
2222
[NodeType.MANUAL_TRIGGER]: manualTriggerExecutor,
2323
[NodeType.INITIAL]: manualTriggerExecutor,
24-
[NodeType.HTTP_REQUEST]: HttpRequestExecutor,
24+
[NodeType.HTTP_REQUEST]: HttpRequestExecutor as NodeExecutor,
2525
};
2626

2727
export const getExecutor = (type: NodeType): NodeExecutor => {

src/features/executions/components/http-request/Dialog.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ const formSchema = z.object({
3333
endpoint: z.url({ message: "Enter a valid url" }),
3434
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
3535
body: z.string().optional(),
36+
variableName: z
37+
.string()
38+
.min(1, { message: "variableName is required" })
39+
.regex(/^[A-Za-z_$][A-Za-z0-9_$]*$/, {
40+
message:
41+
"variableName must start with a letter or underscore and contain only letters, numbers or underscores",
42+
}),
3643
});
3744

3845
export type HttpRequestDialogFormValues = z.infer<typeof formSchema>;
@@ -53,9 +60,10 @@ export const HttpRequestDialog = ({
5360
const form = useForm({
5461
resolver: zodResolver(formSchema),
5562
defaultValues: {
56-
endpoint: defaultValues?.endpoint || "",
57-
method: defaultValues?.method || "GET",
58-
body: defaultValues?.body || "",
63+
endpoint: defaultValues.endpoint || "",
64+
method: defaultValues.method || "GET",
65+
body: defaultValues.body || "",
66+
variableName: defaultValues.variableName || "",
5967
},
6068
});
6169

@@ -70,9 +78,10 @@ export const HttpRequestDialog = ({
7078
useEffect(() => {
7179
if (open) {
7280
form.reset({
73-
endpoint: defaultValues.endpoint,
74-
method: defaultValues.method,
75-
body: defaultValues.body,
81+
variableName: defaultValues.variableName || "",
82+
endpoint: defaultValues.endpoint || "",
83+
method: defaultValues.method || "GET",
84+
body: defaultValues.body || "",
7685
});
7786
}
7887
}, [defaultValues, form, open]);
@@ -91,6 +100,22 @@ export const HttpRequestDialog = ({
91100
onSubmit={form.handleSubmit(handleSubmit)}
92101
className="space-y-8 mt-4"
93102
>
103+
<FormField
104+
control={form.control}
105+
name="variableName"
106+
render={({ field }) => (
107+
<FormItem>
108+
<FormLabel>Variable Name</FormLabel>
109+
<FormControl>
110+
<Input placeholder="variableName" {...field} />
111+
</FormControl>
112+
<FormDescription>
113+
Use this name to reference the result in other nodes
114+
</FormDescription>
115+
<FormMessage />
116+
</FormItem>
117+
)}
118+
/>
94119
<FormField
95120
control={form.control}
96121
name="method"

src/features/executions/components/http-request/Executor.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,46 @@ export const HttpRequestExecutor: NodeExecutor<HttpRequestNodeData> = async ({
88
context,
99
step,
1010
}) => {
11+
if (!data.variableName) {
12+
throw new NonRetriableError("[Http request]: Variable name not configured");
13+
}
1114
if (!data.endpoint) {
1215
throw new NonRetriableError("[Http request]: No endopoint configured");
1316
}
17+
if (!data.method) {
18+
throw new NonRetriableError("[Http request]: No method configured");
19+
}
1420

15-
const result = await step.run("http-request", async () => {
16-
// biome-ignore lint/style/noNonNullAssertion: <see line 13-14-15>
17-
const endpoint = data.endpoint!;
21+
return await step.run("http-request", async () => {
1822
const method = data.method || "GET";
1923

2024
const options: Options = {
2125
method,
26+
headers: {
27+
"Content-Type": "application/json",
28+
},
2229
};
2330
if (["POST", "PATCH", "PUT", "DELETE"].includes(method)) {
2431
options.body = data.body;
2532
}
2633

27-
const response = await ky(endpoint, options);
34+
const response = await ky(data.endpoint, options);
2835
const contentType = response.headers.get("content-type");
2936
const responseData = contentType?.includes("application/json")
3037
? await response.json()
31-
: response.text();
38+
: await response.text();
3239

33-
return {
34-
...context,
40+
const responsePayload = {
3541
httpResponse: {
3642
status: response.status,
3743
statusText: response.statusText,
3844
data: responseData,
3945
},
4046
};
41-
});
4247

43-
return result;
48+
return {
49+
...context,
50+
[data.variableName]: responsePayload,
51+
};
52+
});
4453
};

src/features/executions/components/http-request/Node.tsx

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,59 @@ import BaseExecutionNode from "../BaseExecutionNode";
66
import { GlobeIcon } from "lucide-react";
77
import { type HttpRequestDialogFormValues, HttpRequestDialog } from "./Dialog";
88

9-
export type HttpRequestNodeData = {
10-
endpoint?: string;
11-
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
12-
body?: string;
13-
};
9+
export type HttpRequestNodeData = HttpRequestDialogFormValues;
1410

15-
type HttpRequestNodeType = Node<HttpRequestNodeData>;
11+
export const HttpRequestNode = memo(
12+
(props: NodeProps<Node<HttpRequestNodeData>>) => {
13+
const [open, setOpen] = useState(false);
1614

17-
export const HttpRequestNode = memo((props: NodeProps<HttpRequestNodeType>) => {
18-
const [open, setOpen] = useState(false);
15+
const { setNodes } = useReactFlow();
1916

20-
const { setNodes } = useReactFlow();
17+
const description = props.data?.endpoint
18+
? `${props.data.method || "GET"}: ${props.data.endpoint}`
19+
: "Not configured";
2120

22-
const description = props.data?.endpoint
23-
? `${props.data.method || "GET"}: ${props.data.endpoint}`
24-
: "Not configured";
21+
const onSettings = () => setOpen(true);
2522

26-
const onSettings = () => setOpen(true);
23+
const onSubmit = (values: HttpRequestDialogFormValues) => {
24+
setNodes((nodes) =>
25+
nodes.map((node) => {
26+
if (node.id === props.id) {
27+
return {
28+
...node,
29+
data: {
30+
...node.data,
31+
...values,
32+
},
33+
};
34+
}
35+
return node;
36+
}),
37+
);
38+
};
2739

28-
const onSubmit = (values: HttpRequestDialogFormValues) => {
29-
setNodes((nodes) =>
30-
nodes.map((node) => {
31-
if (node.id === props.id) {
32-
return {
33-
...node,
34-
data: {
35-
...node.data,
36-
...values,
37-
},
38-
};
39-
}
40-
return node;
41-
}),
40+
return (
41+
<>
42+
<HttpRequestDialog
43+
open={open}
44+
onOpenChange={setOpen}
45+
onSubmit={onSubmit}
46+
defaultValues={props.data}
47+
/>
48+
<BaseExecutionNode
49+
{...props}
50+
icon={GlobeIcon}
51+
name="Http Request"
52+
description={description}
53+
onSettings={onSettings}
54+
onDoubleClick={onSettings}
55+
showToolbar
56+
status="initial"
57+
/>
58+
</>
4259
);
43-
};
44-
45-
return (
46-
<>
47-
<HttpRequestDialog
48-
open={open}
49-
onOpenChange={setOpen}
50-
onSubmit={onSubmit}
51-
defaultValues={props.data}
52-
/>
53-
<BaseExecutionNode
54-
{...props}
55-
icon={GlobeIcon}
56-
name="Http Request"
57-
description={description}
58-
onSettings={onSettings}
59-
onDoubleClick={onSettings}
60-
showToolbar
61-
status="initial"
62-
/>
63-
</>
64-
);
65-
});
60+
},
61+
);
6662

6763
HttpRequestNode.displayName = "HttpRequestNode";
6864

0 commit comments

Comments
 (0)