Feature: Support for JsonPath in the response (with HandleBars) #118

Closed
opened 2025-12-29 14:22:54 +01:00 by adam · 19 comments
Owner

Originally created by @zubinix on GitHub (Jul 18, 2018).

Originally assigned to: @StefH on GitHub.

Does WireMock.Net have support for the jsonPath helper found in the java based WireMock? I want to create a template that inserts in the response items from a JSON request. It seems all I can do with WireMock-Net 'out of the box' is use {{request.body}} in the response template which returns the entire JSON body of the request?

Originally created by @zubinix on GitHub (Jul 18, 2018). Originally assigned to: @StefH on GitHub. Does WireMock.Net have support for the **jsonPath** helper found in the java based WireMock? I want to create a template that inserts in the response items from a JSON request. It seems all I can do with WireMock-Net 'out of the box' is use **{{request.body}}** in the response template which returns the entire JSON body of the request?
adam added the feature label 2025-12-29 14:22:54 +01:00
adam closed this issue 2025-12-29 14:22:54 +01:00
Author
Owner

@StefH commented on GitHub (Jul 18, 2018):

Currently it's only supported that you can use a jsonmatcher on the request. See https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching#json-jsonmatcher

It's not yet supported that you can use JsonPath in the output, like you can do with handlebars : https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching#response-templating

@StefH commented on GitHub (Jul 18, 2018): Currently it's only supported that you can use a jsonmatcher on the request. See https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching#json-jsonmatcher It's not yet supported that you can use JsonPath in the output, like you can do with handlebars : https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching#response-templating
Author
Owner

@zubinix commented on GitHub (Jul 18, 2018):

Is there a plan to do so? Is there a HandleBar feature I can use instead to extract parts from the request body?

@zubinix commented on GitHub (Jul 18, 2018): Is there a plan to do so? Is there a HandleBar feature I can use instead to extract parts from the request body?
Author
Owner

@StefH commented on GitHub (Jul 18, 2018):

There is no HandleBars functionality out of the box. I can extend the code to support something like this:

// select single token
"{{JSONPath.SelectToken response.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}"

Where response.body is the response body in json.
And the $.Manufacturers[?(@.Name == 'Acme Co')] is the JSONPath expression (copied from example here: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm)

Also selecting multiple tokens should be possible:

// select multiple tokens
"{{#JSONPath.SelectTokens response.body \"$..Products[?(@.Price >= 50)].Name\"}}{{token}}{{/JSONPath.SelectTokens}}"
@StefH commented on GitHub (Jul 18, 2018): There is no HandleBars functionality out of the box. I can extend the code to support something like this: ``` c# // select single token "{{JSONPath.SelectToken response.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}" ``` Where **response.body** is the response body in json. And the **$.Manufacturers[?(@.Name == 'Acme Co')]** is the JSONPath expression (copied from example here: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm) Also selecting multiple tokens should be possible: ``` c# // select multiple tokens "{{#JSONPath.SelectTokens response.body \"$..Products[?(@.Price >= 50)].Name\"}}{{token}}{{/JSONPath.SelectTokens}}" ```
Author
Owner

@zubinix commented on GitHub (Jul 19, 2018):

That sounds great. When do you think you can add this feature?

@zubinix commented on GitHub (Jul 19, 2018): That sounds great. When do you think you can add this feature?
Author
Owner

@StefH commented on GitHub (Jul 19, 2018):

Currently I am fixing this issue https://github.com/WireMock-Net/WireMock.Net/issues/148#issuecomment-406163503.

After that I will continue on this one.

If the proposed fix here is enough for you and will comply to all your requirements, I will implement it as is.

@StefH commented on GitHub (Jul 19, 2018): Currently I am fixing this issue https://github.com/WireMock-Net/WireMock.Net/issues/148#issuecomment-406163503. After that I will continue on this one. If the proposed fix here is enough for you and will comply to all your requirements, I will implement it as is.
Author
Owner

@StefH commented on GitHub (Jul 19, 2018):

Preview NuGet can be found at
https://www.nuget.org/packages/WireMock.Net/1.0.4.7-preview-jsonpath

