如何在WireMock中根据请求IDS生成JSON动态响应
WireMock动态生成JSON响应的正确配置
问题背景
需要基于请求Body中的ids数组(支持单个/多个元素),动态生成result节点下对应每个id的键值对,已编写响应模板但mappings配置未生效。
原响应模板
{ "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" } ] }
原无效Mappings配置
{ "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" } ] } } } ] }
原配置问题分析
- JSONPath表达式错误:
',$.ids多了前置逗号,正确路径应为$.ids` jsonBody使用错误:jsonBody要求值是合法JSON对象,但模板拼接的是字符串,直接赋值会导致响应格式失效- 键名格式不规范:id作为JSON键未用双引号包裹,生成的JSON会语法错误
正确配置方案
前提:启用响应模板功能
启动WireMock时必须添加--global-response-templating参数,否则模板语法不会被解析。
方式一:使用外部模板文件(推荐,易维护)
- 在WireMock的
__files目录下创建dynamic-response.json,内容为你编写的响应模板(无需修改) - 修改Mappings配置:
{ "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[*]", "matches": "\\d{9}" } ] }, "response": { "status": 200, "headers": { "Content-Type": "application/json" }, "bodyFileName": "dynamic-response.json", "transformers": ["response-template"] } } ] }
方式二:内联模板(直接写在Mappings中)
如果不想使用外部文件,可将模板直接写入body字段:
{ "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[*]", "matches": "\\d{9}" } ] }, "response": { "status": 200, "headers": { "Content-Type": "application/json" }, "body": "{ \"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\" } ]}", "transformers": ["response-template"] } } ] }
额外优化
- 请求匹配规则中,
ids的校验可改为"matchesJsonPath": "$.ids[*]", "matches": "\\d{9}",确保数组每个元素都是9位数字 - 若需根据循环索引动态生成
favorite_{index},将模板中的favorite_0改为favorite_{{@index}}即可(@index是Handlebars内置循环索引变量,从0开始)
内容的提问来源于stack exchange,提问作者Mustafa Selim Güneydın
相关产品推荐
相关产品推荐

