Support json path in the response (#170)

* jsonpath in response

* Fix tests

* Support also BodyAsJson

* Fix Sonar Issue

* Add example (zubinix2)

* Fix batch file

* Solve CodeFactor issues

* netcoreapp2.0;netcoreapp2.1

* 1.0.4.8
This commit is contained in:
Stef Heyenrath
2018-07-23 17:28:32 +02:00
committed by GitHub
parent 215f051218
commit 1f226f7361
19 changed files with 591 additions and 74 deletions

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using HandlebarsDotNet;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Validation;
namespace WireMock.Transformers
{
internal static class HandlebarsHelpers
{
public static void Register()
{
Handlebars.RegisterHelper("JsonPath.SelectToken", (writer, context, arguments) =>
{
(JObject valueToProcess, string jsonpath) = Parse(arguments);
JToken result = null;
try
{
result = valueToProcess.SelectToken(jsonpath);
}
catch (JsonException)
{
// Ignore JsonException and return
return;
}
if (result != null)
{
writer.WriteSafeString(result);
}
});
Handlebars.RegisterHelper("JsonPath.SelectTokens", (writer, options, context, arguments) =>
{
(JObject valueToProcess, string jsonpath) = Parse(arguments);
IEnumerable<JToken> values = null;
try
{
values = valueToProcess.SelectTokens(jsonpath);
}
catch (JsonException)
{
// Ignore JsonException and return
return;
}
if (values == null)
{
return;
}
int id = 0;
foreach (JToken value in values)
{
options.Template(writer, new { id, value });
id++;
}
});
}
private static (JObject valueToProcess, string jsonpath) Parse(object[] arguments)
{
Check.Condition(arguments, args => args.Length == 2, nameof(arguments));
Check.NotNull(arguments[0], "arguments[0]");
Check.NotNullOrEmpty(arguments[1] as string, "arguments[1]");
JObject valueToProcess;
switch (arguments[0])
{
case string jsonAsString:
valueToProcess = JObject.Parse(jsonAsString);
break;
case JObject jsonAsJObject:
valueToProcess = jsonAsJObject;
break;
default:
throw new NotSupportedException($"The value '{arguments[0]}' with type {arguments[0].GetType()} cannot be used in Handlebars JsonPath.");
}
return (valueToProcess, arguments[1] as string);
}
}
}

View File

@@ -2,12 +2,18 @@
using System.Linq;
using HandlebarsDotNet;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Util;
namespace WireMock.Transformers
{
internal static class ResponseMessageTransformer
{
static ResponseMessageTransformer()
{
HandlebarsHelpers.Register();
}
public static ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original)
{
bool bodyIsJson = original.BodyAsJson != null;
@@ -20,21 +26,13 @@ namespace WireMock.Transformers
var template = new { request = requestMessage };
// Body
Formatting formatting = original.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
string body = bodyIsJson ? JsonConvert.SerializeObject(original.BodyAsJson, formatting) : original.Body;
if (body != null)
if (!bodyIsJson)
{
var templateBody = Handlebars.Compile(body);
if (!bodyIsJson)
{
responseMessage.Body = templateBody(template);
}
else
{
responseMessage.BodyAsJson = JsonConvert.DeserializeObject(templateBody(template));
}
TransformBodyAsString(template, original, responseMessage);
}
else
{
TransformBodyAsJson(template, original, responseMessage);
}
// Headers
@@ -54,5 +52,79 @@ namespace WireMock.Transformers
return responseMessage;
}
private static void TransformBodyAsJson(object template, ResponseMessage original, ResponseMessage responseMessage)
{
JObject jobject;
switch (original.BodyAsJson)
{
case JObject bodyAsJObject:
jobject = bodyAsJObject;
break;
default:
jobject = JObject.FromObject(original.BodyAsJson);
break;
}
WalkNode(jobject, template);
responseMessage.BodyAsJson = jobject;
}
private static void WalkNode(JToken node, object template)
{
if (node.Type == JTokenType.Object)
{
// In case of Object, loop all children.
foreach (JProperty child in node.Children<JProperty>())
{
WalkNode(child.Value, template);
}
}
else if (node.Type == JTokenType.Array)
{
// In case of Array, loop all items.
foreach (JToken child in node.Children())
{
WalkNode(child, template);
}
}
else if (node.Type == JTokenType.String)
{
// In case of string, try to transform the value.
string stringValue = node.Value<string>();
if (string.IsNullOrEmpty(stringValue))
{
return;
}
var templateForStringValue = Handlebars.Compile(stringValue);
string transformedString = templateForStringValue(template);
if (!string.Equals(stringValue, transformedString))
{
JToken value;
try
{
// Try to convert this string into a real JsonObject
value = JToken.Parse(transformedString);
}
catch (JsonException)
{
// Ignore JsonException and just convert to JToken
value = transformedString;
}
node.Replace(value);
}
}
}
private static void TransformBodyAsString(object template, ResponseMessage original, ResponseMessage responseMessage)
{
var templateBody = Handlebars.Compile(original.Body);
responseMessage.Body = templateBody(template);
}
}
}