FF-1947: Added response variable to web request

This commit is contained in:
John Andrews
2024-12-03 07:46:54 +13:00
parent 5cc8c582ee
commit be247b823f
15 changed files with 148 additions and 1 deletions

View File

@@ -1,4 +1,7 @@
namespace FileFlows.Web.FlowElements;
using System.Text.RegularExpressions;
using FileFlows.Web.Helpers;
namespace FileFlows.Web.FlowElements;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
@@ -99,6 +102,12 @@ public class WebRequest : Node
/// </summary>
[TextArea(5, variables: true)]
public string Body { get; set; } = null!;
/// <summary>
/// Gets or sets the variable to save the response object in
/// </summary>
[TextVariable(6)]
public string ResponseVariable { get; set; } = null!;
private Dictionary<string, object>? _Variables;
@@ -160,6 +169,23 @@ public class WebRequest : Node
var result = client.Send(message);
string stringBody = result.Content.ReadAsStringAsync().Result ?? string.Empty;
// Try to parse the JSON response and add it to the dictionary
var responseVariable = args.ReplaceVariables(ResponseVariable ?? string.Empty, stripMissing: true);
if (string.IsNullOrEmpty(responseVariable) == false &&
Regex.IsMatch(responseVariable, @"^[a-zA-Z_][a-zA-Z_0-9]*$"))
{
try
{
var jsonResult = JsonUtils.DeserializeToDictionary(stringBody);
if (jsonResult != null)
args.Variables[responseVariable] = jsonResult;
}
catch (System.Text.Json.JsonException ex)
{
args.Logger?.WLog("Failed to parse JSON response: " + ex.Message);
}
}
args.UpdateVariables(new Dictionary<string, object>{
{ "web.StatusCode", (int)result.StatusCode },

95
Web/Helpers/JsonUtils.cs Normal file
View File

@@ -0,0 +1,95 @@
using System.Text.Json;
namespace FileFlows.Web.Helpers;
/// <summary>
/// Provides utility methods for working with JSON data, including the ability to
/// recursively deserialize JSON strings into .NET objects such as <see cref="Dictionary{string, object}"/>.
/// </summary>
public static class JsonUtils
{
/// <summary>
/// Recursively deserializes a JSON string into an object where:
/// - JSON objects are represented as <see cref="Dictionary{string, object}"/>
/// - JSON arrays are represented as <see cref="List{object}"/>
/// - JSON primitives are represented as their corresponding .NET types (e.g., int, string, bool).
/// </summary>
/// <param name="json">The JSON string to deserialize.</param>
/// <returns>
/// An object representing the JSON structure. The return type will be one of the following:
/// - <see cref="Dictionary{string, object}"/> for JSON objects.
/// - <see cref="List{object}"/> for JSON arrays.
/// - Primitive .NET types (e.g., int, string, bool) for JSON values.
/// Returns <c>null</c> if the input JSON string is null or empty.
/// </returns>
/// <exception cref="JsonException">Thrown when the input JSON is invalid.</exception>
public static object? DeserializeToDictionary(string json)
{
if (string.IsNullOrWhiteSpace(json))
return null;
using var document = JsonDocument.Parse(json);
return ConvertElement(document.RootElement);
}
/// <summary>
/// Recursively converts a <see cref="JsonElement"/> into a corresponding .NET object.
/// </summary>
/// <param name="element">The <see cref="JsonElement"/> to convert.</param>
/// <returns>
/// An object representing the JSON element. The return type will be one of the following:
/// - <see cref="Dictionary{string, object}"/> for JSON objects.
/// - <see cref="List{object}"/> for JSON arrays.
/// - Primitive .NET types (e.g., int, string, bool) for JSON values.
/// Returns <c>null</c> for JSON null values or unsupported types.
/// </returns>
private static object? ConvertElement(JsonElement element)
{
return element.ValueKind switch
{
JsonValueKind.Object => ConvertObject(element),
JsonValueKind.Array => ConvertArray(element),
JsonValueKind.String => element.GetString(),
JsonValueKind.Number => element.TryGetInt64(out var longValue) ? longValue : element.GetDouble(),
JsonValueKind.True => true,
JsonValueKind.False => false,
JsonValueKind.Null => null,
_ => null
};
}
/// <summary>
/// Converts a JSON object to a <see cref="Dictionary{string, object}"/>.
/// </summary>
/// <param name="element">The <see cref="JsonElement"/> representing the JSON object.</param>
/// <returns>
/// A <see cref="Dictionary{string, object}"/> where keys are JSON property names and values are their
/// corresponding .NET representations.
/// </returns>
private static Dictionary<string, object?> ConvertObject(JsonElement element)
{
var dictionary = new Dictionary<string, object?>();
foreach (var property in element.EnumerateObject())
{
dictionary[property.Name] = ConvertElement(property.Value);
}
return dictionary;
}
/// <summary>
/// Converts a JSON array to a <see cref="List{object}"/>.
/// </summary>
/// <param name="element">The <see cref="JsonElement"/> representing the JSON array.</param>
/// <returns>
/// A <see cref="List{object}"/> containing the .NET representations of the JSON array elements.
/// </returns>
private static List<object?> ConvertArray(JsonElement element)
{
var list = new List<object?>();
foreach (var item in element.EnumerateArray())
{
list.Add(ConvertElement(item));
}
return list;
}
}

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Wert",
"Method": "Methode",
"Method-Help": "Die Webmethode, die beim Senden dieser Anfrage verwendet werden soll",
"ResponseVariable": "Antwortvariable",
"ResponseVariable-Help": "Der Name der Variablen, in der die JSON-Antwort gespeichert wird. Wenn die Antwort kein gültiges JSON ist, wird diese Variable nicht gesetzt.",
"Url": "URL",
"Url-Help": "Die URL der Anfrage"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Value",
"Method": "Method",
"Method-Help": "The web method to use when sending this request",
"ResponseVariable": "Response Variable",
"ResponseVariable-Help": "The name of the variable where the JSON response will be stored. If the response is not valid JSON, this variable will not be set.",
"Url": "URL",
"Url-Help": "The URL of the request"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Valor",
"Method": "Método",
"Method-Help": "El método web a utilizar al enviar esta solicitud",
"ResponseVariable": "Variable de respuesta",
"ResponseVariable-Help": "El nombre de la variable donde se almacenará la respuesta JSON. Si la respuesta no es un JSON válido, esta variable no se establecerá.",
"Url": "URL",
"Url-Help": "La URL de la solicitud"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Valeur",
"Method": "Méthode",
"Method-Help": "La méthode web à utiliser lors de l'envoi de cette requête",
"ResponseVariable": "Variable de réponse",
"ResponseVariable-Help": "Le nom de la variable où sera enregistrée la réponse JSON. Si la réponse n'est pas un JSON valide, cette variable ne sera pas définie.",
"Url": "URL",
"Url-Help": "L'URL de la requête"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Valore",
"Method": "Metodo",
"Method-Help": "Il metodo web da usare per inviare questa richiesta",
"ResponseVariable": "Variabile di risposta",
"ResponseVariable-Help": "Il nome della variabile in cui verrà memorizzata la risposta JSON. Se la risposta non è un JSON valido, questa variabile non verrà impostata.",
"Url": "URL",
"Url-Help": "L'URL della richiesta"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "値",
"Method": "メソッド",
"Method-Help": "このリクエストを送信する際に使用するウェブメソッド",
"ResponseVariable": "応答変数",
"ResponseVariable-Help": "JSON応答を保存する変数の名前です。応答が有効なJSONでない場合、この変数は設定されません。",
"Url": "URL",
"Url-Help": "リクエストのURL"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "값",
"Method": "메서드",
"Method-Help": "이 요청을 보낼 때 사용할 웹 메서드",
"ResponseVariable": "응답 변수",
"ResponseVariable-Help": "JSON 응답을 저장할 변수의 이름입니다. 응답이 유효한 JSON이 아닌 경우 이 변수가 설정되지 않습니다.",
"Url": "URL",
"Url-Help": "요청의 URL"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Waarde",
"Method": "Methode",
"Method-Help": "De webmethode die gebruikt wordt voor het verzenden van dit verzoek",
"ResponseVariable": "Antwoordvariabele",
"ResponseVariable-Help": "De naam van de variabele waarin de JSON-antwoorden worden opgeslagen. Als de reactie geen geldig JSON is, wordt deze variabele niet ingesteld.",
"Url": "URL",
"Url-Help": "De URL van het verzoek"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Valor",
"Method": "Método",
"Method-Help": "O método web a ser usado ao enviar esta solicitação",
"ResponseVariable": "Variável de resposta",
"ResponseVariable-Help": "O nome da variável onde a resposta JSON será armazenada. Se a resposta não for um JSON válido, esta variável não será definida.",
"Url": "URL",
"Url-Help": "A URL da solicitação"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Значение",
"Method": "Метод",
"Method-Help": "Метод веб-запроса для отправки",
"ResponseVariable": "Переменная ответа",
"ResponseVariable-Help": "Имя переменной, в которую будет сохранён JSON-ответ. Если ответ не является допустимым JSON, эта переменная не будет установлена.",
"Url": "URL",
"Url-Help": "URL для отправки запроса"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "Värde",
"Method": "Metod",
"Method-Help": "Webbmetoden att använda när denna förfrågan skickas",
"ResponseVariable": "Svarvariabel",
"ResponseVariable-Help": "Namnet på variabeln där JSON-svaret sparas. Om svaret inte är giltig JSON kommer denna variabel inte att sättas.",
"Url": "URL",
"Url-Help": "URL:en för förfrågan"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "值",
"Method": "方法",
"Method-Help": "发送此请求时使用的网络方法",
"ResponseVariable": "响应变量",
"ResponseVariable-Help": "保存JSON响应的变量名称。如果响应不是有效的JSON则不会设置此变量。",
"Url": "URL",
"Url-Help": "请求的URL"
},

View File

@@ -58,6 +58,8 @@
"HeadersValue": "值",
"Method": "方法",
"Method-Help": "發送此請求時使用的網絡方法",
"ResponseVariable": "回應變數",
"ResponseVariable-Help": "保存JSON回應的變數名稱。如果回應不是有效的JSON則不會設置此變數。",
"Url": "URL",
"Url-Help": "請求的URL"
},