diff --git a/components/BatchDialog.js b/components/BatchDialog.js
index 06470dd..52c7651 100644
--- a/components/BatchDialog.js
+++ b/components/BatchDialog.js
@@ -45,7 +45,10 @@ export default function BatchDialog({context, request}) {
writeFile(csvPath, outString);
}, [csvData, csvHeaders, csvPath]);
- const canRun = csvData.length > 0 && outputConfig.every(x => x.name && x.jsonPath);
+ // Valid output configs:
+ // * Must contain a name, AND
+ // * Must contain a jsonPath, OR must be statusCode or reqTime (which don't need a jsonPath)
+ const canRun = csvData.length > 0 && outputConfig.every(x => x.name && (x.jsonPath || ["statusCode", "reqTime"].includes(x.context)));
const onRun = async () => {
setSent(0);
diff --git a/components/OutputField.js b/components/OutputField.js
index b046ad3..34c2963 100644
--- a/components/OutputField.js
+++ b/components/OutputField.js
@@ -1,14 +1,24 @@
import React, { useCallback } from 'react';
import ActionButton from './ActionButton';
-export default function OutputField({options, name, jsonPath, onChange, onDelete}) {
+export default function OutputField({options, name, context, jsonPath, onChange, onDelete}) {
const onChangeName = useCallback((e) => {
- onChange(e.target.value, jsonPath)
- }, [jsonPath, onChange]);
+ onChange(e.target.value, context, jsonPath)
+ }, [context, jsonPath, onChange]);
+
+ const onChangeContext = useCallback((e) => {
+ onChange(name, e.target.value, jsonPath)
+ }, [name, jsonPath, onChange])
const onChangeJsonPath = useCallback((e) => {
- onChange(name, e.target.value)
- }, [name, onChange]);
+ onChange(name, context, e.target.value)
+ }, [name, context, onChange]);
+
+ const placeholder = {
+ body: "$.store.books[*].author",
+ headers: "X-Some-Header"
+ }[context];
+ const shouldShowValueField = ["body", "headers"].includes(context);
return
}
\ No newline at end of file
diff --git a/components/OutputFieldsChooser.js b/components/OutputFieldsChooser.js
index 5dfd452..de768d8 100644
--- a/components/OutputFieldsChooser.js
+++ b/components/OutputFieldsChooser.js
@@ -8,15 +8,15 @@ export default function OutputFieldsChooser({colNames, onChange}) {
const [outputs, setOutputs] = useState([]);
const addNew = useCallback(() => {
- const newVal = outputs.concat([{name: "", jsonPath: ""}]);
+ const newVal = outputs.concat([{name: "", context: "body", jsonPath: ""}]);
setOutputs(newVal);
onChange(newVal);
}, [outputs, setOutputs, onChange]);
- const updateField = useCallback((i) => (newName, newJsonPath) => {
+ const updateField = useCallback((i) => (newName, newContext, newJsonPath) => {
// Poor man's deep copy, since I'm not sure if you should modify React state in place
const cloned = JSON.parse(JSON.stringify(outputs))
- cloned[i] = {name: newName, jsonPath: newJsonPath};
+ cloned[i] = {name: newName, context: newContext, jsonPath: newJsonPath};
setOutputs(cloned);
onChange(cloned);
}, [outputs, setOutputs, onChange]);
@@ -30,7 +30,11 @@ export default function OutputFieldsChooser({colNames, onChange}) {
return
{outputs.map((o, i) =>
-
+
)}
diff --git a/utils.js b/utils.js
index cabb8c2..f11b001 100644
--- a/utils.js
+++ b/utils.js
@@ -74,19 +74,42 @@ export async function makeRequest(context, request, i, row, delay, outputConfig,
return
}
- // Check that the Content-Type header is sensible, otherwise error out
- if(!response.contentType.includes("json")) {
- context.app.alert("Error!", `The response has invalid Content-Type "${response.contentType}", needs "application/json"! Alternatively, delete all Outputs and try again.`)
- return // There's no point in attempting to parse the response, just jump to the next request
+ let responseData = {};
+ // If any outputConfigs refer to the response body, we must parse it
+ if(outputConfig.some(x => x.context === "body")) {
+ // Check that the Content-Type header is sensible, otherwise error out
+ if(!response.contentType.includes("json")) {
+ context.app.alert("Error!", `The response has invalid Content-Type "${response.contentType}", needs "application/json"! Alternatively, delete all Outputs and try again.`)
+ return // There's no point in attempting to parse the response, just jump to the next request
+ }
+
+ console.debug("parsing response data")
+ responseData = JSON.parse(readResponseFromFile(response.bodyPath))
}
-
- console.debug("parsing response data")
- // Read the response data, then apply JSONPath expressions on it and update the CSV data
- const responseData = JSON.parse(readResponseFromFile(response.bodyPath))
console.debug(responseData)
- for(const {name, jsonPath} of outputConfig) {
- let out = applyJsonPath(jsonPath, responseData) ?? null
- console.debug(name, "+", jsonPath, "=>", out)
+
+ // WEIRD: Labeled statement! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
+ writerForLoop:
+ for(const {name, jsonPath, context: ctx} of outputConfig) {
+ let out;
+ switch(ctx) {
+ case "body":
+ out = applyJsonPath(jsonPath, responseData) ?? null
+ break
+ case "headers":
+ out = response.headers.find(h => h.name === jsonPath.toLowerCase()).value
+ break
+ case "statusCode":
+ out = response.statusCode.toString()
+ break
+ case "reqTime":
+ out = response.elapsedTime.toString()
+ break
+ default:
+ console.error("Unknown outputConfig:", "name", name, "jsonPath", jsonPath, "context", ctx)
+ continue writerForLoop // Skip to next outputConfig
+ }
+ console.debug(name, "+", jsonPath, "@", ctx, "=>", out)
setCsvData(csvData => {
let newData = [...csvData] // Make a copy of the old data so we can mutate it normally