wiremockwiremock-standalonewiremock-record

How to create dynamic response with json in wiremock


{   "result": {     {{#each (jsonPath request.body '$.ids') as |id|}}"{{id}}": {       "favorite_0": 1,       "search_0": 1,       "visit_0": 1,       "order_0": 1,       "basket_0": 1,       "jfyimpression_0": 1     }{{#unless @last}}     ,{{/unless}}{{/each}}   },   "messages": [     {       "type": "success",       "position": "top",       "content": "Request processed successfully.",       "title": "All is well!",       "code": "SUCCESS_1001"     }   ] }

I created this response for dynamically replicate result for every id. Id list can have be one or multiple item. Depend on the ids result > ids will change.

I tried this json but it didn't help, how to create json for it to be dynamic

{
  "mappings": [
    {
      "request": {
        "method": "POST",
        "url": "/api/v1/feature-store/features",
        "bodyPatterns": [
          {
            "matchesJsonPath": "$.feature_name",
            "equalTo": "customer-product_clickstream_activities_precomputed"
          },
          {
            "matchesJsonPath": "$.identifier",
            "equalTo": "123972627"
          },
          {
            "matchesJsonPath": "$.features",
            "contains": "visit_0"
          },
          {
            "matchesJsonPath": "$.features",
            "contains": "search_0"
          },
          {
            "matchesJsonPath": "$.features",
            "contains": "favorite_0"
          },
          {
            "matchesJsonPath": "$.ids",
            "contains": "\\d{9}"
          }
        ]
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json"
        },
        "jsonBody": {
          "result": "{{{#each (jsonPath request.body ',$.ids') as |id index|}}  {{id}}: {\n    \"favorite_{{index}}\": 1,\n    \"search_{{index}}\": 1,\n    \"visit_{{index}}\": 1,\n    \"order_{{index}}\": 1,\n    \"basket_{{index}}\": 1,\n    \"jfyimpression_{{index}}\": 1\n  }{{#unless @last}},{{/unless}}{{/each}}}",
          "messages": [
            {
              "type": "success",
              "position": "top",
              "content": "Request processed successfully.",
              "title": "All is well!",
              "code": "SUCCESS_1001"
            }
          ]
        }
      }
    }
  ]
}

Solution

  • I setup a simple mapping to help figure out the response templating. Here is the mapping I am using:

    {
      "name": "ids",
      "request": {
        "url": "/api/v1/feature-store/features",
        "method": "POST"
      },
      "response": {
        "status": 200,
        "bodyFileName": "features.txt",
        "headers": {
          "Content-Type": "application/json"
        },
        "transformers": [
          "response-template"
        ]
      }
    }
    

    This file is in my mappings folder and has a couple of key points to it. First, the body is stored in a separate file called features.txt which is saved in the __files directory. The second thing is that it has the response templating transformer enabled.

    The features.txt file looks like this:

    {
      "result": {     
      {{#each (jsonPath request.body '$.ids') as |id index|}}
        "{{id}}": {
          "favorite_{{index}}": 1, 
          "search_{{index}}": 1, 
          "visit_{{index}}": 1, 
          "order_{{index}}": 1, 
          "basket_{{index}}": 1, 
          "jfyimpression_{{index}}": 1     
        }{{#unless @last}}, {{/unless}}
      {{/each}}
    }, 
    "messages": [
        {
          "type": "success", 
          "position": "top", 
          "content": "Request processed successfully.", 
          "title": "All is well!", 
          "code": "SUCCESS_1001"
        }
      ]
    }
    

    It loops through the ids in the request and updates the response accordingly. With a request like this:

    {
      "ids": [1,2]
    }
    

    It will produce a response like this:

    {
      "result": {
        "1": {
          "favorite_0": 1,
          "search_0": 1,
          "visit_0": 1,
          "order_0": 1,
          "basket_0": 1,
          "jfyimpression_0": 1
        },
        "2": {
          "favorite_1": 1,
          "search_1": 1,
          "visit_1": 1,
          "order_1": 1,
          "basket_1": 1,
          "jfyimpression_1": 1
        }
      },
      "messages": [
        {
          "type": "success",
          "position": "top",
          "content": "Request processed successfully.",
          "title": "All is well!",
          "code": "SUCCESS_1001"
        }
      ]
    }
    

    Update:

    If you don't want to separate the response body into a separate file you can include it in the WireMock mapping file. The only difference is that you would use the body element instead of the bodyFileName element. As the WireMock mapping file needs to be valid json, all the response body will need to be escaped like the following:

    {
      "name": "ids",
      "request": {
        "url": "/api/v1/feature-store/features",
        "method": "POST"
      },
      "response": {
        "status": 200,
        "body": "{ \"result\": { {{#each (jsonPath request.body '$.ids') as |id index|}} \"{{id}}\": { \"favorite_{{index}}\": 1, \"search_{{index}}\": 1, \"visit_{{index}}\": 1, \"order_{{index}}\": 1, \"basket_{{index}}\": 1, \"jfyimpression_{{index}}\": 1 }{{#unless @last}}, {{/unless}} {{/each}} }, \"messages\": [ { \"type\": \"success\", \"position\": \"top\", \"content\": \"Request processed successfully.\", \"title\": \"All is well!\", \"code\": \"SUCCESS_1001\" } ] }",
        "headers": {
          "Content-Type": "application/json"
        },
        "transformers": [
          "response-template"
        ]
      }
    }