Martin Borzan
03/10/2023, 7:49 AM#each
helper described here.
I have a request body with an persons
array property containing a varied amount of items. The mock should edit these persons in the response by adding a random generated UUID to each.
For the example request:
{
persons: [
{"name": "Andy", "age": 34},
{"name": "Rick", "age": 18},
{"name": "Michael", "age": 48}
]
}
The response should be:
{
persons: [
{"id": "a6aa0b30-8afd-43d6-af25-431b7c3d08ba", "name": "Andy", "age": 34},
{"id": "d2255b1a-d4fa-4b27-a459-69bde072ba36", "name": "Rick", "age": 18},
{"id": "dc644b5a-9a0e-4e3d-b82a-c53e2b7f1561", "name": "Michael", "age": 48}
]
}
With the id being randomly generated.
What I have managed to do so far is fix the number of persons in the array with the following template:
{
...
"response": {
"jsonBody": {
"persons": [
{
"id": "{{randomValue type='UUID'}}",
"name": "{{jsonPath request.body '$.persons[0].name'}}"
"age": "{{jsonPath request.body '$.persons[0].age'}}"
},
{
"id": "{{randomValue type='UUID'}}",
"name": "{{jsonPath request.body '$.persons[1].name'}}"
"age": "{{jsonPath request.body '$.persons[1].age'}}"
},
{
"id": "{{randomValue type='UUID'}}",
"name": "{{jsonPath request.body '$.persons[2].name'}}"
"age": "{{jsonPath request.body '$.persons[2].age'}}"
}
]
},
"transformers": ["response-template"]
}
}
```
This only works for exactly 3 people, though. How do I make use of the
```{{#each request.body.persons as |person|}}
<voodoo magic here>
{{/each}}
Helper in my json response template file?
Any help would be appreciated.Rob Elliot
03/10/2023, 9:10 AM{
persons: [
{{#each (jsonPath request.body '$.persons') as |person|}}
{"id": "{{randomValue type='UUID'}}", "name": "{{ person.name }}", "age": {{ person.age }} }
{{/each}}
]
}
Martin Borzan
03/10/2023, 11:17 AMRob Elliot
03/10/2023, 11:18 AM{
"persons": [
{{#each (jsonPath request.body '$.persons') as |person|}}
{"id": "{{randomValue type='UUID'}}", "name": "{{ person.name }}", "age": {{ person.age }} }{{#unless @last}},{{/unless}}
{{/each}}
]
}
Martin Borzan
03/10/2023, 12:10 PMRob Elliot
03/10/2023, 12:11 PMMartin Borzan
03/10/2023, 12:12 PMRob Elliot
03/10/2023, 12:21 PMwithBody
should be valid JSON, it can be any StringMartin Borzan
03/10/2023, 12:43 PMorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cloud.contract.wiremock.WireMockConfiguration': Invocation of init method failed; nested exception is com.github.tomakehurst.wiremock.common.JsonException: {
"errors" : [ {
"code" : 10,
"source" : {
"pointer" : "/response/jsonBody"
},
"title" : "Error parsing JSON",
"detail" : "Unexpected character ('{' (code 123)): was expecting double-quote to start field name\n at [Source: (String)\"{\r\n \"scenarioName\": \"CREATE_PERSONS\",\r\n ....
}
Rob Elliot
03/10/2023, 12:44 PMMartin Borzan
03/10/2023, 12:44 PM"transformers": ["response-template"]
Rob Elliot
03/10/2023, 12:45 PMMartin Borzan
03/10/2023, 12:46 PMRob Elliot
03/10/2023, 12:55 PMMartin Borzan
03/10/2023, 12:59 PM{
"scenarioName": "CREATE_PERSONS",
"requiredScenarioState": "CREATE",
"request": {
"method": "POST",
"url": "/groups"
},
"response": {
"status": 201,
"jsonBody": {
"persons": [
{{#each (jsonPath request.body '$.persons') as |person|}}
{
"id": "{{randomValue type='UUID'}}",
"name": "{{ person.name }}",
"age": {{ person.age }} a
}{{#unless @last}},{{/unless}}
{{/each}}
],
"auditDetails": {
"version": 0
}
},
"headers": {
"Content-Type": "application/json"
},
"transformers": ["response-template"]
}
}
@AutoConfigureWireMock(port = 0, stubs = "classpath:/wiremock_stubs/Groups")
Rob Elliot
03/10/2023, 1:11 PMjsonBody
there because it's a template, not json. Try just body
{
"scenarioName": "CREATE_PERSONS",
"requiredScenarioState": "CREATE",
"request": {
"method": "POST",
"url": "/groups"
},
"response": {
"status": 201,
"body": "{\"persons\": [{{#each (jsonPath request.body '$.persons') as |person|}}{\"id\": \"{{randomValue type='UUID'}}\", \"name\": \"{{ person.name }}\",\"age\": {{ person.age }} }{{#unless @last}},{{/unless}}{{/each}}],\"auditDetails\": {\"version\": 0}}",
"headers": {
"Content-Type": "application/json"
},
"transformers": [
"response-template"
]
}
}
Martin Borzan
03/10/2023, 1:14 PMRob Elliot
03/10/2023, 1:15 PMbodyFileName
and point to a separate file so that you don't have to put the whole thing on one line and don't have to escape anything.{
"scenarioName": "CREATE_PERSONS",
"requiredScenarioState": "CREATE",
"request": {
"method": "POST",
"url": "/groups"
},
"response": {
"status": 201,
"bodyFileName": "Groups.json.handlebars",
"headers": {
"Content-Type": "application/json"
},
"transformers": [
"response-template"
]
}
}
/wiremock_stubs/Groups.json.handlebars
{
"persons": [
{{#each (jsonPath request.body '$.persons') as |person|}}
{"id": "{{randomValue type='UUID'}}", "name": "{{ person.name }}", "age": {{ person.age }} }{{#unless @last}},{{/unless}}
{{/each}}
]
}
Martin Borzan
03/10/2023, 1:19 PMRob Elliot
03/10/2023, 1:23 PMMartin Borzan
03/10/2023, 1:25 PM{
"persons": [
{{#each (jsonPath request.body '$.persons') as |person|}}
{"id": "{{randomValue type='UUID'}}", "name": "{{ person.name }}", "age": {{ person.age }} }{{#unless @last}},{{/unless}}
{{/each}}
]
}
as valid json.Rob Elliot
03/10/2023, 1:25 PMMartin Borzan
03/10/2023, 1:26 PM"errors" : [ {
"code" : 10,
"source" : {
"pointer" : "/groupName"
},
"title" : "Error parsing JSON",
"detail" : "Unrecognized field \"groupName\" (class com.github.tomakehurst.wiremock.stubbing.StubMapping), not marked as ignorable"
} ]
Rob Elliot
03/10/2023, 1:30 PMgroupName
in the stub mapping json...Martin Borzan
03/10/2023, 1:32 PMRob Elliot
03/10/2023, 1:34 PM{
"scenarioName": "CREATE_PERSONS",
"requiredScenarioState": "CREATE",
"request": {
"method": "POST",
"url": "/groups"
},
"response": {
"status": 201,
"bodyFileName": "Groups.json.handlebars",
"headers": {
"Content-Type": "application/json"
},
"transformers": [
"response-template"
]
},
"groupName": "s"
}
Martin Borzan
03/10/2023, 1:35 PMmapping.json:
{
"scenarioName": "CREATE_PERSONS",
"requiredScenarioState": "CREATE",
"request": {
"method": "POST",
"url": "/groups"
},
"response": {
"status": 201,
"bodyFileName": "createGroupResponseTemplate.json",
"headers": {
"Content-Type": "application/json"
},
"transformers": [
"response-template"
]
}
}
createGroupResponseTemplate.json
{
"groupName": "{{jsonPath request.body '$.groupName'}}",
"department": "{{jsonPath request.body '$.department'}}",
"persons": [
{{#each (jsonPath request.body '$.persons') as |person|}}
{
"id": "{{randomValue type='UUID'}}",
"name": "{{ person.name }}",
"age": {{ person.age }}
}{{#unless @last}},{{/unless}}
{{/each}}
]
}
Rob Elliot
03/10/2023, 1:44 PMcreateGroupResponseTemplate.json
is in the directory that it's loading stubs from so it's treating it as a stub json and it isn'tMartin Borzan
03/10/2023, 1:45 PMRob Elliot
03/10/2023, 1:49 PM@AutoConfigureWireMock(port = 0, stubs = "classpath:/wiremock_stubs/Groups")
just takes all json files in /wiremock_stubs/Groups
and tries to turn them into stubs.
I don't know if Spring will recurse into subdirs? If not you could put your body into /wiremock_stubs/Groups/bodies/createGroupResponseTemplate.json
and it might work with "bodyFileName": "bodies/createGroupResponseTemplate.json"
Or perhaps just naming it createGroupResponseTemplate.json.handlebars
would be enough to stop Spring treating it as a stub?Martin Borzan
03/10/2023, 1:52 PMRob Elliot
03/10/2023, 1:53 PMcreateGroupResponseTemplate.json
in src/test/resources/__files
might work.Martin Borzan
03/10/2023, 3:21 PMRob Elliot
03/10/2023, 3:23 PMsrc/test/resources/__files
Martin Borzan
03/10/2023, 3:24 PMIllegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backslash to be included in string value
Rob Elliot
03/10/2023, 3:40 PMMartin Borzan
03/13/2023, 8:40 AMRob Elliot
03/13/2023, 4:23 PM\r
carriage return character. What is it that doesn't like it? The waters are quite muddy because of having Spring in the mix, so stack traces with errors are going to be vital to understanding what's going ion.Martin Borzan
03/15/2023, 7:42 AMMatched response definition:
{
"status" : 201,
"body" : "{\n \"groupName\": \"Mock Group Name\",\n \"department\": \"Mock Department\",\n \"persons\": [\n {\n \"id\": \"d822a6b5-8b5e-4f97-9690-dc87b3e6654e\", \n \"name\": \"Mock Name P1\", \n \"age\": \"23\"\n },\n {\n \"id\": \"e9ddf0f5-1d49-4bd9-8a89-975a82b0a966\", \n \"name\": \"Mock Name P2\", \n \"age\": \"32\"\n }\n ]\n}\n",
"bodyFileName" : "createGroup.wiremock",
"headers" : {
"Content-Type" : "application/json"
},
"transformers" : [ "response-template" ]
}
Rob Elliot
03/15/2023, 9:39 AMbody
and bodyFileName
? You should have one or the other (in this case bodyFileName
).Martin Borzan
03/15/2023, 10:35 AMRob Elliot
03/15/2023, 10:37 AMMartin Borzan
03/15/2023, 10:37 AMRob Elliot
03/15/2023, 10:42 AMMartin Borzan
03/15/2023, 10:44 AMRob Elliot
03/15/2023, 11:25 AMitems
key should be a string but contains an unescaped new line. As there is no items
key in the Matched response definition you've sent I guess that it's not actually the real values. But it's probably that your createGroup.wiremock
handlebars file does not resolve to valid json.
You could try copying the value of the body
key in the Matched response definition out, sticking it through a json unescaper, and saving the result into a json file - IntelliJ will probably then show you what's wrong with it.Martin Borzan
03/15/2023, 11:59 AMRob Elliot
03/15/2023, 12:04 PM