Is there an easy way to ignore request body parame...
# help
b
Is there an easy way to ignore request body parameters when matching? We generate a unique id and pass it in a request to one endpoint but I’d like to be able to ignore it during playback Looking for something like:
Copy code
"ignoreBodyParameters": [
  {
    "name": "myParameter",
    "nestedLevel": "*" // Ignore no matter the depth in body
  },
  ...
]
I’m sure there’s some fancy JSON templating one could do in place of that nesting parameter but that’s the general idea
a
What’s your request look like?
request body parameters
is throwing me for a loop
b
Sorry yeah, we have a request that relays device info to the server:
Copy code
{
  "device_name": "...",
  "device_id": "...",
  ...
}
The
device_id
parameter is the issue here: We clear app state between our integration tests, and in doing so, our app will generate a new one. I can of course do something more invasive and, based on the app environment (which in this case would be
test
), generate the same device id no matter what, but I’d prefer to handle it at the mapping layer if possible!
So I’d love to basically say “Consider a stub mapping a match if all parameters in the body match while ignoring
device_id
a
Got it! one second…
You can use a few strategies, but I think the one I’d request would be to use
equalToJson
with
"ignoreExtraElements": true
https://wiremock.org/docs/request-matching/#less-strict-matching
Copy code
{
  "request": {
    ...
    "bodyPatterns" : [ {
      "equalToJson" : "{ \"total_results\": 4  }",
      "ignoreArrayOrder" : true,
      "ignoreExtraElements" : true
    } ]
    ...
  },
  ...
}
You can also un-stringify that JSON I _think_:
Copy code
...
"equalToJson": { "total_results": 4 },
"ignoreExtraElements": true,
...
b
Would that help? It’s not an array and not an extra element so I’m not sure those would get us what we want.. Unless I’m misreading the
equalToJson
field 🤔
Oh snap
I missed the placeholder bit
👍🏻 1
So maybe I could do
Copy code
{
  "deviceId": "${json-unit.any-string}"
}
a
I think so 😄
b
OK I’ll need to figure out how to slot that config into the
requestBodyPattern
parameter of the
recordings/start
API cause that’s how we’re starting recording
That’s super helpful, thanks! I’ll post an update if I get this working for future readers 🙂
a
awesome awesome! Definitely post if you have any more questions
b
It kinda looks like this isn’t supported via the API
a
🤔
b
On the page you linked the syntax is
Copy code
"equalToJson" : { "total_results": 4 }
But from the API the key is
matcher
which needs to be
equalToJson
But I don’t see a way to further configure that
equalToJson
a
Ah, you might not be able to un-stringify it? Did you try
Copy code
"equalToJson": "{ \"total_results\": 4 }"
?
b
So I’m trying this:
Copy code
{
  "targetBaseUrl": "{{Target URL}}",
  "captureHeaders": {
    "X-Maestro-Test-Id": {}
  },
  "requestBodyPattern": {
    "equalToJson": "{ \"device_id\": \"${json-unit.any-string}\" }"
  },
  "persist": true,
  "repeatsAsScenarios": false
}
But getting:
Copy code
{
  "errors": [
    {
      "code": 10,
      "source": {
        "pointer": "/requestBodyPattern/equalToJson"
      },
      "title": "Error parsing JSON",
      "detail": "Unrecognized field \"equalToJson\" (class com.github.tomakehurst.wiremock.recording.RequestBodyAutomaticPatternFactory), not marked as ignorable"
    }
  ]
}
This is the POST
body
to
http://{{Local IP}}:{{Port}}/__admin/recordings/start
But if I do
Copy code
{
  "targetBaseUrl": "{{Target URL}}",
  "captureHeaders": {
    "X-Maestro-Test-Id": {}
  },
  "requestBodyPattern": {
    "matcher": "equalToJson"
  },
  "persist": true,
  "repeatsAsScenarios": false
}
it succeeds, but obviously that’s not what I want (it’s not configuring the device id param at all)
a
🤔 Where is this API documentation from? Apologies, I don’t use the admin API stuff often
a
Ah! So since you’re setting up the recording,
requestBodyPattern
is telling the recorder what to record - in this case saying “hey, record the
bodyPatterns
as
equalToJson
, and ignore/don’t ignore Extra Elements”.
Instead, I think we’d want to add something to that
filters
field?
👀 1
Copy code
"filters" : {
    "urlPathPattern" : "/api/.*",
    "method" : "GET",
    "allowNonProxied": true
  },