Note that the syntax has been changed from JSONPath.SelectToken to JsonPath.SelectToken !

@StefH commented on GitHub (Jul 19, 2018): Preview NuGet can be found at https://www.nuget.org/packages/WireMock.Net/1.0.4.7-preview-jsonpath Note that the syntax has been changed from `JSONPath.SelectToken` to `JsonPath.SelectToken` !
Author
Owner

@zubinix commented on GitHub (Jul 20, 2018):

Thanks StefH. I will take a look and get back to you.

@zubinix commented on GitHub (Jul 20, 2018): Thanks StefH. I will take a look and get back to you.
Author
Owner

@zubinix commented on GitHub (Jul 20, 2018):

My request input I'm trying to match is

{"username": "Zubin"}

using

    "Response": {
      "UseTransformer": true,
      "StatusCode": 200,
      "BodyAsJson": { "result": "{{JsonPath.SelectToken response.body \"@.username\"}}" },
      "Headers": {
        "Content-Type": "application/json"
      }
    }

but I get

{
    "Status": "{\"ClassName\":\"System.NotSupportedException\",\"Message\":\"The value '' with type HandlebarsDotNet.Compiler.UndefinedBindingResult cannot be used in Handlebars JsonPath.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\"   at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n   at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n   at lambda_method(Closure , TextWriter , Object )\\r\\n   at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n   at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233067,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null}"
}

What am I doing wrong?

@zubinix commented on GitHub (Jul 20, 2018): My request input I'm trying to match is `{"username": "Zubin"}` using ``` "Response": { "UseTransformer": true, "StatusCode": 200, "BodyAsJson": { "result": "{{JsonPath.SelectToken response.body \"@.username\"}}" }, "Headers": { "Content-Type": "application/json" } } ``` but I get ``` { "Status": "{\"ClassName\":\"System.NotSupportedException\",\"Message\":\"The value '' with type HandlebarsDotNet.Compiler.UndefinedBindingResult cannot be used in Handlebars JsonPath.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\" at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n at lambda_method(Closure , TextWriter , Object )\\r\\n at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233067,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null}" } ``` What am I doing wrong?
Author
Owner

@StefH commented on GitHub (Jul 20, 2018):

1] You want to use the request I guess
2] Also try request.bodyAsJson instead of request.body?

So: {{JsonPath.SelectToken request.bodyAsJson \"@.username\"}}

See also this code : https://github.com/WireMock-Net/WireMock.Net/blob/SupportJSONPath_in_the_response/test/WireMock.Net.Tests/ResponseBuilderTests/ResponseWithHandlebarsTests.cs#L384

@StefH commented on GitHub (Jul 20, 2018): 1] You want to use the request I guess 2] Also try **request.bodyAsJson** instead of **request.body**? So: `{{JsonPath.SelectToken request.bodyAsJson \"@.username\"}}` See also this code : https://github.com/WireMock-Net/WireMock.Net/blob/SupportJSONPath_in_the_response/test/WireMock.Net.Tests/ResponseBuilderTests/ResponseWithHandlebarsTests.cs#L384
Author
Owner

@zubinix commented on GitHub (Jul 20, 2018):

Yep should have used request.body but still getting

{
    "Status": "{\"ClassName\":\"System.NotSupportedException\",\"Message\":\"The value '' with type HandlebarsDotNet.Compiler.UndefinedBindingResult cannot be used in Handlebars JsonPath.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\"   at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n   at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n   at lambda_method(Closure , TextWriter , Object )\\r\\n   at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n   at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233067,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null}"
}

The input request I'm trying to grab data from is very simple just:

{"username": "Zubin"}

I'm just trying to make "Zubin" appear the response.

@zubinix commented on GitHub (Jul 20, 2018): Yep should have used request.body but still getting ``` { "Status": "{\"ClassName\":\"System.NotSupportedException\",\"Message\":\"The value '' with type HandlebarsDotNet.Compiler.UndefinedBindingResult cannot be used in Handlebars JsonPath.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\" at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n at lambda_method(Closure , TextWriter , Object )\\r\\n at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2146233067,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null}" } ``` The input request I'm trying to grab data from is very simple just: ``` {"username": "Zubin"} ``` I'm just trying to make "Zubin" appear the response.
Author
Owner

