mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-21 00:49:17 +01: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);
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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 {
|
||||
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_BEARER,
|
||||
AUTH_TYPE_NONE,
|
||||
BODY_TYPE_FORM_MULTIPART,
|
||||
BODY_TYPE_FORM_URLENCODED,
|
||||
BODY_TYPE_GRAPHQL,
|
||||
BODY_TYPE_JSON,
|
||||
BODY_TYPE_NONE,
|
||||
@@ -27,10 +29,11 @@ import { Editor } from './core/Editor';
|
||||
import type { TabItem } from './core/Tabs/Tabs';
|
||||
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||
import { EmptyStateText } from './EmptyStateText';
|
||||
import { FormUrlencodedEditor } from './FormUrlencodedEditor';
|
||||
import { GraphQLEditor } from './GraphQLEditor';
|
||||
import { HeadersEditor } from './HeadersEditor';
|
||||
import { UrlParametersEditor } from './ParameterEditor';
|
||||
import { UrlBar } from './UrlBar';
|
||||
import { UrlParametersEditor } from './UrlParameterEditor';
|
||||
|
||||
interface Props {
|
||||
style?: CSSProperties;
|
||||
@@ -59,10 +62,14 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
options: {
|
||||
value: activeRequest.bodyType,
|
||||
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: 'XML', value: BODY_TYPE_XML },
|
||||
{ label: 'GraphQL', value: BODY_TYPE_GRAPHQL },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator', label: 'Other' },
|
||||
{ label: 'No Body', shortLabel: 'Body', value: BODY_TYPE_NONE },
|
||||
],
|
||||
onChange: async (bodyType) => {
|
||||
@@ -71,7 +78,24 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
patch.headers = activeRequest?.headers.filter(
|
||||
(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.headers = [
|
||||
...(activeRequest?.headers.filter(
|
||||
@@ -141,6 +165,10 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
[activeRequest, updateRequest],
|
||||
);
|
||||
|
||||
const handleBodyChange = useCallback(
|
||||
(body: HttpRequest['body']) => updateRequest.mutate({ body }),
|
||||
[updateRequest],
|
||||
);
|
||||
const handleBodyTextChange = useCallback(
|
||||
(text: string) => updateRequest.mutate({ body: { text } }),
|
||||
[updateRequest],
|
||||
@@ -223,7 +251,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
placeholder="..."
|
||||
className="!bg-gray-50"
|
||||
heightMode={fullHeight ? 'full' : 'auto'}
|
||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
||||
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||
contentType="application/json"
|
||||
onChange={handleBodyTextChange}
|
||||
format={(v) => tryFormatJson(v)}
|
||||
@@ -236,7 +264,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
placeholder="..."
|
||||
className="!bg-gray-50"
|
||||
heightMode={fullHeight ? 'full' : 'auto'}
|
||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
||||
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||
contentType="text/xml"
|
||||
onChange={handleBodyTextChange}
|
||||
/>
|
||||
@@ -245,9 +273,15 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
||||
forceUpdateKey={forceUpdateKey}
|
||||
baseRequest={activeRequest}
|
||||
className="!bg-gray-50"
|
||||
defaultValue={`${activeRequest?.body?.text}` ?? ''}
|
||||
defaultValue={`${activeRequest?.body?.text ?? ''}`}
|
||||
onChange={handleBodyTextChange}
|
||||
/>
|
||||
) : activeRequest.bodyType === BODY_TYPE_FORM_URLENCODED ? (
|
||||
<FormUrlencodedEditor
|
||||
forceUpdateKey={forceUpdateKey}
|
||||
body={activeRequest.body}
|
||||
onChange={handleBodyChange}
|
||||
/>
|
||||
) : (
|
||||
<EmptyStateText>No Body</EmptyStateText>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export const BODY_TYPE_NONE = null;
|
||||
export const BODY_TYPE_GRAPHQL = 'graphql';
|
||||
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 AUTH_TYPE_NONE = null;
|
||||
@@ -63,7 +65,7 @@ export interface HttpRequest extends BaseModel {
|
||||
name: string;
|
||||
url: string;
|
||||
urlParameters: HttpUrlParameter[];
|
||||
body: Record<string, string | number | boolean | null | undefined>;
|
||||
body: Record<string, unknown>;
|
||||
bodyType: string | null;
|
||||
authentication: Record<string, string | number | boolean | null | undefined>;
|
||||
authenticationType: string | null;
|
||||
|
||||
Reference in New Issue
Block a user