HTTP send
This commit is contained in:
@@ -15,7 +15,6 @@ const ServerManager = ({ onServerChange = () => {} }) => {
|
||||
if (!initialized.current) {
|
||||
initialized.current = true;
|
||||
await loadServers();
|
||||
console.log(servers);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import ServerManager from '@/components/ServerManager.jsx';
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table.jsx';
|
||||
import {useAPI} from '@/providers/APIProvider';
|
||||
import MonacoEditor from '@/components/shared/MonacoEditor';
|
||||
// import MonacoVariableEditor from './MonacoVariableEditor'; // Import the new component
|
||||
import APIClient from '@/services/APIClient.js';
|
||||
|
||||
const HTTP_METHODS = [
|
||||
'POST', 'GET', 'PUT', 'DELETE', 'CONNECT',
|
||||
@@ -18,7 +18,9 @@ const HTTP_METHODS = [
|
||||
];
|
||||
|
||||
export const HTTPClientView = ({model, index}) => {
|
||||
const apiClient = new APIClient();
|
||||
const {getServer} = useAPI();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [currentModel, setCurrentModel] = useState(model);
|
||||
const [basePath, setBasePath] = useState('');
|
||||
const [currentTab, setCurrentTab] = useState('body');
|
||||
@@ -32,8 +34,8 @@ export const HTTPClientView = ({model, index}) => {
|
||||
|
||||
const [editorContents, setEditorContents] = useState({
|
||||
requestBody: currentModel.requestBody || '',
|
||||
responseBody: currentModel.responseBody || '',
|
||||
console: '',
|
||||
responseBody: '',
|
||||
consoleLog: '',
|
||||
preRequestScript: currentModel.preRequestScript || '',
|
||||
postRequestScript: currentModel.postRequestScript || ''
|
||||
});
|
||||
@@ -101,6 +103,55 @@ export const HTTPClientView = ({model, index}) => {
|
||||
</div>
|
||||
);
|
||||
|
||||
const handleSendRequest = async () => {
|
||||
if (isLoading) return;
|
||||
|
||||
setIsLoading(true);
|
||||
setEditorContents(prev => ({...prev, consoleLog: ''}));
|
||||
|
||||
try {
|
||||
const response = await apiClient.sendAPIRequest(
|
||||
currentModel,
|
||||
(log) => setEditorContents(prev => ({
|
||||
...prev,
|
||||
consoleLog: prev.consoleLog + log + '\n'
|
||||
}))
|
||||
);
|
||||
|
||||
const headerArray = Array.isArray(response.headers)
|
||||
? response.headers
|
||||
: Object.entries(response.headers).map(([key, value]) => ({
|
||||
name: key,
|
||||
value: value
|
||||
}));
|
||||
|
||||
setResponseData({
|
||||
headers: headerArray,
|
||||
status: `Status: ${response.status}`,
|
||||
time: `${response.time}ms`,
|
||||
size: `Size: ${response.size}`
|
||||
});
|
||||
|
||||
console.log(responseData);
|
||||
|
||||
setEditorContents(prev => ({
|
||||
...prev,
|
||||
responseBody: response.body
|
||||
}));
|
||||
|
||||
console.log(editorContents.responseBody);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setEditorContents(prev => ({
|
||||
...prev,
|
||||
consoleLog: prev.consoleLog + `Error: ${error.message}\n`
|
||||
}));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderResponseHeaders = () => (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
@@ -162,7 +213,12 @@ export const HTTPClientView = ({model, index}) => {
|
||||
className="flex-1"
|
||||
/>
|
||||
|
||||
<Button>Send</Button>
|
||||
<Button
|
||||
disabled={isLoading}
|
||||
onClick={handleSendRequest}
|
||||
>
|
||||
{isLoading ? 'Sending...' : 'Send'}
|
||||
</Button>
|
||||
<Button variant="secondary">Save</Button>
|
||||
</div>
|
||||
|
||||
@@ -185,18 +241,7 @@ export const HTTPClientView = ({model, index}) => {
|
||||
<div className="flex flex-col h-full gap-2">
|
||||
<Select
|
||||
value={currentModel.contentType}
|
||||
// onValueChange={(value) => setCurrentModel(prev => ({ ...prev, contentType: value }))}
|
||||
onValueChange={(value) => {
|
||||
// Update both content type and editor content
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
contentType: value,
|
||||
// Optionally format the content when switching to JSON
|
||||
requestBody: value === 'json' && prev.requestBody ?
|
||||
JSON.stringify(JSON.parse(prev.requestBody), null, 2) :
|
||||
prev.requestBody
|
||||
}));
|
||||
}}
|
||||
onValueChange={(value) => setCurrentModel(prev => ({ ...prev, contentType: value }))}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Content Type"/>
|
||||
@@ -207,7 +252,7 @@ export const HTTPClientView = ({model, index}) => {
|
||||
<SelectItem value="plaintext">Text/Plain</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="h-full">
|
||||
<div className="h-[calc(100%-40px)]">
|
||||
<MonacoEditor
|
||||
id={`request-body-${model.id}`}
|
||||
value={currentModel.requestBody}
|
||||
@@ -303,7 +348,7 @@ export const HTTPClientView = ({model, index}) => {
|
||||
<TabsContent value="console" className="h-full m-0">
|
||||
<MonacoEditor
|
||||
id={`console-${model.id}`}
|
||||
value={editorContents.console}
|
||||
value={editorContents.consoleLog}
|
||||
language="plaintext"
|
||||
readOnly={true}
|
||||
height="full"
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { X } from "lucide-react";
|
||||
import EditableInput from '@/components/shared/EditableInput.jsx';
|
||||
|
||||
const PropertyTable = ({
|
||||
properties = [],
|
||||
@@ -87,7 +88,7 @@ const PropertyTable = ({
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
<EditableInput
|
||||
value={property.key}
|
||||
onChange={(e) =>
|
||||
handlePropertyChange(index, 'key', e.target.value)
|
||||
@@ -96,7 +97,7 @@ const PropertyTable = ({
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
<EditableInput
|
||||
value={property.value}
|
||||
onChange={(e) =>
|
||||
handlePropertyChange(index, 'value', e.target.value)
|
||||
|
||||
@@ -18,16 +18,36 @@ class APIClient {
|
||||
|
||||
async sendAPIRequest(model, onLog = () => {}) {
|
||||
try {
|
||||
onLog(`Request: ${model.method} ${model.path}`);
|
||||
let variables = {};
|
||||
const processedModel = await this.executePreRequestScript(model, variables, onLog);
|
||||
const processedRequest = this.replacePlaceholdersWithVariables(processedModel, variables);
|
||||
|
||||
onLog(`Request: ${processedRequest.method} ${processedRequest.path}`);
|
||||
|
||||
|
||||
const response = await this.makeRequest(model);
|
||||
const formattedResponse = this.formatResponse(response);
|
||||
return formattedResponse;
|
||||
onLog(formattedResponse);
|
||||
|
||||
const finalResponse = await this.executePostRequestScript(
|
||||
model.postRequestScript,
|
||||
variables,
|
||||
processedRequest,
|
||||
formattedResponse,
|
||||
onLog
|
||||
);
|
||||
|
||||
|
||||
return finalResponse;
|
||||
|
||||
} catch (error) {
|
||||
if (error.name === 'AbortError') {
|
||||
throw new Error('Request was cancelled');
|
||||
}
|
||||
throw new Error(`API Error: ${error.message}`);
|
||||
const errorMessage = error.message || 'Unknown error';
|
||||
onLog(`Error: ${errorMessage}`);
|
||||
throw new Error(`API Error: ${errorMessage}`);
|
||||
|
||||
} finally {
|
||||
this.abortController = null;
|
||||
}
|
||||
@@ -66,6 +86,139 @@ class APIClient {
|
||||
getClientUrl() {
|
||||
return this.contextPath + this.CLIENT_URL;
|
||||
}
|
||||
|
||||
replacePlaceholdersWithVariables(original, variables) {
|
||||
const request = JSON.parse(JSON.stringify(original));
|
||||
const mergedVariables = { ...this.globals, ...variables };
|
||||
|
||||
Object.entries(mergedVariables).forEach(([key, value]) => {
|
||||
const placeholder = new RegExp(`{{${key}}}`, 'g');
|
||||
|
||||
request.path = request.path?.replace(placeholder, value);
|
||||
request.requestBody = request.requestBody?.replace(placeholder, value);
|
||||
|
||||
if (request.headers) {
|
||||
const headersStr = JSON.stringify(request.headers).replace(placeholder, value);
|
||||
request.headers = JSON.parse(headersStr);
|
||||
}
|
||||
|
||||
if (request.queryParams) {
|
||||
const paramsStr = JSON.stringify(request.queryParams).replace(placeholder, value);
|
||||
request.queryParams = JSON.parse(paramsStr);
|
||||
}
|
||||
});
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
async executePreRequestScript(model, variables, onLog) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Create sandbox iframe if not exists
|
||||
let sandbox = document.getElementById('preRequest');
|
||||
if (!sandbox) {
|
||||
sandbox = document.createElement('iframe');
|
||||
sandbox.id = 'preRequest';
|
||||
sandbox.style.display = 'none';
|
||||
document.body.appendChild(sandbox);
|
||||
}
|
||||
|
||||
// Setup communication channel
|
||||
window.preRequestComplete = (updatedModel, error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(updatedModel);
|
||||
}
|
||||
};
|
||||
|
||||
// Setup context
|
||||
window.temp_variable = variables;
|
||||
window.currentRequest = model;
|
||||
window.consoleOutput = onLog;
|
||||
|
||||
// Create sandbox content
|
||||
const sandboxContent = `
|
||||
<script>
|
||||
var oldLog = console.log;
|
||||
console.log = function(message) {
|
||||
if (window.parent.consoleOutput) {
|
||||
window.parent.consoleOutput(message);
|
||||
}
|
||||
oldLog.apply(console, arguments);
|
||||
};
|
||||
|
||||
window.globals = window.parent.globals;
|
||||
window.variables = window.parent.temp_variable;
|
||||
window.request = window.parent.currentRequest;
|
||||
|
||||
try {
|
||||
${model.preRequestScript || ''}
|
||||
window.parent.preRequestComplete(window.request, null);
|
||||
} catch (error) {
|
||||
window.parent.preRequestComplete(null, error);
|
||||
}
|
||||
</script>
|
||||
`;
|
||||
|
||||
sandbox.srcdoc = sandboxContent;
|
||||
});
|
||||
}
|
||||
|
||||
async executePostRequestScript(script, variables, request, response, onLog) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Create sandbox iframe if not exists
|
||||
let sandbox = document.getElementById('postRequest');
|
||||
if (!sandbox) {
|
||||
sandbox = document.createElement('iframe');
|
||||
sandbox.id = 'postRequest';
|
||||
sandbox.style.display = 'none';
|
||||
document.body.appendChild(sandbox);
|
||||
}
|
||||
|
||||
// Setup communication channel
|
||||
window.postRequestComplete = (updatedResponse, error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(updatedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
// Setup context
|
||||
window.request = request;
|
||||
window.response = response;
|
||||
window.temp_variable = variables;
|
||||
window.consoleOutput = onLog;
|
||||
|
||||
// Create sandbox content
|
||||
const sandboxContent = `
|
||||
<script>
|
||||
var oldLog = console.log;
|
||||
console.log = function(message) {
|
||||
if (window.parent.consoleOutput) {
|
||||
window.parent.consoleOutput(message);
|
||||
}
|
||||
oldLog.apply(console, arguments);
|
||||
};
|
||||
|
||||
window.globals = window.parent.globals;
|
||||
window.variables = window.parent.temp_variable;
|
||||
window.request = window.parent.request;
|
||||
window.response = window.parent.response;
|
||||
|
||||
try {
|
||||
${script || ''}
|
||||
window.parent.postRequestComplete(window.response, null);
|
||||
} catch (error) {
|
||||
window.parent.postRequestComplete(window.response, error.toString());
|
||||
}
|
||||
</script>
|
||||
`;
|
||||
|
||||
sandbox.srcdoc = sandboxContent;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default APIClient;
|
||||
|
||||
Reference in New Issue
Block a user