@StefH commented on GitHub (Jul 20, 2018):

You should use username instead of @.username.
And the BodyAsJson does not (yet) work, so you need to use this solution:

{
    "Guid": "407e031f-c96b-429d-8a58-01c6a456fedd",
    "Priority": 0,
    "Request": {
        "Path": {
            "Matchers": [
                {
                    "Name": "WildcardMatcher",
                    "Pattern": "/zubinix",
                    "IgnoreCase": false
                }
            ]
        },
        "Methods": [
            "post"
        ]
    },
    "Response": {
        "StatusCode": 200,
        "BodyDestination": "SameAsSource",
        "Body": "{ \"result\": \"{{JsonPath.SelectToken request.body \"username\"}}\" }",
        "UseTransformer": true,
        "Headers": {
            "Content-Type": "application/json"
        }
    }
}

Note that you also can use request.bodyAsJson.

@StefH commented on GitHub (Jul 20, 2018): You should use **username** instead of **@.username**. And the **BodyAsJson** does not (yet) work, so you need to use this solution: ``` js { "Guid": "407e031f-c96b-429d-8a58-01c6a456fedd", "Priority": 0, "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "/zubinix", "IgnoreCase": false } ] }, "Methods": [ "post" ] }, "Response": { "StatusCode": 200, "BodyDestination": "SameAsSource", "Body": "{ \"result\": \"{{JsonPath.SelectToken request.body \"username\"}}\" }", "UseTransformer": true, "Headers": { "Content-Type": "application/json" } } } ``` Note that you also can use **request.bodyAsJson**.
Author
Owner

@zubinix commented on GitHub (Jul 20, 2018):

That did the trick. Thanks.

@zubinix commented on GitHub (Jul 20, 2018): That did the trick. Thanks.
Author
Owner

@StefH commented on GitHub (Jul 20, 2018):

I did update the code, so now also BodyAsJson (in the response) is supported, see this mapping:

{
  "Request": {
    "Path": {
      "Matchers": [
        {
          "Name": "WildcardMatcher",
          "Pattern": "/zubinix2",
          "IgnoreCase": false
        }
      ]
    },
    "Methods": [
      "post"
    ],
    "Body": {}
  },
  "Response": {
    "StatusCode": 200,
    "BodyAsJson": {
      "path": "{{request.path}}",
      "result": "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}"
    },
    "UseTransformer": true,
    "Headers": {
      "Content-Type": "application/json"
    }
  }
}

New Nuget (1.0.4.8-preview-01) is available.

Please test

@StefH commented on GitHub (Jul 20, 2018): I did update the code, so now also **BodyAsJson** (in the response) is supported, see this mapping: ``` js { "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "/zubinix2", "IgnoreCase": false } ] }, "Methods": [ "post" ], "Body": {} }, "Response": { "StatusCode": 200, "BodyAsJson": { "path": "{{request.path}}", "result": "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}" }, "UseTransformer": true, "Headers": { "Content-Type": "application/json" } } } ``` New Nuget (1.0.4.8-preview-01) is available. Please test
Author
Owner

@zubinix commented on GitHub (Jul 23, 2018):

Trying the above. What could be causing this error?

{
    "Status": "{\"ClassName\":\"System.ArgumentNullException\",\"Message\":\"Value cannot be null.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\"   at WireMock.Validation.Check.NotNull[T](T value, String parameterName)\\r\\n   at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n   at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n   at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.WalkNode(JToken node, Object template)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.WalkNode(JToken node, Object template)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.TransformBodyAsJson(Object template, ResponseMessage original, ResponseMessage responseMessage)\\r\\n   at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n   at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n   at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2147467261,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null,\"ParamName\":\"arguments[0]\"}"
}

For input


    "Response": {
      "UseTransformer": true,
      "StatusCode": 200,
      "BodyAsJson": {
      	"path": "{{request.path}}",
        "result": "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}" 
      },
      "Headers": {
        "Content-Type": "application/json"
      }
    }
