Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 16da9fd

Browse files
committed
curl refactor
1 parent d8560aa commit 16da9fd

File tree

3 files changed

+148
-97
lines changed

3 files changed

+148
-97
lines changed

‎client/packages/lowcoder/src/comps/queries/queryComp.tsx

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
import { QueryContext } from "../../util/context/QueryContext";
6565
import { useFixedDelay } from "../../util/hooks";
6666
import { JSONObject, JSONValue } from "../../util/jsonTypes";
67+
import { processCurlData } from "../../util/curlUtils";
6768
import { BoolPureControl } from "../controls/boolControl";
6869
import { millisecondsControl } from "../controls/millisecondControl";
6970
import { paramsMillisecondsControl } from "../controls/paramsControl";
@@ -744,11 +745,9 @@ class QueryListComp extends QueryListTmpComp implements BottomResListComp {
744745
const compType = extraInfo?.compType || "js";
745746
const dataSourceId = extraInfo?.dataSourceId;
746747
const curlData = extraInfo?.curlData;
747-
console.log("CURL DATA", curlData)
748+
console.log("CURL DATA", curlData);
748749

749-
750-
751-
// Build the payload that will be pushed to the list
750+
// Build the basic payload
752751
let payload: any = {
753752
id: id,
754753
name: name,
@@ -761,55 +760,21 @@ class QueryListComp extends QueryListTmpComp implements BottomResListComp {
761760

762761
// If this is a REST API created from cURL, pre-populate the HTTP query fields
763762
if (compType === "restApi" && curlData) {
764-
// Normalize possible field names returned by different curl parsers
765-
const rawHeaders: Record<string, any> | undefined =
766-
curlData.header || curlData.headers;
767-
const rawParams: Record<string, any> | undefined =
768-
curlData.params || curlData.parameters || curlData.query;
769-
770-
// Convert headers & params objects to the key/value array expected by the UI controls
771-
const headersArr = rawHeaders
772-
? Object.entries(rawHeaders).map(([key, value]) => ({ key, value }))
773-
: [{ key: "", value: "" }];
774-
775-
const paramsArr = rawParams
776-
? Object.entries(rawParams).map(([key, value]) => ({ key, value }))
777-
: [{ key: "", value: "" }];
778-
779-
// Detect request body – different parsers may expose it under various keys
780-
const bodyContent: any =
781-
curlData.body ?? curlData.data ?? curlData.postData ?? undefined;
782-
783-
// Determine body type – prefer the Content-Type header if present
784-
let bodyType: string = "none";
785-
if (bodyContent !== undefined && bodyContent !== "") {
786-
const contentTypeHeader =
787-
(rawHeaders && (rawHeaders["Content-Type"] || rawHeaders["content-type"])) ||
788-
"";
789-
if (contentTypeHeader) {
790-
bodyType = contentTypeHeader;
791-
} else if (typeof bodyContent === "object") {
792-
bodyType = "application/json";
793-
} else {
794-
bodyType = "text/plain";
795-
}
763+
const curlConfig = processCurlData(curlData);
764+
if (curlConfig) {
765+
payload = {
766+
...payload,
767+
comp: {
768+
httpMethod: curlConfig.method,
769+
path: curlConfig.url,
770+
headers: curlConfig.headers,
771+
params: curlConfig.params,
772+
bodyType: curlConfig.bodyType,
773+
body: curlConfig.body,
774+
bodyFormData: curlConfig.bodyFormData,
775+
},
776+
};
796777
}
797-
798-
payload = {
799-
...payload,
800-
comp: {
801-
httpMethod: curlData.method || "GET",
802-
path: curlData.url || curlData.path || "",
803-
headers: headersArr,
804-
params: paramsArr,
805-
bodyType: bodyType,
806-
body:
807-
typeof bodyContent === "object"
808-
? JSON.stringify(bodyContent, null, 2)
809-
: bodyContent || "",
810-
bodyFormData: [{ key: "", value: "", type: "text" }],
811-
},
812-
};
813778
}
814779

815780
this.dispatch(

‎client/packages/lowcoder/src/pages/queryLibrary/QueryLibraryEditor.tsx

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"
4848
import { Helmet } from "react-helmet";
4949
import {fetchQLPaginationByOrg} from "@lowcoder-ee/util/pagination/axios";
5050
import { isEmpty } from "lodash";
51+
import { processCurlData } from "../../util/curlUtils";
5152

5253
const Wrapper = styled.div`
5354
display: flex;
@@ -208,52 +209,21 @@ export const QueryLibraryEditor = () => {
208209

209210
// If it is a REST API created from cURL, pre-populate the HTTP query fields
210211
if (extraInfo?.compType === "restApi" && extraInfo?.curlData) {
211-
const curlData = extraInfo.curlData;
212-
213-
const rawHeaders: Record<string, any> | undefined =
214-
curlData.header || curlData.headers;
215-
const rawParams: Record<string, any> | undefined =
216-
curlData.params || curlData.parameters || curlData.query;
217-
218-
const headersArr = rawHeaders
219-
? Object.entries(rawHeaders).map(([key, value]) => ({ key, value }))
220-
: [{ key: "", value: "" }];
221-
222-
const paramsArr = rawParams
223-
? Object.entries(rawParams).map(([key, value]) => ({ key, value }))
224-
: [{ key: "", value: "" }];
225-
226-
const bodyContent: any =
227-
curlData.body ?? curlData.data ?? curlData.postData ?? undefined;
228-
229-
let bodyType: string = "none";
230-
if (bodyContent !== undefined && bodyContent !== "") {
231-
const contentTypeHeader =
232-
(rawHeaders && (rawHeaders["Content-Type"] || rawHeaders["content-type"])) || "";
233-
if (contentTypeHeader) {
234-
bodyType = contentTypeHeader;
235-
} else if (typeof bodyContent === "object") {
236-
bodyType = "application/json";
237-
} else {
238-
bodyType = "text/plain";
239-
}
212+
const curlConfig = processCurlData(extraInfo.curlData);
213+
if (curlConfig) {
214+
queryDSL = {
215+
...queryDSL,
216+
comp: {
217+
httpMethod: curlConfig.method,
218+
path: curlConfig.url,
219+
headers: curlConfig.headers,
220+
params: curlConfig.params,
221+
bodyType: curlConfig.bodyType,
222+
body: curlConfig.body,
223+
bodyFormData: curlConfig.bodyFormData,
224+
},
225+
};
240226
}
241-
242-
queryDSL = {
243-
...queryDSL,
244-
comp: {
245-
httpMethod: curlData.method || "GET",
246-
path: curlData.url || curlData.path || "",
247-
headers: headersArr,
248-
params: paramsArr,
249-
bodyType: bodyType,
250-
body:
251-
typeof bodyContent === "object"
252-
? JSON.stringify(bodyContent, null, 2)
253-
: bodyContent || "",
254-
bodyFormData: [{ key: "", value: "", type: "text" }],
255-
},
256-
};
257227
}
258228

259229
dispatch(
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* Utility to convert parsed cURL data from @bany/curl-to-json library
3+
* to the format expected by REST API query components
4+
*/
5+
6+
// Body type mapping to match the dropdown values in httpQuery.tsx
7+
const CONTENT_TYPE_TO_BODY_TYPE: Record<string, string> = {
8+
"application/json": "application/json",
9+
"text/plain": "text/plain",
10+
"text/html": "text/plain",
11+
"text/xml": "text/plain",
12+
"application/xml": "text/plain",
13+
"application/x-www-form-urlencoded": "application/x-www-form-urlencoded",
14+
"multipart/form-data": "multipart/form-data",
15+
};
16+
17+
/**
18+
* Parse URL-encoded form data - handles both string and object input
19+
*/
20+
function parseUrlEncodedData(data: string | object): Array<{ key: string; value: string; type: string }> {
21+
if (!data) {
22+
return [{ key: "", value: "", type: "text" }];
23+
}
24+
25+
try {
26+
let result: Array<{ key: string; value: string; type: string }> = [];
27+
28+
if (typeof data === 'object') {
29+
// @bany/curl-to-json already parsed it into an object
30+
Object.entries(data).forEach(([key, value]) => {
31+
result.push({
32+
key: key,
33+
value: decodeURIComponent(String(value).replace(/\+/g, ' ')), // Handle URL encoding
34+
type: "text"
35+
});
36+
});
37+
} else if (typeof data === 'string') {
38+
// Raw URL-encoded string - use URLSearchParams
39+
const params = new URLSearchParams(data);
40+
params.forEach((value, key) => {
41+
result.push({
42+
key: key,
43+
value: value,
44+
type: "text"
45+
});
46+
});
47+
}
48+
49+
return result.length > 0 ? result : [{ key: "", value: "", type: "text" }];
50+
} catch (error) {
51+
console.warn('Failed to parse URL-encoded data:', error);
52+
return [{ key: "", value: "", type: "text" }];
53+
}
54+
}
55+
56+
export function processCurlData(curlData: any) {
57+
if (!curlData) return null;
58+
59+
console.log("Raw cURL data:", curlData); // Debug log
60+
61+
// Convert headers object to key-value array format expected by UI
62+
const headers = curlData.header
63+
? Object.entries(curlData.header).map(([key, value]) => ({ key, value }))
64+
: [{ key: "", value: "" }];
65+
66+
// Convert query params object to key-value array format expected by UI
67+
const params = curlData.params
68+
? Object.entries(curlData.params).map(([key, value]) => ({ key, value }))
69+
: [{ key: "", value: "" }];
70+
71+
// Get request body - @bany/curl-to-json may use 'body' or 'data'
72+
const bodyContent = curlData.body !== undefined ? curlData.body : curlData.data;
73+
74+
// Determine body type based on Content-Type header or content structure
75+
let bodyType = "none";
76+
let bodyFormData = [{ key: "", value: "", type: "text" }];
77+
let processedBody = "";
78+
79+
if (bodyContent !== undefined && bodyContent !== "") {
80+
const contentTypeHeader = curlData.header?.["Content-Type"] || curlData.header?.["content-type"];
81+
82+
if (contentTypeHeader) {
83+
// Extract base content type (remove charset, boundary, etc.)
84+
const baseContentType = contentTypeHeader.split(';')[0].trim().toLowerCase();
85+
bodyType = CONTENT_TYPE_TO_BODY_TYPE[baseContentType] || "text/plain";
86+
} else {
87+
// Fallback: infer from content structure
88+
if (typeof bodyContent === "object") {
89+
bodyType = "application/json";
90+
} else {
91+
bodyType = "text/plain";
92+
}
93+
}
94+
95+
// Handle different body types
96+
if (bodyType === "application/x-www-form-urlencoded") {
97+
bodyFormData = parseUrlEncodedData(bodyContent);
98+
processedBody = ""; // Form data goes in bodyFormData, not body
99+
console.log("Parsed form data:", bodyFormData); // Debug log
100+
} else if (typeof bodyContent === "object") {
101+
processedBody = JSON.stringify(bodyContent, null, 2);
102+
} else {
103+
processedBody = bodyContent;
104+
}
105+
}
106+
107+
return {
108+
method: curlData.method || "GET",
109+
url: curlData.url || "",
110+
headers,
111+
params,
112+
bodyType,
113+
body: processedBody,
114+
bodyFormData,
115+
};
116+
}

0 commit comments

Comments
 (0)