from the docs, so maybe something like…
Copy code
"filters" : {
    "urlPathPattern" : "/api/.*",
    "method" : "GET",
    "allowNonProxied": true,
    "bodyPatterns": [ {
      "equalToJson": "{ \"device_id\": \"${json-unit.any-string}\" }",
      "ignoreExtraElements": true
    } ]
  },
?
b
Ok interesting. Got a
200
so I’m testing now 👀
👀 1
Ah it didn’t work. But I do see that at least
equalToJson
is being registered/configured
Also, this
filters
key… Makes it sound like only the requests matching that filter will be mapped/recorded? 🤔
Which isn’t actually what we want
Yeah OK I just confirmed that’s what’s happening (cleared out mappings prior to recording with that filter config).
I’m probably doing a bad job of explaining the ideal end result 😂 But I think to summarize:
Record all requests/responses for future playbacks, but when playing back, consider this response a match for this request IFF everything about the request EXCEPT the request body
device_id
parameter match (but matching entirely is obviously acceptable as well).
a
oh oh oh
I thought this sounded familiar - 2+ years ago I just recommended manually changing them with global find + replace in your IDE 😅 https://stackoverflow.com/a/66317444/11625850
b
Ah bingo. That was the exact solution I was hoping to avoid 😂
Unless the
StubMappingTransformer
allows me to do it in an automated fashion (I meant avoiding the manual find and replace haha)!
a
Going the manual route is an excuse to get great at regex! /s
😂 1
b
It looks like the record API supports the transformer though…
Copy code
"transformers" : [ "modify-response-header" ],
  "transformerParameters" : {
    "headerValue" : "123"
  }
I’m not fully understanding how I’d do what I want, but it seeeeeems possible
Copy code
"transformers" : [ "device_id" ],
  "transformerParameters" : {
    "device_id" : "000000000000000"
  }
Or something 😂
A transformer is an implementations of
StubMappingTransformer
and needs to be registered when starting WireMock as described in Extending WireMock.
Ah, this is the bit that I probably can’t do via CLI
Ahh… I can write one and pass it via
--extensions
I think I’ll look into that!
So excitingly I got the above “working” in that I can build a fat JAR that contains both Wiremock and my extensions, spin up the server with
java -jar my-wiremock-extensions-1.0-SNAPSHOT.jar --bind-address 127.0.0.1 --extensions com.expample.DeviceIdTransformer --verbose
and when saving stub mappings it correctly transforms the mapping’s request body matcher to only be
"equalToJson": "{\"password\":\"myPassword\",\"email\":\"<mailto:94669@example.org|94669@example.org>\"}"
. I learned late last night that I was thinking about the matching logic wrong. The real logic is “ignore everything from the request body other than email/password, haha. Much simpler to reason about.
THAT SAID, it’s still not working 😢 I get
Copy code
[custom matcher]                                           |                                                     <<<<< custom matcher does not match
in the console when this request is hit. The header I’m diffing on as well as the URL seem to match, it’s just the body matcher that is borked
My understanding of the
ignoreExtraElements
is that a request body should be able to contain N number of elements and my
equalToJson
can contain M number of elements (where M < N) and it can match so long as all elements in M are exactly the same in N, but maybe I’m wrong?
OK I actually got it working 🎉 I had to pass
null
to the 2 custom matcher fields. Previously I was just passing along the fields from the original stub mapping. Not exactly sure what changed because out output JSON stayed the same, but it worked 🙃
a
🙌🏻 Glad you were able to get it sorted, apologies for being absent this morning 😅
❤️ 1