@zubinix commented on GitHub (Jul 23, 2018): Trying the above. What could be causing this error? ``` { "Status": "{\"ClassName\":\"System.ArgumentNullException\",\"Message\":\"Value cannot be null.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\" at WireMock.Validation.Check.NotNull[T](T value, String parameterName)\\r\\n at WireMock.Transformers.HandlebarsHelpers.Parse(Object[] arguments)\\r\\n at WireMock.Transformers.HandlebarsHelpers.<>c.<Register>b__0_0(TextWriter writer, Object context, Object[] arguments)\\r\\n at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.WalkNode(JToken node, Object template)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.WalkNode(JToken node, Object template)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.TransformBodyAsJson(Object template, ResponseMessage original, ResponseMessage responseMessage)\\r\\n at WireMock.Transformers.ResponseMessageTransformer.Transform(RequestMessage requestMessage, ResponseMessage original)\\r\\n at WireMock.ResponseBuilders.Response.ProvideResponseAsync(RequestMessage requestMessage)\\r\\n at WireMock.Mapping.ResponseToAsync(RequestMessage requestMessage)\\r\\n at WireMock.Owin.WireMockMiddleware.Invoke(HttpContext ctx)\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2147467261,\"Source\":\"WireMock.Net\",\"WatsonBuckets\":null,\"ParamName\":\"arguments[0]\"}" } ``` For input ``` js "Response": { "UseTransformer": true, "StatusCode": 200, "BodyAsJson": { "path": "{{request.path}}", "result": "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}" }, "Headers": { "Content-Type": "application/json" } } ```
Author
Owner

@StefH commented on GitHub (Jul 23, 2018):

When you send a request, do you also provide the Content-Type header with value application/json?

Like:
header

@StefH commented on GitHub (Jul 23, 2018): When you send a request, do you also provide the `Content-Type` header with value `application/json`? Like: ![header](https://user-images.githubusercontent.com/249938/43070996-a5ae0d78-8e71-11e8-86c1-7b273a1b19b5.png)
Author
Owner

@zubinix commented on GitHub (Jul 23, 2018):

Oh yes, I was missing the header in the request. Works now but interesting if I delete the header it still works! So the header is required the first time only? I'm using fiddler and postman as follows:

  1. Add mapping (using postman).
  2. Send request without application/json header using postman -> error above received. Verified in fiddler.
  3. Edit request in fiddler and add application/json header -> correct response received.
  4. Send the original request without the header from postman -> correct response received without using header??? caching???
@zubinix commented on GitHub (Jul 23, 2018): Oh yes, I was missing the header in the request. Works now but interesting if I delete the header it still works! So the header is required the first time only? I'm using fiddler and postman as follows: 1. Add mapping (using postman). 2. Send request without application/json header using postman -> error above received. Verified in fiddler. 3. Edit request in fiddler and add application/json header -> correct response received. 4. Send the original request without the header from postman -> correct response received without using header??? caching???
Author
Owner

@StefH commented on GitHub (Jul 23, 2018):

Very strange. There is no caching on the request, that would break the whole WireMock functionality. For now, do you think it works as excepted ? If so, this issue can be closed, and then I'll create a new official NuGet.

@StefH commented on GitHub (Jul 23, 2018): Very strange. There is no caching on the request, that would break the whole WireMock functionality. For now, do you think it works as excepted ? If so, this issue can be closed, and then I'll create a new official NuGet.
Author
Owner

@zubinix commented on GitHub (Jul 23, 2018):

Yes. Please close and create the NuGet. Thanks! I might create another issue relating to this apparent caching after get some more experience this tool.

@zubinix commented on GitHub (Jul 23, 2018): Yes. Please close and create the NuGet. Thanks! I might create another issue relating to this apparent caching after get some more experience this tool.
Author
Owner

@zubinix commented on GitHub (Jul 23, 2018):

Support for Json request parameters in response has been added.

@zubinix commented on GitHub (Jul 23, 2018): Support for Json request parameters in response has been added.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#118