mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-20 16:01:18 +02:00
Form urlencoded bodies!
This commit is contained in:
@@ -121,14 +121,32 @@ pub async fn actually_send_request(
|
|||||||
}
|
}
|
||||||
request_builder = request_builder.query(&query_params);
|
request_builder = request_builder.query(&query_params);
|
||||||
|
|
||||||
|
|
||||||
if let Some(t) = &request.body_type {
|
if let Some(t) = &request.body_type {
|
||||||
let empty_value = &serde_json::to_value("").unwrap();
|
let empty_string = &serde_json::to_value("").unwrap();
|
||||||
|
let empty_bool = &serde_json::to_value(false).unwrap();
|
||||||
let b = request.body.0;
|
let b = request.body.0;
|
||||||
|
|
||||||
if b.contains_key("text") {
|
if b.contains_key("text") {
|
||||||
let raw_text = b.get("text").unwrap_or(empty_value).as_str().unwrap_or("");
|
let raw_text = b.get("text").unwrap_or(empty_string).as_str().unwrap_or("");
|
||||||
let body = render::render(raw_text, &workspace, environment_ref);
|
let body = render::render(raw_text, &workspace, environment_ref);
|
||||||
request_builder = request_builder.body(body);
|
request_builder = request_builder.body(body);
|
||||||
|
} else if b.contains_key("form") {
|
||||||
|
let mut form_params = Vec::new();
|
||||||
|
let form = b.get("form");
|
||||||
|
if let Some(f) = form {
|
||||||
|
for p in f.as_array().unwrap_or(&Vec::new()) {
|
||||||
|
let enabled = p.get("enabled").unwrap_or(empty_bool).as_bool().unwrap_or(false);
|
||||||
|
let name = p.get("name").unwrap_or(empty_string).as_str().unwrap_or_default();
|
||||||
|
let value = p.get("value").unwrap_or(empty_string).as_str().unwrap_or_default();
|
||||||
|
if !enabled || name.is_empty() { continue; }
|
||||||
|
form_params.push((
|
||||||
|
render::render(name, &workspace, environment_ref),
|
||||||
|
render::render(value, &workspace, environment_ref),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request_builder = request_builder.form(&form_params);
|
||||||
} else {
|
} else {
|
||||||
warn!("Unsupported body type: {}", t);
|
warn!("Unsupported body type: {}", t);
|
||||||
}
|
}
|
||||||
|
|||||||
37
src-web/components/FormUrlencodedEditor.tsx
Normal file
37
src-web/components/FormUrlencodedEditor.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import type { HttpRequest } from '../lib/models';
|
||||||
|
import type { PairEditorProps } from './core/PairEditor';
|
||||||
|
import { PairEditor } from './core/PairEditor';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
forceUpdateKey: string;
|
||||||
|
body: HttpRequest['body'];
|
||||||
|
onChange: (headers: HttpRequest['body']) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function FormUrlencodedEditor({ body, forceUpdateKey, onChange }: Props) {
|
||||||
|
const pairs = useMemo(
|
||||||
|
() =>
|
||||||
|
(Array.isArray(body.form) ? body.form : []).map((p) => ({
|
||||||
|
enabled: p.enabled,
|
||||||
|
name: p.name,
|
||||||
|
value: p.value,
|
||||||
|
})),
|
||||||
|
[body.form],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = useCallback<PairEditorProps['onChange']>(
|
||||||
|
(pairs) => onChange({ form: pairs }),
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PairEditor
|
||||||
|
valueAutocompleteVariables
|
||||||
|
nameAutocompleteVariables
|
||||||
|
pairs={pairs}
|
||||||
|
onChange={handleChange}
|
||||||
|
forceUpdateKey={forceUpdateKey}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import {
|
|||||||
AUTH_TYPE_BASIC,
|
AUTH_TYPE_BASIC,
|
||||||
AUTH_TYPE_BEARER,
|
AUTH_TYPE_BEARER,
|
||||||
AUTH_TYPE_NONE,
|
AUTH_TYPE_NONE,
|
||||||
|
BODY_TYPE_FORM_MULTIPART,
|
||||||
|
BODY_TYPE_FORM_URLENCODED,
|
||||||
BODY_TYPE_GRAPHQL,
|
BODY_TYPE_GRAPHQL,
|
||||||
BODY_TYPE_JSON,
|
BODY_TYPE_JSON,
|
||||||
BODY_TYPE_NONE,
|
BODY_TYPE_NONE,
|
||||||
@@ -27,10 +29,11 @@ import { Editor } from './core/Editor';
|
|||||||
import type { TabItem } from './core/Tabs/Tabs';
|
import type { TabItem } from './core/Tabs/Tabs';
|
||||||
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||||
import { EmptyStateText } from './EmptyStateText';
|
import { EmptyStateText } from './EmptyStateText';
|
||||||
|
import { FormUrlencodedEditor } from './FormUrlencodedEditor';
|
||||||
import { GraphQLEditor } from './GraphQLEditor';
|
import { GraphQLEditor } from './GraphQLEditor';
|
||||||
import { HeadersEditor } from './HeadersEditor';
|
import { HeadersEditor } from './HeadersEditor';
|
||||||
import { UrlParametersEditor } from './ParameterEditor';
|
|
||||||
import { UrlBar } from './UrlBar';
|
import { UrlBar } from './UrlBar';
|
||||||
|
import { UrlParametersEditor } from './UrlParameterEditor';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
@@ -59,10 +62,14 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
options: {
|
options: {
|
||||||
value: activeRequest.bodyType,
|
value: activeRequest.bodyType,
|
||||||
items: [
|
items: [
|
||||||
|
{ type: 'separator', label: 'Form Data' },
|
||||||
|
{ label: 'Url Encoded', value: BODY_TYPE_FORM_URLENCODED },
|
||||||
|
// { label: 'Multi-Part', value: BODY_TYPE_FORM_MULTIPART },
|
||||||
|
{ type: 'separator', label: 'Text Content' },
|
||||||
{ label: 'JSON', value: BODY_TYPE_JSON },
|
{ label: 'JSON', value: BODY_TYPE_JSON },
|
||||||
{ label: 'XML', value: BODY_TYPE_XML },
|
{ label: 'XML', value: BODY_TYPE_XML },
|
||||||
{ label: 'GraphQL', value: BODY_TYPE_GRAPHQL },
|
{ label: 'GraphQL', value: BODY_TYPE_GRAPHQL },
|
||||||
{ type: 'separator' },
|
{ type: 'separator', label: 'Other' },
|
||||||
{ label: 'No Body', shortLabel: 'Body', value: BODY_TYPE_NONE },
|
{ label: 'No Body', shortLabel: 'Body', value: BODY_TYPE_NONE },
|
||||||
],
|
],
|
||||||
onChange: async (bodyType) => {
|
onChange: async (bodyType) => {
|
||||||
@@ -71,7 +78,24 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
patch.headers = activeRequest?.headers.filter(
|
patch.headers = activeRequest?.headers.filter(
|
||||||
(h) => h.name.toLowerCase() !== 'content-type',
|
(h) => h.name.toLowerCase() !== 'content-type',
|
||||||
);
|
);
|
||||||
} else if (bodyType == BODY_TYPE_GRAPHQL || bodyType === BODY_TYPE_JSON) {
|
} else if (
|
||||||
|
bodyType === BODY_TYPE_FORM_URLENCODED ||
|
||||||
|
bodyType === BODY_TYPE_FORM_MULTIPART ||
|
||||||
|
bodyType === BODY_TYPE_JSON ||
|
||||||
|
bodyType === BODY_TYPE_XML
|
||||||
|
) {
|
||||||
|
patch.method = 'POST';
|
||||||
|
patch.headers = [
|
||||||
|
...(activeRequest?.headers.filter(
|
||||||
|
(h) => h.name.toLowerCase() !== 'content-type',
|
||||||
|
) ?? []),
|
||||||
|
{
|
||||||
|
name: 'Content-Type',
|
||||||
|
value: bodyType,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else if (bodyType == BODY_TYPE_GRAPHQL) {
|
||||||
patch.method = 'POST';
|
patch.method = 'POST';
|
||||||
patch.headers = [
|
patch.headers = [
|
||||||
...(activeRequest?.headers.filter(
|
...(activeRequest?.headers.filter(
|
||||||
@@ -141,6 +165,10 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
[activeRequest, updateRequest],
|
[activeRequest, updateRequest],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleBodyChange = useCallback(
|
||||||
|
(body: HttpRequest['body']) => updateRequest.mutate({ body }),
|
||||||
|
[updateRequest],
|
||||||
|
);
|
||||||
const handleBodyTextChange = useCallback(
|
const handleBodyTextChange = useCallback(
|
||||||
(text: string) => updateRequest.mutate({ body: { text } }),
|
(text: string) => updateRequest.mutate({ body: { text } }),
|
||||||
[updateRequest],
|
[updateRequest],
|
||||||
@@ -223,7 +251,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
placeholder="..."
|
placeholder="..."
|
||||||
className="!bg-gray-50"
|
className="!bg-gray-50"
|
||||||
heightMode={fullHeight ? 'full' : 'auto'}
|
heightMode={fullHeight ? 'full' : 'auto'}
|
||||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||||
contentType="application/json"
|
contentType="application/json"
|
||||||
onChange={handleBodyTextChange}
|
onChange={handleBodyTextChange}
|
||||||
format={(v) => tryFormatJson(v)}
|
format={(v) => tryFormatJson(v)}
|
||||||
@@ -236,7 +264,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
placeholder="..."
|
placeholder="..."
|
||||||
className="!bg-gray-50"
|
className="!bg-gray-50"
|
||||||
heightMode={fullHeight ? 'full' : 'auto'}
|
heightMode={fullHeight ? 'full' : 'auto'}
|
||||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||||
contentType="text/xml"
|
contentType="text/xml"
|
||||||
onChange={handleBodyTextChange}
|
onChange={handleBodyTextChange}
|
||||||
/>
|
/>
|
||||||
@@ -245,9 +273,15 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
forceUpdateKey={forceUpdateKey}
|
forceUpdateKey={forceUpdateKey}
|
||||||
baseRequest={activeRequest}
|
baseRequest={activeRequest}
|
||||||
className="!bg-gray-50"
|
className="!bg-gray-50"
|
||||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||||
onChange={handleBodyTextChange}
|
onChange={handleBodyTextChange}
|
||||||
/>
|
/>
|
||||||
|
) : activeRequest.bodyType === BODY_TYPE_FORM_URLENCODED ? (
|
||||||
|
<FormUrlencodedEditor
|
||||||
|
forceUpdateKey={forceUpdateKey}
|
||||||
|
body={activeRequest.body}
|
||||||
|
onChange={handleBodyChange}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyStateText>No Body</EmptyStateText>
|
<EmptyStateText>No Body</EmptyStateText>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
export const BODY_TYPE_NONE = null;
|
export const BODY_TYPE_NONE = null;
|
||||||
export const BODY_TYPE_GRAPHQL = 'graphql';
|
export const BODY_TYPE_GRAPHQL = 'graphql';
|
||||||
export const BODY_TYPE_JSON = 'application/json';
|
export const BODY_TYPE_JSON = 'application/json';
|
||||||
|
export const BODY_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
|
||||||
|
export const BODY_TYPE_FORM_MULTIPART = 'multipart/form-data';
|
||||||
export const BODY_TYPE_XML = 'text/xml';
|
export const BODY_TYPE_XML = 'text/xml';
|
||||||
|
|
||||||
export const AUTH_TYPE_NONE = null;
|
export const AUTH_TYPE_NONE = null;
|
||||||
@@ -63,7 +65,7 @@ export interface HttpRequest extends BaseModel {
|
|||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
urlParameters: HttpUrlParameter[];
|
urlParameters: HttpUrlParameter[];
|
||||||
body: Record<string, string | number | boolean | null | undefined>;
|
body: Record<string, unknown>;
|
||||||
bodyType: string | null;
|
bodyType: string | null;
|
||||||
authentication: Record<string, string | number | boolean | null | undefined>;
|
authentication: Record<string, string | number | boolean | null | undefined>;
|
||||||
authenticationType: string | null;
|
authenticationType: string | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user