From 0804087196b423c880455cb0d6a44e7e7ee11bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=84=EC=84=B1=ED=95=84?= Date: Sat, 25 Jan 2025 17:04:24 +0900 Subject: [PATCH] HTTP send --- TestMasterUI/src/components/ServerManager.jsx | 1 - .../client-views/HTTPClientView.jsx | 81 +++++++-- .../src/components/shared/PropertyTable.jsx | 5 +- TestMasterUI/src/services/APIClient.js | 159 +++++++++++++++++- 4 files changed, 222 insertions(+), 24 deletions(-) diff --git a/TestMasterUI/src/components/ServerManager.jsx b/TestMasterUI/src/components/ServerManager.jsx index e69e20b..476e1ec 100644 --- a/TestMasterUI/src/components/ServerManager.jsx +++ b/TestMasterUI/src/components/ServerManager.jsx @@ -15,7 +15,6 @@ const ServerManager = ({ onServerChange = () => {} }) => { if (!initialized.current) { initialized.current = true; await loadServers(); - console.log(servers); } }; diff --git a/TestMasterUI/src/components/client-views/HTTPClientView.jsx b/TestMasterUI/src/components/client-views/HTTPClientView.jsx index 66a6757..c417407 100644 --- a/TestMasterUI/src/components/client-views/HTTPClientView.jsx +++ b/TestMasterUI/src/components/client-views/HTTPClientView.jsx @@ -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}) => { ); + 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 = () => ( @@ -162,7 +213,12 @@ export const HTTPClientView = ({model, index}) => { className="flex-1" /> - + @@ -185,18 +241,7 @@ export const HTTPClientView = ({model, index}) => {
-
+
{ - handlePropertyChange(index, 'key', e.target.value) @@ -96,7 +97,7 @@ const PropertyTable = ({ /> - handlePropertyChange(index, 'value', e.target.value) diff --git a/TestMasterUI/src/services/APIClient.js b/TestMasterUI/src/services/APIClient.js index 6e25926..c16a6a7 100644 --- a/TestMasterUI/src/services/APIClient.js +++ b/TestMasterUI/src/services/APIClient.js @@ -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 = ` + + `; + + 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 = ` + + `; + + sandbox.srcdoc = sandboxContent; + }); + } + } export default APIClient;